๐ง Next.js ์ฌํ 1์ฅ: Caching Deep Dive โ 4์ค ์บ์ ์ํคํ ์ฒ ํํค์น๊ธฐ
๐ ๊ฐ์
4์ค ์บ์ ์ํคํ ์ฒ(Request Memoization, Data Cache, Full Route Cache, Router Cache)๋ฅผ ์์ ํ ์ดํดํฉ๋๋ค.
๐ ๋ชฉ์ฐจ
- ๐ ์ด ๋ฌธ์๋ฅผ ์ฝ๊ธฐ ์ ์
- ๐ค ์ ์์์ผ ํ๋๊ฐ
- ๐๏ธ ๋น์ ๋ก ๋จผ์ ์ดํดํ๊ธฐ
- ๐งฉ 1๋จ๊ณ: Request Memoization (์๋ช 1์ด์ ํจ์ ์บ์) ๐ข
- ๐ฑ 2๋จ๊ณ: Data Cache (DB ์ฟผ๋ฆฌ์ ์๊ตฌ ๋ณด์กด) ๐ก
- ๐ก๏ธ 3๋จ๊ณ: Full Route Cache (์์ฑ๋ HTML์ ํ์ํ) ๐ด
- ๐ฅ 4๋จ๊ณ: Router Cache (ํด๋ผ์ด์ธํธ ํญ ๋ฉ๋ชจ๋ฆฌ) ๐ฃ
- ๐ฅ ์๋ฌ ํด๊ฒฐ ์นดํ๋ก๊ทธ
- ๐ ์ด๋ฒ์ ๋ฐฐ์ด ๋ด์ฉ ์ด์ ๋ฆฌ
- ๐ ๋ง๋ฌด๋ฆฌ ํด์ฆ
- ๐ ๋ ์์๋ณด๊ธฐ
๐ ์ด ๋ฌธ์๋ฅผ ์ฝ๊ธฐ ์ ์
โฑ๏ธ ์์ ์ฝ๊ธฐ ์๊ฐ: 20๋ถ (์ ์ฒด) / ํต์ฌ ํํธ๋ง: 10๋ถ
๐บ๏ธ ์ด ๋ฌธ์์ ๋ฐฐ๊ฒฝ ์ธ๊ณ๊ด: '์์๋ค ์ปค๋ฎค๋ํฐ'
- ์์ฒ (์ ์ ): "์ด? ๊ด๋ฆฌ์ ํ์ด์ง์์ ๊ณต์ง์ฌํญ ์ ๋ชฉ์ '๊ธด๊ธ ํจ์น 2.0'์ผ๋ก ์์ ํ๊ณ DB ์ ์ฅ(UPDATE)๊น์ง ์ฑ๊ณตํ์ด์. ๊ทธ๋ฐ๋ฐ ๋ฉ์ธ ํ๋ฉด์ผ๋ก ๋์๊ฐ์ ์๋ก๊ณ ์นจ(F5)์ ํด๋ ์์ ์ ๋ชฉ์ธ '๊ธด๊ธ ํจ์น 1.0'๋ง ๊ณ์ ๋ ์. ์ ๊ฐ ์บ์ ๊ฐฑ์ ๊ฒฝ๋ก๋ฅผ ๋์น ๊ฑธ๊น์?"
- ์ํธ(๋ฆฌ๋): "์ข์ ์์ฌ์ด์์. Next.js๋ ๋ฒ์ ๊ณผ ์ค์ ์ ๋ฐ๋ผ Data Cache, Full Route Cache, Router Cache๊ฐ ์๋ก ๋ค๋ฅธ ์๋ช ์ผ๋ก ๋จ์ต๋๋ค. ์ ์ฅ ๋ก์ง์ด ์ฑ๊ณตํด๋ ๊ด๋ จ ์บ์๋ฅผ ์ด๋ป๊ฒ ๋ฌดํจํํ ์ง ์ฐ๊ฒฐํ์ง ์์ผ๋ฉด ํ๋ฉด์ ๋ก์ ๊ฒฐ๊ณผ๋ฅผ ๋ค์ ๋ฐ์ ์ ์์ด์."
๐บ๏ธ ์ด ๋ฌธ์์ ํ๋ฆ
Next.js ์บ์์ ์
๋ช
โ 4๊ฐ์ง ์บ์ ๊ณ์ธต ์๋ฒฝ ๋ถํด โ ๊ฐ ์บ์์ ์ด๊ธฐํ(Invalidate) ์๋ฆฌ
๐ฏ ์ด ๋ฌธ์๋ฅผ ๋ค ์ฝ์ผ๋ฉด ํ ์ ์๋ ๊ฒ
- ๋ด ์ฝ๋๊ฐ ์ด๋ ๊ณ์ธต์ ์บ์์ ๋ฌถ์ฌ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐฑ์ ํ์ง ๋ชปํ๊ณ ์๋์ง, "๋ฒ์ธ ๋ ์ด์ด"๋ฅผ ์ ํํ๊ฒ ์ง๋ชฉํ ์ ์๋ค.
- Vercel ๋น๋ ์ ํ๋ฉด ์์ ๋จ๋
โ (Static)๊ณผฦ (Dynamic)์ ์ง์ง ๋ด๋ถ ๋์ ์๋ฆฌ๋ฅผ ์ค๋ช ํ ์ ์๋ค.
๐ค ์ ์์์ผ ํ๋๊ฐ
Next.js App Router์ ์บ์๋ ๋ฒ์ ๊ณผ ์ค์ ์ ๋ฐ๋ผ ๊ธฐ๋ณธ๊ฐ์ด ๋ฌ๋ผ์ก์ด. Next 13/14์ ์ด์ ๋ชจ๋ธ์์๋ fetch์ ์ ์ ๋ผ์ฐํธ๊ฐ ์ ๊ทน์ ์ผ๋ก ์บ์๋์๊ณ , Next 15+ ์ดํ์๋ ๊ธฐ๋ณธ fetch๊ฐ ๋ ๋ณด์์ ์ผ๋ก ๋์ํ๋ฉฐ cacheComponents: true์ 'use cache'์ฒ๋ผ ๋ช
์์ ์ธ ์ ์ธ์ด ์ค์ํด์ก์ง.
๊ทธ๋๋ ํต์ฌ ์ง๋ฌธ์ ๊ทธ๋๋ก์ผ. "์ด ๊ฒฐ๊ณผ๋ฅผ ์ธ์ ๊น์ง ์ฌ์ฌ์ฉํด๋ ๋๋๊ฐ?" ์๋ฒ ๋ ๋๋ง(SSR) ์์ฃผ์ ์น์ ๊ตฌ์กฐ์ ์ผ๋ก ๋น์ธ๊ณ , ์ฌ์ฉ์๊ฐ 1๋ง ๋ช ๋ค์ด์ฌ ๋๋ง๋ค ์๋ฒ๊ฐ 1๋ง ๊ฐ์ HTML ๊ณต์ฅ์ ๋๋ฆฌ๊ณ DB๋ฅผ ์ฐ๋ฅด๋ฉด ๋น์ฉ๊ณผ ์ง์ฐ์ด ์ปค์ง๊ธฐ ๋๋ฌธ์ด์ผ.
ํ์ง๋ง ์ด๊ฑธ ์๋ฒฝํ๊ฒ ์ดํดํ์ง ๋ชปํ๋ฉด, ์์ฒ ์ด์ฒ๋ผ ํ๋ฃจ ์ข
์ผ DB ๊ฐ์ด ์
๋ฐ์ดํธ ์ ๋๋ ๋ช์์ ํค๋งค๊ฒ ๋ผ.
Next.js๋ ๋จ์ผ ์บ์๊ฐ ์๋๋ผ 4๊ฐ์ ์บ์ ๊ณ์ธต(Layer)์ด ๋ง์น ์ํ ๊ป์ง์ฒ๋ผ ์๋ก๋ฅผ ๋๋ฌ์ธ๊ณ ์์ด. ์ด 4์ค ์ด๋์ ๋ฉํ ๋ชจ๋ธ์ ๋จธ๋ฆฟ์์ ๊ทธ๋ฆฌ๋ ๊ฒ์ด ์๋์ด์ ๊ฐ์ฅ ์๋ํ ์ฌ์ ์ ์์์ด์ผ.
๐๏ธ ๋น์ ๋ก ๋จผ์ ์ดํดํ๊ธฐ
๐ง 5์ด์๊ฒ ์ค๋ช ํ๋ค๋ฉด? (์์๋ค ํ๋ฒ๊ฑฐ ๊ณต์ฅ์ 4์ค ์คํผ๋ ์์คํ )
์๋์ด "๋น ๋งฅ ํ๋!" ์ฃผ๋ฌธํ์ ๋ ๊ณต์ฅ ๋ด๋ถ์์ ์ผ์ด๋๋ 4๋จ๊ณ ์ต์ ํ:
- 1๋จ๊ณ (Router Cache - ๋ด ์ค๋งํธํฐ): "์ด? ๋ ๋ฐฉ๊ธ ๋น ๋งฅ ์์ผฐ์๋๋ฐ. ๋ฐฐ๋ฌ ์ ์ํค๊ณ ๋ด ์ฃผ๋จธ๋์์ ์๊น ์ํจ ๋น ๋งฅ(์ฌ์ง) ๊บผ๋ด์ ๋ด์ผ์ง~" (์๋ก๊ณ ์นจ ์ ๊น์ง ์ ์ง)
- 2๋จ๊ณ (Request Memoization - ํ ๋ฒ ๋ฐฐ๋ฌํ ๋): "์ด๋ฒ์ ์ง์ง ๋ฐฐ๋ฌ ์์ผฐ์ด. ์ฃผ๋ฐฉ์ฅ์ด ๊ณ ๊ธฐ ๊ตฝ๋๋ฐ, ๋ด๊ฐ ๊ณ ๊ธฐ(fetch) 2๋ฒ ๊ฐ๋ค ๋ฌ๋ผ๊ณ ํด๋ ์ฃผ๋ฐฉ์ฅ์ด ๋ฌด์ํ๊ณ ํ ๋ฒ ๊ตฌ์ด ๊ณ ๊ธฐ๋ฅผ ๋ฐ๋ฐ ๋๋ ์ค!"
- 3๋จ๊ณ (Data Cache - ์ฃผ๋ฐฉ์ ์๊ตฌ ๋๋๊ณ ): "์ด์ ๋ค์ด์จ ํน์ ์์ค(DB ๊ฒฐ๊ณผ)๋ฅผ ์๊ตฌ ๋๋๊ณ ์ ๋ณด๊ดํด๋์ด. ๋ด์ผ ์๋์ด ์๋, ๋ชจ๋ ์๋ ์ ๋ฒ๋ฆฌ๊ณ ๋๊ฐ์ ์์ค๋ฅผ ๊ณ์ ๋ฟ๋ฆด ๊ฑฐ์ผ!"
- 4๋จ๊ณ (Full Route Cache - ์ง์ด์ฅ์ ๋ชจํ ํ๋ฒ๊ฑฐ): "์์ ์์ค, ๋นต, ์ผ์ฑ๋ฅผ ๋ค ์กฐ๋ฆฝํด๋ ์์ ํ ๋น ๋งฅ(HTML ํ์ผ ์์ฒด)์ ๊ฐ๊ฒ ์์ ์ ๋ฆฌ์ฅ์์ผ๋ก ๊ฑธ์ด๋์ด! ์ฃผ๋ฌธ ์ค๋ฉด ์ฃผ๋ฐฉ์ฅ ์ ๊นจ์ฐ๊ณ ์ ๋ชจํ ๋ฐ๋ก ๋์ ธ์ค ใ ใ ใ "
๐งฉ 1๋จ๊ณ: Request Memoization (์๋ช 1์ด์ ํจ์ ์บ์) ๐ข
์ด๊ฑด ์ด๋ฏธ guide 6์ฅ์์ ๋ง์คํฐํ ๋ด์ฉ์ด์ผ. ๊ฐ๋ณ๊ฒ ์ง๊ณ ๋์ด๊ฐ์.
ํน์ง ์์ฝ
- ๋ชฉ์ : ๊น๊ณ ๋ณต์กํ ์ปดํฌ๋ํธ ํธ๋ฆฌ ํ์์์ ๋ฐ์ดํฐ๋ฅผ ๋๊ฐ์ด ๋ ํธ์ถํ ๋, ๋คํฌ์ํฌ ๋ถํ ๋ฐฉ์ง (Props Drilling ํํผ)
- ๋์: ์ค๋ก์ง
GET๋ฐฉ์์fetch()ํจ์. (๊ทธ๋ฆฌ๊ณ ์๋์ผ๋ก ๋ํํReact.cache) - ์๋ช : ๋ธ๋ผ์ฐ์ ๊ฐ ํ๋ฉด์ ๊ฐฑ์ ํ๋ ๋ฑ ๊ทธ "ํ ๋ฒ์ ๋ ๋๋ง ํด(Lifecycle)" ๋์๋ง ์ด์์์.
- ์ด๊ธฐํ(Revalidation) ๋ฐฉ๋ฒ: ์์. ์ปดํฌ๋ํธ ๋ ๋๋ง์ด ๋ฑ ๋๋๋ 1์ด ๋ค์ ๋ฉ๋ชจ๋ฆฌ์์ ์ฐ๊ธฐ์ฒ๋ผ ์ฌ๋ผ์ง.
๐ฑ 2๋จ๊ณ: Data Cache (DB ์ฟผ๋ฆฌ์ ์๊ตฌ ๋ณด์กด) ๐ก
์ฌ๊ธฐ์๋ถํฐ ์์ฒ ์ด๊ฐ ์ค์ ๋ก ๋๋ฒ๊น ํด์ผ ํ ๋ฒ์๊ฐ ๋์ด์ ธ. ์ ์ฅ์ ๋๋๋ฐ ํ๋ฉด์ด ๊ฐฑ์ ๋์ง ์์ ๋ ๊ฐ์ฅ ๋จผ์ ์์ฌํ ๊ณ์ธต์ด์ง.
ํน์ง
- ๋ชฉ์ : ๊ฐ์ URL๊ณผ ํ๋ผ๋ฏธํฐ๋ก ๋ค์ด์ค๋ ์ธ๋ถ API ์๋ต์ด๋ ์บ์ ๊ฐ๋ฅํ ๊ณ์ฐ ๊ฒฐ๊ณผ๋ฅผ ์๋ฒ ์บ์์ ์ ์ฅํด ์ฌ์ฌ์ฉํจ.
- ๋์:
fetch()์๋ต๊ฐ ๊ทธ ์์ฒด. - ์๋ช
:
cache: 'force-cache',next.revalidate,cacheLife, ํ๊ทธ ๋ฌดํจํ ๊ฐ์ ์ ์ฑ ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง.
โ ์์ฒ ์ด์ ํจ์ (๊ธฐ๋ณธ ์บ์ ๋ช)
// app/notice/page.tsx
export default async function NoticeInfo() {
// Next 13/14 ์ด์ ๋ชจ๋ธ์์๋ ๊ธฐ๋ณธ ์บ์ ๋์์ ํนํ ์กฐ์ฌํด์ผ ํ๋ค.
// ํ์ฌ ๋ฒ์ ์์๋ force-cache๋ revalidate๋ฅผ ๋ช
์ํ๋ฉด ๊ฐฑ์ ์ ์ฑ
์ด ํ์ํ๋ค.
const res = await fetch('https://db.api/api/notice/urgent', {
next: { revalidate: 3600 },
});
const data = await res.json();
return <div>{data.title}</div>
}โ ์ ์ด๊ถ ๋์ฐพ๊ธฐ (Opting out)
์์ฒ ๊ฐ์ง์ "์บ์ ์ ํด!" ํ์ถ ๋ฐฉ๋ฒ์ด ์์ด.
1) ๋ถ๋ถ ํ์ถ (Fetch ๋ ๋ฒจ)
fetch(url, { cache: 'no-store' }) // Next.js์ผ, ์ ๋ฐ ์ด ์ฟผ๋ฆฌ๋งํผ์ ๋งค๋ฒ ์ค์๊ฐ์ผ๋ก ๊ฐ์ ธ์ค๋ ด!
2) ํ์ผ ์ ์ฒด ํ์ถ (Segment Configuration)
export const dynamic = 'force-dynamic' // ์ด ํ์ผ(page) ๋ด์ ๋ชจ๋ ๋ก์ง ์บ์ ๊ฑฐ๋ถ!
export default async function Page() { ... }3) ์๊ฐ์ ๋ณด๊ด (ISR - Time based Revalidation)
fetch(url, { next: { revalidate: 3600 } }) // Next.js์ผ, ์ด๊ฑฐ 1์๊ฐ(3600์ด) ์นด์ดํธ๋ค์ดํ๊ณ ์บ์ ํ๊ธฐํด.
๐ก๏ธ 3๋จ๊ณ: Full Route Cache (์์ฑ๋ HTML์ ํ์ํ) ๐ด
Data Cache๊ฐ "DB ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ(JSON)"๋ฅผ ์กฐ๊ฐ์กฐ๊ฐ ์ผ๋ ค๋๋ ๊ฑฐ๋ผ๋ฉด, Full Route Cache๋ ๋ ๊ทน๊ฐ์ ๋ณ๊ธฐ์ผ.
์์ ํ๋ฉด ์ ์ฒด HTML/RSC ๊ฒฐ๊ณผ๋ฅผ ๋น๋ ํ์์ด๋ ์ฌ๊ฒ์ฆ ์์ ์ ๋ง๋ค์ด ๋๊ณ ์ฌ์ฌ์ฉํ๋ ๊ณ์ธต์ด๋ผ๊ณ ๋ณด๋ฉด ๋ผ.
ํน์ง
- ๋ชฉ์ : ์๋ฒ ๊นกํต CPU๋ฅผ ์๋ผ๊ธฐ ์ํด, 1์ด์ ์ง์ฐ๋ ์์ด ๋ฒ๊ฐ์ฒ๋ผ ํ๋ฉด์ ์๋ตํ๊ธฐ ์ํ ์์ ํ ๋ณด๊ด.
- ์๋ช
: ์๊ตฌ์ . ๋ค์ ๋น๋(Build)๋ช
๋ น
npm run build๋ฅผ ์๋ก ์น๊ธฐ ์ ๊น์ง ์ฌ๋ผ์ง์ง ์์. - ์กฐ๊ฑด: ์์ฒญ๋ง๋ค ๋ฌ๋ผ์ง๋ ์
๋ ฅ(
cookies,headers, ์ค์๊ฐ ๋ฐ์ดํฐ ๋ฑ)์ด ์๊ณ , ๋ผ์ฐํธ๊ฐ ์ ์ ์ผ๋ก ํ๊ฐ๋ ์ ์์ ๋.
๐ Static vs Dynamic ๋ฃจํธ ํ๋ ๊ธฐ
ํฐ๋ฏธ๋์์ npm run build๋ฅผ ์ณค์ ๋ ๋จ๋ ์ฑ์ ํ๋ฅผ ์ ๋ด์ผ ํด.
Route (app) Size First Load JS
โ โ / 154 B 86.6 kB
โ โ /about 154 B 86.6 kB
โ ฦ /profile/[id] 154 B 86.6 kB
โ (Static) prerendered as static HTML (uses no initial data)
ฦ (Dynamic) server-rendered on demand using Node.jsโ (Static)ํ์ ์ ๋น๋ฐ: ๋ผ์ฐํธ ๊ฒฐ๊ณผ๊ฐ ์์ฒญ๋ณ ์ ๋ ฅ์ ์์กดํ์ง ์์ ๋ ํ๋ํ๋ค. ๊ณต๊ฐ ๋ง์ผํ ํ์ด์ง๋ ์ผ์ ์๊ฐ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ๋ชฉ๋ก์ด ์ฌ๊ธฐ์ ์ด์ธ๋ฆฐ๋ค.ฦ (Dynamic)ํ์ : ๋ก๊ทธ์ธ ์ธ์ฆ์ฒ๋ผcookies()๋headers()์ ๋ฐ๋ผ ๊ฒฐ๊ณผ๊ฐ ๋ฐ๋๋ฉด ์์ฒญ๋ง๋ค ๋ค์ ํ๋จํด์ผ ํ๋ค. ๊ฐ์ธํ ๋ฐ์ดํฐ๋ฅผ ์ ์ HTML์ ์์ผ๋ฉด ์บ์ ์ค์ผ์ด ์๊ธด๋ค.
[์์ฒ ์ด ์๋ฌ์ ์ง์ ๊ท๋ช
]
์์ฒ ์ด์ ๊ณต์ง์ฌํญ ํ์ด์ง๋ ๊ณต๊ฐ ๋ฐ์ดํฐ๋ผ ์บ์ ํ๋ณด์์ด. DB ๊ฐ ์
๋ฐ์ดํธ ๋ก์ง(Admin)๋ง ๋ง๋ค๊ณ , ์ ์ ๊ฐ ๋ณด๋ ๋ผ์ฐํธ์ ๋ฐ์ดํฐ ํ๊ทธ๋ฅผ ๋ค์ ๊ฒ์ฆํ๋ผ๋ ๋ช
๋ น(revalidatePath, revalidateTag, updateTag)์ ์ฐ๊ฒฐํ์ง ์์๋ ๊ฑฐ์ผ.
๐ฅ 4๋จ๊ณ: Router Cache (ํด๋ผ์ด์ธํธ ํญ ๋ฉ๋ชจ๋ฆฌ) ๐ฃ
์๋ฒ๋ฅผ ๊ด๋ฆฌํ๋ ์ 3๊ฐ์ ์บ์์ ๋ค๋ฅด๊ฒ, ๋ง์ง๋ง ๋ฐฉ์ด์ ์ ์ฌํ๋ฆฌ/ํฌ๋กฌ ๋ธ๋ผ์ฐ์ ์ ์ฌ์ฉ์ ์ปดํจํฐ์ ๋ฉ๋ชจ๋ฆฌ(RAM) ์์ ์ด์์์ด.
๋ธ๋ผ์ฐ์ ๋ ๋๋ํ๊ณ ๊ฒ์ผ๋ฅด๋ค
Next.js App Router๋ก ๋ค๋น๊ฒ์ด์ (Link ํ๊ทธ ํด๋ฆญ)์ ํ๋ฉด, ๊ธฐ์กด ๋ฆฌ์กํธ์ฒ๋ผ ์๋ฒ๋ก ์ ๊ฐ๊ณ ๋ธ๋ผ์ฐ์ ์์ ๊ฟ์ณ๋ ๋ ๋๋ง ์กฐ๊ฐ ๋ชจ์(RSC Payload)์ ๊บผ๋ด์จ.
- ์๋ช
: ๋ธ๋ผ์ฐ์ ํญ์ X๋ก ๋ซ๊ฑฐ๋
์๋ก๊ณ ์นจ(F5)์ ๋๋ฅด๊ธฐ ์ ๊น์ง(๋๋ 30์ด~5๋ถ ๋ด์ธ ๋ฉ๋ชจ๋ฆฌ ์ ์ฑ ๋ง๋ฃ ์ ๊น์ง). - ์ด ๋์ ๋๋ฌธ์ "๋ ๋ฐฉ๊ธ ๊ธ ์ผ๋๋ฐ ๋ค๋ก ๊ฐ๊ธฐ ๋๋ ๋๋ ์๋ ๋ชฉ๋ก ๋จ๋ค?" ๊ฐ์ ๋ฒ๊ทธ์ฑ ์ฒด๊ฐ์ด ๊ฐํ์ ์ผ๋ก ๋ฐ์ํด.
๐จ ๋ฌดํจํํ๊ธฐ (Invalidation)
์ด ์บ์๊ฐ ๋ฐฉํด๊ฐ ๋ ๋๋ ๋ธ๋ผ์ฐ์ ์๊ฒ "๋ค์ํ์ผ๋ก ์ด ๋ฉ๋ชจ ์์ฒฉ ๋น์!"๋ผ๊ณ ๋ช ๋ นํด์ผ ํด.
'use client'
import { useRouter } from 'next/navigation'
export default function ReRouteButton() {
const router = useRouter()
return <button onClick={() => router.refresh()}>๊ฐ์ ๊ฐฑ์ (๋ธ๋ผ์ฐ์ ์บ์ ๋ฌดํจํ)!</button>
}router.refresh() ๋ ํ๋ฉด ๋ฐฑ์งํ ์์ด ์ค์ง ๋ฐฑ๊ทธ๋ผ์ด๋๋ก ์๋ฒ์ ์ต์ RSC Payload๋ง ์๋ก ์น ๋ด๋ ค๋ฐ์ ์นํํ๋ ๋ง๋ฒ์ ๊ณ ๊ธ ํ
์ด์ผ.
๐ฅ ์๋ฌ ํด๊ฒฐ ์นดํ๋ก๊ทธ
์๋ฌ ๋ฉ์์ง๊ฐ ๋จ๋ฉด Ctrl+F๋ก ๊ฒ์ํด๋ด.
โ Dynamic server usage: cookies ์๋ฌ๊ฐ ๋จ๋ฉด์ ๋น๋๊ฐ ์คํจํด์!
์์ธ: generateStaticParams ์ ๊ฐ์ด '๋ฏธ๋ฆฌ ์ ์ ์ผ๋ก(Static) ๊ตฌ์๋๋ ค๊ณ ์์ 'ํ ํ์ผ ๊ณต๊ฐ ๋ด๋ถ์์, cookies() ๋ URL ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ ๊ฐ์ด ์ค์๊ฐ ๋ฐํ์์๋ง ์ ์ ์๋ ๊ฐ์ฒด๋ฅผ ๋ฌด๋ฆฌํ๊ฒ ๊บผ๋ด ์ฐ๋ ค๋ค ๋ชจ์์ด ๋ฐ์ํ ๊ฒ.
ํด๊ฒฐ์ฑ
: ํ์ด์ง์ export const dynamic = 'force-dynamic' ์ ๋ช
์์ ์ผ๋ก ์ ์ธํ์ฌ ์ด ํ์ผ์ ์ ๋ ํ์(Static)์ผ๋ก ๋จ์ ์ ์๋ ์ด๋ช
์์ Next.js์๊ฒ ์๋ฐฑํด๋ผ.
๐ ์ด๋ฒ์ ๋ฐฐ์ด ๋ด์ฉ ์ด์ ๋ฆฌ
์ด ๊ฑฐ๋ํ 4์ค ์ฅ๋ฒฝ์ ๋ฐฉ์ด ์์! ๋ธ๋ผ์ฐ์ ๊ฐ ํ๋ฉด์ ๋ฌ๋ผ๊ณ ์กฐ๋ฅด๋ฉด...
| ๊ป์ง ๊ณ์ธต ์์ | ํ๊ฒจ๋ด๋ ๋จ๊ณ | ์บ์ ์์น | ๋ฌด๋ ฅํ ๋ฐฉ๋ฒ |
|---|---|---|---|
| 1๋ฒ ๋ฐฉ์ด๋ง | Router Cache: "์ผ ๋ธ๋ผ์ฐ์ ์ผ, ๋ ์๊น ์ด๊ฑฐ ๋ฐฉ๋ฌธํ์์์. ๋ด RAM์ ์ ์ฅ๋ ๊ฑฐ ์ค๊ฒ." | ํด๋ผ์ด์ธํธ (๋ธ๋ผ์ฐ์ ) | router.refresh() / ํ์ด์ง ์ฐฝ ๋ซ๊ธฐ / F5 ๊ฐ์ ์ธ๋ก๊ณ ์นจ |
| 2๋ฒ ๋ฐฉ์ด๋ง | Full Route Cache: (์๋ฒ ๋๋ฌ) "์ด? ๋๊ฐ ์ฐพ๋ HTML, ๋ด๊ฐ ์ ๋ฒ ๋น๋ ๋ ์์ ํ ํ์์ผ๋ก ๊ตฌ์๋จ์ง!" | ์๋ฒ (๋์คํฌ) | ์ฌ๋น๋(build) / revalidatePath ์๋ฒ์ก์
ํ๊ฒฉ |
| 3๋ฒ ๋ฐฉ์ด๋ง | Request Memoization: (์ปดํฌ๋ํธ ๋ ๋๋ง ์ค) "์ ๋๊ฐ์ fetch ๋ค? ์ฃผ๋ฐฉ์ฅ ๊ณ ์ํ์ง ๋ง๊ณ ๋ด ๊ธฐ์ต(๋ฉ๋ชจ๋ฆฌ)์์ ๋ณต์ฌํด์ค๊ฒ." | ์๋ฒ (๋ฉ๋ชจ๋ฆฌ ๋จ๋ฐ์ฑ) | ์กฐ์น ํ์ ์์ (1 ๋ฐํ์ ์ข ๋ฃ ์ ์๋ ํ๊ธฐ) |
| 4๋ฒ ๋ฐฉ์ด๋ง | Data Cache: "๊ฒฐ๊ตญ ์ง์ง ๋ฐ์ดํฐ ์ฐ๋ฅด๋ ค ์๋ค? ๊ทผ๋ฐ ๊ทธ API ๊ฒฐ๊ณผ๊ฐ 5์๊ฐ ๋์ ์ผ๋ ค๋ ๋ด DB ์บ์ ์ฐฝ๊ณ ์์ ์ค๊ฒ ใ ใ ใ " | ์๋ฒ (๋์คํฌ) | fetch { cache: no-store } / revalidateTag ๋ฑ |
๐ก ์๋์ด์ ๋ฉํ ๋ชจ๋ธ
๋น๋ ์โ (Static)๋ก ๊ตณ์ด๋ฒ๋ฆฐ ๋ผ์ฐํธ๋ Data Cache๋ฅผ ๋ฌดํจํํ๊ธฐ ์ ๊น์ง ์ ๋ ์๊ธฐ ์ค์ค๋ก ๊ฐฑ์ ๋์ง ์๋๋ค.
"๋ฐ์ดํฐ๊ฐ ์ ๋ฐ๋์ด์!" ๋ผ๋ ์ง๋ฌธ์ ๋นํฉํ์ง ๋ง๊ณ , ๊ฐ์ฅ ๋จผ์ Vercel ๋น๋ ํฐ๋ฏธ๋ ์ฐฝ์ ์ด๊ณ ๊ทธ ํ์ด์ง๊ฐโ์ธ์งฦ์ธ์ง๋ถํฐ ์์ถํ๋ผ!
๐ ๋ง๋ฌด๋ฆฌ ํด์ฆ
Q1. ์์ฒ ์ด๊ฐ /profile/me ํ์ด์ง์์ cookies()๋ก ์ธ์ ์ ์ฝ๊ณ ์ฌ์ฉ์ ์ด๋ฆ์ ๋ ๋๋งํ๋ค. ์ด ํ์ด์ง๋ฅผ Full Route Cache๋ก ์ ์ ์ผ๋ก ๊ตฌ์๋ ๋ ๊น?
โ ์ ๋ต: ์ ๋๋ค.
๐ก ์์ธ ํด์ค: /profile/me๋ ์์ฒญ ์ฟ ํค์ ๋ฐ๋ผ ๊ฒฐ๊ณผ๊ฐ ๋ฌ๋ผ์ง๋ ๊ฐ์ธํ ํ์ด์ง๋ค. cookies(), headers() ๊ฐ์ ์์ฒญ ์์ API๋ฅผ ์ฐ๋ฉด ์ ์ HTML ํ๋๋ฅผ ๋ชจ๋ ์ฌ์ฉ์์๊ฒ ๊ณต์ ํ ์ ์๋ค. ์ํธ๊ฐ ๊ฐ์กฐํ ๊ธฐ์ค์ ๊ฐ๋จํ๋ค. ์์ฒญ๋ง๋ค ๋ฌ๋ผ์ง๋ ์ ๋ ฅ์ด ๋ ๋๋ง ๊ฒฐ๊ณผ๋ฅผ ๋ฐ๊พธ๋ฉด Full Route Cache ๋์์ด ์๋๋ค. ๊ณต๊ฐ ํ๋กํ์ฒ๋ผ URL ํ๋ผ๋ฏธํฐ๋ง์ผ๋ก ๊ฒฐ๊ณผ๊ฐ ๊ฒฐ์ ๋๋ ๊ตฌ์กฐ์ ๋ถ๋ฆฌํด์ผ ํ๋ค.
Q2. ๊ด๋ฆฌ์ ํ์ด์ง์์ ๊ณต์ง ์ ๋ชฉ์ ์์ ํ๋๋ฐ ๋ฉ์ธ ๊ณต์ง ๋ชฉ๋ก์ด ๊ณ์ ์์ ์ ๋ชฉ์ ๋ณด์ฌ์ค๋ค. ์๋ฒ์ ๋จ์ ์์ ๊ฐ๋ฅ์ฑ์ด ๊ฐ์ฅ ํฐ ์บ์๋ ๋ฌด์์ธ๊ฐ?
โ ์ ๋ต: Data Cache ๋๋ ๊ทธ ๋ฐ์ดํฐ๋ฅผ ํฌํจํด ๋ง๋ค์ด์ง Full Route Cache๋ค.
๐ก ์์ธ ํด์ค: Request Memoization์ ํ ๋ฒ์ ๋ ๋๋ง ๋์๋ง ์ค๋ณต fetch๋ฅผ ํฉ์น๋ ์์ ๊ธฐ์ต์ด๊ณ , Router Cache๋ ๋ธ๋ผ์ฐ์ ์ธ์ ์ RSC Payload ๊ธฐ์ต์ด๋ค. ์ ์์ฒญ์์๋ ๋ก์ ๋ฐ์ดํฐ๊ฐ ๋ฐ๋ณต๋๋ค๋ฉด ์๋ฒ ์ชฝ Data Cache๊ฐ ๊ฐฑ์ ๋์ง ์์๊ฑฐ๋, ๊ทธ ๋ฐ์ดํฐ๋ก ๋ง๋ Full Route Cache๊ฐ ์์ง ์ฌ๊ฒ์ฆ๋์ง ์์์ ๊ฐ๋ฅ์ฑ์ด ๋๋ค. ์์ ์ก์ ์๋ revalidateTag๋ revalidatePath ๊ฐ์ ๋ฌดํจํ ์ ๋ต์ด ํจ๊ป ์์ด์ผ ํ๋ค.
Q3. ์์ฒ ์ด์ ํ ์คํธ ํ์: ์์๋ค ์ปค๋ฎค๋ํฐ ํ์ ๊ณต๊ฐ ๊ฒ์๊ธ ๋ชฉ๋ก๊ณผ ๋ก๊ทธ์ธํ ์ฌ์ฉ์์ ์๋ฆผ ๋ฐฐ์ง๋ฅผ ํจ๊ป ๋ณด์ฌ์ค๋ค. ์ ์ฒด ํ์ด์ง๋ฅผ Dynamic์ผ๋ก ๋ง๋ค์ง ์๊ณ ๋น ๋ฅธ ์ฒซ ํ๋ฉด๋ ์งํค๊ณ ์ถ๋ค. ์ด๋ค ์ค๊ณ๊ฐ ๋ ์์ ํ ๊น?
โ ์ ๋ต: ๊ณต๊ฐ ๊ฒ์๊ธ ๋ชฉ๋ก์ ์บ์ ๊ฐ๋ฅํ ์๋ฒ ๋ฐ์ดํฐ๋ก ๋๊ณ , ์๋ฆผ ๋ฐฐ์ง๋ ์์ฒญ ์์ ๋ฐ์ดํฐ๊ฐ ํ์ํ ๋ณ๋ ๊ฒฝ๊ณ๋ก ๋ถ๋ฆฌํ๋ค.
๐ก ์์ธ ํด์ค: ๊ณต๊ฐ ๋ชฉ๋ก์ ์ฌ๋ฌ ์ฌ์ฉ์๊ฐ ๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฏ๋ก Data Cache๋ Full Route Cache์ ํ๋ณด๊ฐ ๋๋ค. ๋ฐ๋ฉด ์๋ฆผ ๋ฐฐ์ง๋ ์ฟ ํค์ ์ฌ์ฉ์๋ณ ๊ถํ์ ์์กดํ๋ฏ๋ก ์ ์ ์ ธ ์์ ์์ผ๋ฉด ์บ์ ์ค์ผ์ด ์๊ธด๋ค. ์ํธ๋ผ๋ฉด "๋ฌด์์ ์บ์ํ ์ง"๋ณด๋ค ๋จผ์ ์ด๋ค ์ ๋ ฅ์ด ๊ฒฐ๊ณผ๋ฅผ ๋ฐ๊พธ๋์ง๋ฅผ ํ๋ก ๋๋๋ผ๊ณ ๋ฆฌ๋ทฐํ ๊ฒ์ด๋ค.
๐ฃ ์์ฒ ์ด์ ํด๊ทผ ์ผ๊ธฐ
์ค๋์ ์บ์๋ฅผ ํ๋์ ์ค์์น์ฒ๋ผ ๋ณด๋ ์ต๊ด์ ๋ฒ๋ ธ๋ค. Request Memoization, Data Cache, Full Route Cache, Router Cache๊ฐ ์๋ก ๋ค๋ฅธ ์๋ช ๊ณผ ์์น๋ฅผ ๊ฐ์ง๋ค๋ ๊ฑธ ์๊ณ ๋๋, "์ ์๋ก๊ณ ์นจํ๋๋ฐ๋ ๊ทธ๋๋ก์ง?"๋ผ๋ ์ง๋ฌธ๋ ํจ์ฌ ์ ํํด์ก๋ค.
๐ก "์บ์๋ ๋น ๋ฅด๊ฒ ๋ง๋๋ ์ฅ์น๊ฐ ์๋๋ผ, ๊ฐ์ ๊ฒฐ๊ณผ๋ผ๊ณ ๋งํ ์ ์๋ ๋ฒ์๋ฅผ ์ ์ธํ๋ ์ฅ์น๋ค."
๋ด์ผ๋ถํฐ ๋ฆฌ๋ทฐ์์๋ ๋จผ์ ๋ฐ์ดํฐ์ ์ฃผ์ธ์ ๋ฌป๊ธฐ๋ก ํ๋ค. ๊ณต๊ฐ ๋ฐ์ดํฐ์ธ์ง, ์ฌ์ฉ์ ์ฟ ํค์ ๋ฌถ์ธ ๋ฐ์ดํฐ์ธ์ง, ๋ธ๋ผ์ฐ์ ๊ฐ ์ ๊น ๋ค๊ณ ์๋ ํ๋ฉด ์กฐ๊ฐ์ธ์ง ๋๋ ๋ณด๊ณ , ์บ์๋ฅผ ๋ถ์ธ ์ฝ๋ ์์๋ ๋ฐ๋์ ๋ฌดํจํ ๊ฒฝ๋ก๋ฅผ ๊ฐ์ด ํ์ธํ๊ฒ ๋ค. ์ํธ๊ฐ ๋งํ ๊ฒ์ฒ๋ผ ์บ์ ์ค๊ณ๋ ์ฑ๋ฅ ํ๋์ด๋ฉด์ ๋์์ ๊ฐ์ธ์ ๋ณด ๊ฒฝ๊ณ ์ค๊ณ๋ค.