๐Ÿš€ Next.js 16 ์บ์‹ฑ ์ ์šฉํ•ด๋ณด๊ธฐ

twonezeroยท2026๋…„ 1์›” 30์ผ

๐Ÿ“Œ ๊ฐœ์š”

Next.js 16์˜ ์ƒˆ๋กœ์šด ์บ์‹ฑ ๊ธฐ๋Šฅ์„ ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•˜์—ฌ ์„ฑ๋Šฅ์„ ๊ฐœ์„ ํ•จ. ๊ธฐ์กด์˜ fetch ๊ธฐ๋ฐ˜ ๋ฐ์ดํ„ฐ ๋กœ๋”ฉ ๋ฐฉ์‹์—์„œ ์„œ๋ฒ„ ์•ก์…˜๊ณผ 'use cache' ๋””๋ ‰ํ‹ฐ๋ธŒ๋ฅผ ํ™œ์šฉํ•œ ์ตœ์ ํ™”๋œ ๊ตฌ์กฐ๋กœ ์ „ํ™˜ํ–ˆ์Œ.


๐ŸŽฏ ์ฃผ์š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ

1. ์บ์‹œ๋œ ์„œ๋ฒ„ ์•ก์…˜ ์ถ”๊ฐ€

๊ธฐ์กด์—๋Š” ํด๋ผ์ด์–ธํŠธ์—์„œ ์ง์ ‘ API๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฉ์‹์„ ์‚ฌ์šฉํ–ˆ์œผ๋‚˜, ์ด๋ฅผ ์„œ๋ฒ„ ์•ก์…˜์œผ๋กœ ์ „ํ™˜ํ•˜๊ณ  ์บ์‹ฑ์„ ์ ์šฉํ•จ.

๋ณ€๊ฒฝ ์ „ (app/page.tsx):

const BASE_URL = process.env.NEXT_PUBLIC_BASE_URL;

const Page = async () => {
  if (!BASE_URL) return null;
  const res = await fetch(`${BASE_URL}/api/events`);
  const { events } = await res.json();
  // ...
}

๋ณ€๊ฒฝ ํ›„ (app/page.tsx):

import { getAllEventsCached } from "@/lib/actions/event.actions";

const Page = async () => {
  const events = await getAllEventsCached();
  // ...
}

๐Ÿ’ก ์ฃผ์š” ๊ฐœ์„ ์ 

  • ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์˜์กด์„ฑ ์ œ๊ฑฐ
  • ๋ถˆํ•„์š”ํ•œ ๋„คํŠธ์›Œํฌ ์˜ค๋ฒ„ํ—ค๋“œ ๊ฐ์†Œ
  • ์„œ๋ฒ„ ์‚ฌ์ด๋“œ์—์„œ ์ง์ ‘ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ ‘๊ทผ์œผ๋กœ ์‘๋‹ต ์†๋„ ํ–ฅ์ƒ

2. getAllEventsCached ๊ตฌํ˜„

lib/actions/event.actions.ts์— ์ƒˆ๋กœ์šด ์บ์‹œ๋œ ์„œ๋ฒ„ ์•ก์…˜์„ ์ถ”๊ฐ€ํ•จ:

export const getAllEventsCached = async () => {
    'use cache';

    try {
        await connectDB();

        const events = await Event.find().sort({ createdAt: -1 }).lean();

        return JSON.parse(JSON.stringify(events));
    } catch (error) {
        console.error("Error fetching all events:", error);
        throw error;
    }
};

๐Ÿ”ฅ ํ•ต์‹ฌ ํฌ์ธํŠธ

  • 'use cache' ๋””๋ ‰ํ‹ฐ๋ธŒ: Next.js 16์˜ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์œผ๋กœ, ํ•จ์ˆ˜ ์‹คํ–‰ ๊ฒฐ๊ณผ๋ฅผ ์ž๋™์œผ๋กœ ์บ์‹ฑ (next.config.ts ์—์„œ cacheComponents ๋ฅผ true ๋กœ ํ•ด์•ผํ•จ.)
  • .lean(): Mongoose์˜ lean() ๋ฉ”์„œ๋“œ๋กœ ์ˆœ์ˆ˜ JavaScript ๊ฐ์ฒด ๋ฐ˜ํ™˜, ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ๊ฐ์†Œ
  • JSON.parse(JSON.stringify()): MongoDB ObjectId์™€ Date ๊ฐ์ฒด๋ฅผ ์ง๋ ฌํ™”ํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ ์ปดํฌ๋„ŒํŠธ์—์„œ๋„ ์•ˆ์ „ํ•˜๊ฒŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋„๋ก ์ฒ˜๋ฆฌ

3. EventList ์ปดํฌ๋„ŒํŠธ ๋ถ„๋ฆฌ

์ฝ”๋“œ ๊ตฌ์กฐ ๊ฐœ์„ ์„ ์œ„ํ•ด ์ด๋ฒคํŠธ ๋ชฉ๋ก ๋ Œ๋”๋ง ๋กœ์ง์„ ๋ณ„๋„ ์ปดํฌ๋„ŒํŠธ๋กœ ์ถ”์ถœํ•จ.

components/EventList.tsx:

import EventCard from "@/components/EventCard";
import { IEvent } from "@/database";

export default async function EventList({ events }: { events: IEvent[] }) {

  return (
    <ul className="events">
      {events && events.length > 0 ? (
        events.map((event: IEvent) => (
          <li key={event.title} className="list-none">
            <EventCard {...event} />
          </li>
        ))
      ) : (
        <p className="text-center text-gray-500">No events found at the moment.</p>
      )}
    </ul>
  );
}

์ด๋ฅผ ํ†ตํ•ด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ด์ ์„ ์–ป์Œ:

  • ๊ด€์‹ฌ์‚ฌ์˜ ๋ถ„๋ฆฌ
  • ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ปดํฌ๋„ŒํŠธ ๊ตฌ์กฐ
  • ๋” ๋‚˜์€ ์ฝ”๋“œ ๊ฐ€๋…์„ฑ
  • ๋นˆ ์ƒํƒœ ์ฒ˜๋ฆฌ ๊ฐœ์„ 

4. Next.js ์„ค์ • ์—…๋ฐ์ดํŠธ

next.config.ts์— ์บ์‹ฑ ๊ด€๋ จ ์„ค์ •์„ ์ถ”๊ฐ€ํ•จ:

const nextConfig: NextConfig = {
  cacheComponents: true,
  
  images: {
    remotePatterns: [
      // ...
    ]
  }
};

โš™๏ธ cacheComponents ์˜ต์…˜

Next.js 16์—์„œ ๊ธฐ๋Šฅ์œผ๋กœ, ์ปดํฌ๋„ŒํŠธ ๋ ˆ๋ฒจ์˜ ์บ์‹ฑ์„ ํ™œ์„ฑํ™”ํ•จ. ์ด๋ฅผ ํ†ตํ•ด ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์˜ ๋ Œ๋”๋ง ๊ฒฐ๊ณผ๋„ ์บ์‹œํ•  ์ˆ˜ ์žˆ์Œ.


๐Ÿ“Š ์„ฑ๋Šฅ ๊ฐœ์„  ํšจ๊ณผ

Before

  1. ํด๋ผ์ด์–ธํŠธ โ†’ API Route โ†’ MongoDB
  2. ๋งค ์š”์ฒญ๋งˆ๋‹ค ์ „์ฒด ๋„คํŠธ์›Œํฌ ๋ผ์šด๋“œํŠธ๋ฆฝ ๋ฐœ์ƒ
  3. ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๊ฒ€์ฆ ์˜ค๋ฒ„ํ—ค๋“œ

After

  1. ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ โ†’ ์บ์‹œ๋œ ์„œ๋ฒ„ ์•ก์…˜ โ†’ MongoDB
  2. ์บ์‹œ ํžˆํŠธ ์‹œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ฟผ๋ฆฌ ์ƒ๋žต
  3. ์ง์ ‘์ ์ธ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ ‘๊ทผ์œผ๋กœ ์‘๋‹ต ์‹œ๊ฐ„ ๋‹จ์ถ•

๐Ÿ” ๊ธฐ์ˆ ์  ์ธ์‚ฌ์ดํŠธ

Next.js 16์˜ 'use cache' ๋””๋ ‰ํ‹ฐ๋ธŒ

'use cache'๋Š” Next.js 16์—์„œ ์ƒˆ๋กญ๊ฒŒ ๋„์ž…๋œ ๊ธฐ๋Šฅ์œผ๋กœ, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํŠน์ง•์ด ์žˆ์Œ:

  • ํ•จ์ˆ˜ ๋ ˆ๋ฒจ ์บ์‹ฑ: ํŠน์ • ํ•จ์ˆ˜์˜ ์‹คํ–‰ ๊ฒฐ๊ณผ๋ฅผ ์บ์‹œ
  • ์ž๋™ ๋ฌดํšจํ™”: ๋ฐฐํฌ ์‹œ ๋˜๋Š” revalidate ์„ค์ •์— ๋”ฐ๋ผ ์ž๋™์œผ๋กœ ์บ์‹œ ๋ฌดํšจํ™”
  • ํƒ€์ž… ์•ˆ์ „์„ฑ: TypeScript์™€ ์™„๋ฒฝํ•˜๊ฒŒ ํ˜ธํ™˜
  • ์„œ๋ฒ„ ์•ก์…˜๊ณผ์˜ ํ†ตํ•ฉ: ์„œ๋ฒ„ ์•ก์…˜์—์„œ ๋ฐ”๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

Mongoose .lean() ์ตœ์ ํ™”

const events = await Event.find().sort({ createdAt: -1 }).lean();

.lean() ๋ฉ”์„œ๋“œ๋Š”:

  • Mongoose Document ๋Œ€์‹  ์ˆœ์ˆ˜ JavaScript ๊ฐ์ฒด ๋ฐ˜ํ™˜
  • ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ์•ฝ 30-40% ๊ฐ์†Œ
  • ์ง๋ ฌํ™” ์„ฑ๋Šฅ ํ–ฅ์ƒ
  • ์ฝ๊ธฐ ์ „์šฉ ๋ฐ์ดํ„ฐ์— ์ตœ์ ํ™”

โš ๏ธ ์ฃผ์˜์‚ฌํ•ญ

.lean()์„ ์‚ฌ์šฉํ•˜๋ฉด Mongoose์˜ virtuals, getter/setter, ๋ฉ”์„œ๋“œ ๋“ฑ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Œ. ์ˆœ์ˆ˜ํ•˜๊ฒŒ ๋ฐ์ดํ„ฐ๋งŒ ์ฝ์–ด์˜ฌ ๋•Œ ์‚ฌ์šฉํ•ด์•ผ ํ•จ.


๐ŸŽจ ์ฝ”๋“œ ๊ตฌ์กฐ ๊ฐœ์„ 

์ปดํฌ๋„ŒํŠธ ๋ถ„๋ฆฌ์˜ ์ด์ 

๊ธฐ์กด์—๋Š” app/page.tsx์—์„œ ์ง์ ‘ ์ด๋ฒคํŠธ ๋ชฉ๋ก์„ ๋ Œ๋”๋งํ–ˆ์œผ๋‚˜, EventList ์ปดํฌ๋„ŒํŠธ๋กœ ๋ถ„๋ฆฌํ•จ์œผ๋กœ์จ:

  1. ๋‹จ์ผ ์ฑ…์ž„ ์›์น™ ์ค€์ˆ˜: ๊ฐ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ํ•˜๋‚˜์˜ ๋ช…ํ™•ํ•œ ์—ญํ•  ์ˆ˜ํ–‰
  2. ํ…Œ์ŠคํŠธ ์šฉ์ด์„ฑ: ๋…๋ฆฝ์ ์ธ ์ปดํฌ๋„ŒํŠธ ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅ
  3. ์žฌ์‚ฌ์šฉ์„ฑ: ๋‹ค๋ฅธ ํŽ˜์ด์ง€์—์„œ๋„ ๋™์ผํ•œ ์ด๋ฒคํŠธ ๋ฆฌ์ŠคํŠธ UI ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅ
  4. ์œ ์ง€๋ณด์ˆ˜์„ฑ: ์ด๋ฒคํŠธ ๋ชฉ๋ก ๊ด€๋ จ ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ํ•œ ๊ณณ์—์„œ ๊ด€๋ฆฌ

๐Ÿšฆ ๋‹ค์Œ ๋‹จ๊ณ„

ํ˜„์žฌ ๊ตฌํ˜„๋œ ์บ์‹ฑ์€ ๊ธฐ๋ณธ์ ์ธ ์ˆ˜์ค€์ด๋ฉฐ, ์ถ”๊ฐ€๋กœ ๊ณ ๋ คํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐœ์„ ์‚ฌํ•ญ:

  1. Revalidation ์ „๋žต ์ˆ˜๋ฆฝ

    • ์ด๋ฒคํŠธ ์ƒ์„ฑ/์ˆ˜์ • ์‹œ ์บ์‹œ ๋ฌดํšจํ™”
    • ์‹œ๊ฐ„ ๊ธฐ๋ฐ˜ revalidation ์„ค์ •
  2. ์„ธ๋ถ„ํ™”๋œ ์บ์‹ฑ

    • ๊ฐœ๋ณ„ ์ด๋ฒคํŠธ ๋‹จ์œ„ ์บ์‹ฑ
    • ํƒœ๊ทธ ๊ธฐ๋ฐ˜ ์บ์‹œ ๋ฌดํšจํ™”
  3. ๋ชจ๋‹ˆํ„ฐ๋ง

    • ์บ์‹œ ํžˆํŠธ์œจ ์ธก์ •
    • ์„ฑ๋Šฅ ๋ฉ”ํŠธ๋ฆญ ์ถ”์ 

๐Ÿ“ ๊ฒฐ๋ก 

Next.js 16์˜ ์ƒˆ๋กœ์šด ์บ์‹ฑ ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•˜์—ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์„ฑ๋Šฅ์„ ํฌ๊ฒŒ ๊ฐœ์„ ํ•จ. 'use cache' ๋””๋ ‰ํ‹ฐ๋ธŒ์™€ ์„œ๋ฒ„ ์•ก์…˜์˜ ์กฐํ•ฉ์€ ๋งค์šฐ ๊ฐ•๋ ฅํ•˜๋ฉฐ, ๊ธฐ์กด์˜ ๋ณต์žกํ•œ ์บ์‹ฑ ์ „๋žต์„ ๋‹จ์ˆœํ™”ํ•  ์ˆ˜ ์žˆ์Œ.

ํŠนํžˆ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ ์—์„œ ์˜๋ฏธ๊ฐ€ ์žˆ์Œ:

  • โœ… ๊ฐœ๋ฐœ์ž ๊ฒฝํ—˜(DX) ํ–ฅ์ƒ: ์„ ์–ธ์ ์ธ ์บ์‹ฑ ๋ฐฉ์‹
  • โœ… ์„ฑ๋Šฅ ๊ฐœ์„ : ๋ถˆํ•„์š”ํ•œ ๋„คํŠธ์›Œํฌ ์š”์ฒญ ์ œ๊ฑฐ
  • โœ… ์ฝ”๋“œ ํ’ˆ์งˆ: ๋” ๋‚˜์€ ๊ตฌ์กฐ์™€ ๊ด€์‹ฌ์‚ฌ์˜ ๋ถ„๋ฆฌ
  • โœ… ํ™•์žฅ์„ฑ: ํ–ฅํ›„ ์ถ”๊ฐ€ ์ตœ์ ํ™”๋ฅผ ์œ„ํ•œ ๊ธฐ๋ฐ˜ ๋งˆ๋ จ

profile
I Enjoy Learn-and-Run Vibe๐Ÿ˜Š

0๊ฐœ์˜ ๋Œ“๊ธ€