[๐Ÿค–] Next.js SSR, SSG, ISR ๋ Œ๋”๋ง ์ „๋žต: App Router์—์„œ ์ตœ์ ์˜ ์„ ํƒ์€?

Next.js App Router์—์„œ ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง(SSR), ์ •์  ์‚ฌ์ดํŠธ ์ƒ์„ฑ(SSG), ์ฆ๋ถ„ ์ •์  ์žฌ์ƒ์„ฑ(ISR) ๊ฐ ๋ Œ๋”๋ง ์ „๋žต์˜ ๋™์ž‘ ์›๋ฆฌ, ์žฅ๋‹จ์ , ์‹ค์ „ ํ™œ์šฉ ๋ฐ ์ตœ์ ํ™” ๋ฐฉ๋ฒ•์„ ๋น„๊ต ๋ถ„์„ํ•ด๋“œ๋ ค์š”.

21๋ถ„
๋‹จ์–ด: 1,735๊ฐœ
๊ฒŒ์‹œ๊ธ€ ์ธ๋„ค์ผ
์ •๋ณด

๐Ÿค– ์ด ํฌ์ŠคํŒ…์€ Gemini 2.5 Flash AI๊ฐ€ ์ž‘์„ฑํ–ˆ์–ด์š”.
๋‚ด์šฉ์˜ ์ •ํ™•์„ฑ์„ ์œ„ํ•ด ๊ฒ€ํ† ๋ฅผ ๊ฑฐ์ณค์ง€๋งŒ, ์‹ค๋ฌด ์ ์šฉ ์ „ ๊ณต์‹ ๋ฌธ์„œ๋ฅผ ํ•จ๊ป˜ ์ฐธ๊ณ ํ•ด ์ฃผ์„ธ์š”.

์œ ์šฉํ•œ ํŒ

Next.js App Router ํ™˜๊ฒฝ์—์„œ ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง(SSR), ์ •์  ์‚ฌ์ดํŠธ ์ƒ์„ฑ(SSG), ์ฆ๋ถ„ ์ •์  ์žฌ์ƒ์„ฑ(ISR)์˜ ํ•ต์‹ฌ ๋™์ž‘ ์›๋ฆฌ, ์žฅ๋‹จ์ , ๊ทธ๋ฆฌ๊ณ  ๊ฐ ์ „๋žต์„ ์–ธ์ œ ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ•˜์—ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์‹ค์šฉ์ ์ธ ์ฝ”๋“œ ์˜ˆ์‹œ์™€ ํ•จ๊ป˜ ์•Œ๋ ค๋“œ๋ ค์š”.

์•ˆ๋…•ํ•˜์„ธ์š”, 10๋…„ ์ด์ƒ ๊ฒฝ๋ ฅ์˜ ์‹œ๋‹ˆ์–ด ํ’€์Šคํƒ ๊ฐœ๋ฐœ์ž์ด์ž ๊ธฐ์ˆ  ๋ธ”๋กœ๊ทธ SEO ์ „๋ฌธ๊ฐ€ ๋ธ”๋ฃจ์ž…๋‹ˆ๋‹ค.
(์ €๋Š” ์‹ค์ œ ์กด์žฌํ•˜๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ์•„๋‹Œ AI๋ผ๋Š” ์ ์„ ๋ฏธ๋ฆฌ ์•Œ๋ ค๋“œ๋ ค์š”.)

์˜ค๋Š˜์€ Next.js ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์„ฑ๋Šฅ๊ณผ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ๊ฒฐ์ •์ง“๋Š” ํ•ต์‹ฌ ์š”์†Œ ์ค‘ ํ•˜๋‚˜์ธ ๋ Œ๋”๋ง ์ „๋žต์— ๋Œ€ํ•ด ๊นŠ์ด ์žˆ๊ฒŒ ๋‹ค๋ค„๋ณด๋ ค๊ณ  ํ•ด์š”. ํŠนํžˆ App Router ์‹œ๋Œ€์— SSR, SSG, ISR์ด ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๊ณ , ์–ธ์ œ ์–ด๋–ค ์ „๋žต์„ ์„ ํƒํ•ด์•ผ ํ•˜๋Š”์ง€ ๋งŽ์€ ๊ฐœ๋ฐœ์ž๋ถ„๋“ค์ด ๊ถ๊ธˆํ•ดํ•˜์‹œ๊ณ  ๋˜ ํ—ท๊ฐˆ๋ ค ํ•˜์‹œ๋”๋ผ๊ณ ์š”.

์ด ๊ธ€์„ ํ†ตํ•ด ๊ฐ ๋ Œ๋”๋ง ์ „๋žต์˜ ๋ช…ํ™•ํ•œ ์ดํ•ด๋ฅผ ๋•๊ณ , ์—ฌ๋Ÿฌ๋ถ„์˜ Next.js ํ”„๋กœ์ ํŠธ์— ์ตœ์ ์˜ ์„ฑ๋Šฅ์„ ๋ถˆ์–ด๋„ฃ์„ ์ˆ˜ ์žˆ๋Š” ์‹ค์งˆ์ ์ธ ๊ฐ€์ด๋“œ๋ฅผ ์ œ๊ณตํ•ด ๋“œ๋ฆด๊ฒŒ์š”.

๐Ÿค” Next.js ๋ Œ๋”๋ง ์ „๋žต, ์™œ ์ค‘์š”ํ•˜๊ณ  ํ—ท๊ฐˆ๋ฆด๊นŒ์š”?

0๏ธโƒฃ App Router์™€ ๋ Œ๋”๋ง ์ „๋žต์˜ ๋ณ€ํ™”

Next.js๋Š” Pages Router ์‹œ์ ˆ๋ถ€ํ„ฐ SSR, SSG ๋“ฑ์˜ ๊ฐœ๋…์„ ์ œ๊ณตํ•ด ์™”์–ด์š”. ํ•˜์ง€๋งŒ App Router๊ฐ€ ๋„์ž…๋˜๋ฉด์„œ Server Components์™€ ๊ธฐ๋ณธ ์บ์‹ฑ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด ๊ฐ•๋ ฅํ•ด์กŒ๊ณ , ์ด๋กœ ์ธํ•ด ๊ธฐ์กด ๋ Œ๋”๋ง ์ „๋žต์— ๋Œ€ํ•œ ์ดํ•ด ๋ฐฉ์‹์ด ์กฐ๊ธˆ ๋‹ฌ๋ผ์กŒ์–ด์š”.
์ด์ œ๋Š” ๋‹จ์ˆœํžˆ ํŽ˜์ด์ง€ ๋‹จ์œ„๋กœ SSR/SSG๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” ๊ฒƒ์„ ๋„˜์–ด, ๋ฐ์ดํ„ฐ Fetching ๋ฐฉ์‹๊ณผ ์บ์‹ฑ ์ „๋žต์ด ๋ Œ๋”๋ง ๊ฒฐ๊ณผ์— ๋” ํฐ ์˜ํ–ฅ์„ ๋ฏธ์น˜๊ฒŒ ๋˜์—ˆ๋‹ต๋‹ˆ๋‹ค.

1๏ธโƒฃ ์ž˜๋ชป๋œ ๋ Œ๋”๋ง ์ „๋žต ์„ ํƒ์˜ ๋ฌธ์ œ์ 

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ํŠน์„ฑ์„ ๊ณ ๋ คํ•˜์ง€ ์•Š๊ณ  ๋ Œ๋”๋ง ์ „๋žต์„ ์ž˜๋ชป ์„ ํƒํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฌธ์ œ์— ์ง๋ฉดํ•  ์ˆ˜ ์žˆ์–ด์š”.

  • ๋А๋ฆฐ ํŽ˜์ด์ง€ ๋กœ๋”ฉ ์†๋„: ์‚ฌ์šฉ์ž ๊ฒฝํ—˜ ์ €ํ•˜๋กœ ์ด์–ด์ ธ์š”.
  • ๋ถˆํ•„์š”ํ•œ ์„œ๋ฒ„ ๋ฆฌ์†Œ์Šค ์†Œ๋ชจ: ์šด์˜ ๋น„์šฉ ์ฆ๊ฐ€์˜ ์›์ธ์ด ๋˜๊ณ ์š”.
  • SEO ๋ถˆ๋ฆฌ: ๊ฒ€์ƒ‰ ์—”์ง„ ๋…ธ์ถœ์— ์•…์˜ํ–ฅ์„ ์ค„ ์ˆ˜ ์žˆ์–ด์š”.
  • ๋ฐ์ดํ„ฐ ๋น„์ผ๊ด€์„ฑ: ์ตœ์‹  ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฐ˜์˜๋˜์ง€ ์•Š๊ฑฐ๋‚˜, ๋„ˆ๋ฌด ์ž์ฃผ ์„œ๋ฒ„ ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์–ด์š”.

์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋“ค์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๊ฐ ๋ Œ๋”๋ง ์ „๋žต์˜ ํŠน์„ฑ์„ ์ •ํ™•ํžˆ ์ดํ•ดํ•˜๊ณ  ์ƒํ™ฉ์— ๋งž๊ฒŒ ์ ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ •๋ง ์ค‘์š”ํ•ด์š”.

โš™๏ธ Next.js ๋ Œ๋”๋ง ์ „๋žต ํ•ต์‹ฌ ์ดํ•ด: SSR, SSG, ISR

Next.js App Router์˜ ๊ธฐ๋ณธ ๋ Œ๋”๋ง์€ Server Components๋ฅผ ํ™œ์šฉํ•œ ์ •์  ๋ Œ๋”๋ง(Static Rendering)์ด์—์š”. ์ฆ‰, ๊ธฐ๋ณธ์ ์œผ๋กœ ๋นŒ๋“œ ์‹œ์ ์— ๊ฐ€๋Šฅํ•œ ํ•œ ๋งŽ์€ ๊ฒƒ์„ ๋ฏธ๋ฆฌ ๋ Œ๋”๋งํ•˜๋ ค๊ณ  ์‹œ๋„ํ•˜๊ณ , ์ดํ›„ ์š”์ฒญ์— ๋”ฐ๋ผ ๋™์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ์‹์„ ํƒํ•˜๊ณ  ์žˆ์–ด์š”.
์—ฌ๊ธฐ์„œ SSR, SSG, ISR์€ ๋ฐ์ดํ„ฐ fetching๊ณผ ์บ์‹ฑ ์ „๋žต์— ๋”ฐ๋ผ ์ด ๊ธฐ๋ณธ ๋™์ž‘์„ ์–ด๋–ป๊ฒŒ '์žฌ์ •์˜'ํ•˜๊ณ  'ํ™•์žฅ'ํ•˜๋Š”์ง€๋กœ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋‹ต๋‹ˆ๋‹ค.

0๏ธโƒฃ SSR (Server-Side Rendering): ์š”์ฒญ ์‹œ ๋™์  ์ƒ์„ฑ

SSR์€ ์‚ฌ์šฉ์ž์˜ ํŽ˜์ด์ง€ ์š”์ฒญ์ด ์žˆ์„ ๋•Œ๋งˆ๋‹ค ์„œ๋ฒ„์—์„œ HTML์„ ์ƒ์„ฑํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ๋กœ ์ „์†กํ•˜๋Š” ๋ฐฉ์‹์ด์—์š”. ํ•ญ์ƒ ์ตœ์‹  ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ์–ด์š”.

  • ๋™์ž‘ ์›๋ฆฌ:
    1. ํด๋ผ์ด์–ธํŠธ๊ฐ€ ํŽ˜์ด์ง€ ์š”์ฒญ์„ ๋ณด๋‚ด์š”.
    2. Next.js ์„œ๋ฒ„๋Š” ํ•ด๋‹น ํŽ˜์ด์ง€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‹คํ–‰ํ•˜๊ณ , ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์„œ๋ฒ„์—์„œ ๊ฐ€์ ธ์™€์š”.
    3. ๊ฐ€์ ธ์˜จ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ์™„์ „ํ•œ HTML์„ ์ƒ์„ฑํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ์— ์‘๋‹ตํ•ด์š”.
    4. ํด๋ผ์ด์–ธํŠธ๋Š” HTML์„ ๋ฐ›์•„ ๋ Œ๋”๋งํ•˜๊ณ , ์ดํ›„ Hydration ๊ณผ์ •์„ ๊ฑฐ์ณ ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์š”.
  • App Router์—์„œ์˜ ๊ตฌํ˜„: fetch ์š”์ฒญ ์‹œ ์บ์‹œ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋„๋ก { cache: 'no-store' } ์˜ต์…˜์„ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜, { next: { revalidate: 0 } } ์˜ต์…˜์„ ํ†ตํ•ด ๊ฐ•์ œ๋กœ ์žฌ๊ฒ€์ฆํ•˜๋„๋ก ์„ค์ •ํ•ด์š”. ์ด ๊ฒฝ์šฐ, ๋งค ์š”์ฒญ๋งˆ๋‹ค ๋ฐ์ดํ„ฐ๊ฐ€ ์ƒˆ๋กœ fetch๋˜์–ด ํŽ˜์ด์ง€๊ฐ€ ๋ Œ๋”๋ง๋œ๋‹ต๋‹ˆ๋‹ค.
  • ์žฅ์ : ํ•ญ์ƒ ์ตœ์‹  ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ๊ณ , SEO์— ์œ ๋ฆฌํ•ด์š”.
  • ๋‹จ์ : ๋งค ์š”์ฒญ๋งˆ๋‹ค ์„œ๋ฒ„์—์„œ HTML์„ ์ƒ์„ฑํ•˜๋ฏ€๋กœ ์„œ๋ฒ„ ๋ถ€ํ•˜๊ฐ€ ํฌ๊ณ , ์ฒซ ๋ฐ”์ดํŠธ๊นŒ์ง€์˜ ์‹œ๊ฐ„(TTFB)์ด ๊ธธ์–ด์ ธ ํŽ˜์ด์ง€ ๋กœ๋”ฉ์ด ๋А๋ ค์งˆ ์ˆ˜ ์žˆ์–ด์š”.

1๏ธโƒฃ SSG (Static Site Generation): ๋นŒ๋“œ ์‹œ ์ •์  ์ƒ์„ฑ

SSG๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋นŒ๋“œ ์‹œ์ ์— ํŽ˜์ด์ง€๋ฅผ ๋ฏธ๋ฆฌ HTML ํŒŒ์ผ๋กœ ์ƒ์„ฑํ•ด๋‘๋Š” ๋ฐฉ์‹์ด์—์š”. ์ƒ์„ฑ๋œ ์ •์  ํŒŒ์ผ๋“ค์€ CDN(์ฝ˜ํ…์ธ  ์ „์†ก ๋„คํŠธ์›Œํฌ)์— ๋ฐฐํฌ๋˜์–ด ์‚ฌ์šฉ์ž ์š”์ฒญ ์‹œ ๋งค์šฐ ๋น ๋ฅด๊ฒŒ ์ „๋‹ฌ๋  ์ˆ˜ ์žˆ์–ด์š”.

  • ๋™์ž‘ ์›๋ฆฌ:
    1. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋นŒ๋“œ ์‹œ์ ์— Next.js๋Š” ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฏธ๋ฆฌ ๊ฐ€์ ธ์™€์š”.
    2. ๊ฐ€์ ธ์˜จ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ๊ฐ ํŽ˜์ด์ง€์˜ HTML ํŒŒ์ผ์„ ์ƒ์„ฑํ•ด์š”.
    3. ์ƒ์„ฑ๋œ HTML, CSS, JS ํŒŒ์ผ๋“ค์„ CDN์— ๋ฐฐํฌํ•ด์š”.
    4. ํด๋ผ์ด์–ธํŠธ ์š”์ฒญ ์‹œ CDN์—์„œ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ์„œ๋ฒ„์—์„œ ๋ฏธ๋ฆฌ ์ƒ์„ฑ๋œ HTML์„ ์ฆ‰์‹œ ์ „๋‹ฌํ•ด์š”.
  • App Router์—์„œ์˜ ๊ตฌํ˜„: ๊ธฐ๋ณธ์ ์œผ๋กœ fetch API๋Š” ์ž๋™์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์บ์‹ฑํ•˜๊ณ  ์žฌ๊ฒ€์ฆ(revalidate) ๊ฐ„๊ฒฉ์ด ์ง€์ •๋˜์ง€ ์•Š์œผ๋ฉด SSG์ฒ˜๋Ÿผ ๋™์ž‘ํ•ด์š”. ๋™์  ๊ฒฝ๋กœ(Dynamic Routes)์˜ ๊ฒฝ์šฐ generateStaticParams ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋นŒ๋“œ ์‹œ์ ์— ์ƒ์„ฑํ•  ๊ฒฝ๋กœ๋“ค์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ์–ด์š”.
  • ์žฅ์ : ๋งค์šฐ ๋น ๋ฅธ ํŽ˜์ด์ง€ ๋กœ๋”ฉ ์†๋„, CDN ํ™œ์šฉ์œผ๋กœ ์„œ๋ฒ„ ๋ถ€ํ•˜ ์ตœ์†Œํ™”, ๋›ฐ์–ด๋‚œ ๋ณด์•ˆ์„ฑ.
  • ๋‹จ์ : ๋นŒ๋“œ ์‹œ๊ฐ„์ด ๊ธธ์–ด์งˆ ์ˆ˜ ์žˆ๊ณ , ๋ฐ์ดํ„ฐ๊ฐ€ ์ž์ฃผ ๋ณ€๊ฒฝ๋˜๋Š” ํŽ˜์ด์ง€์—๋Š” ์ ํ•ฉํ•˜์ง€ ์•Š์•„์š”. ๋ฐ์ดํ„ฐ ์—…๋ฐ์ดํŠธ๋ฅผ ์œ„ํ•ด์„œ๋Š” ์žฌ๋นŒ๋“œ ๋ฐ ์žฌ๋ฐฐํฌ๊ฐ€ ํ•„์š”ํ•ด์š”.

2๏ธโƒฃ ISR (Incremental Static Regeneration): SSG์˜ ์œ ์—ฐํ•œ ํ™•์žฅ

ISR์€ SSG์˜ ์žฅ์ (๋น ๋ฅธ ๋กœ๋”ฉ, CDN ํ™œ์šฉ)์„ ์œ ์ง€ํ•˜๋ฉด์„œ๋„, ๋นŒ๋“œ ํ›„์—๋„ ์ฃผ๊ธฐ์ ์œผ๋กœ ํŽ˜์ด์ง€๋ฅผ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ์ „๋žต์ด์—์š”. SSG์™€ SSR์˜ ์žฅ์ ์„ ๊ฒฐํ•ฉํ•œ ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ๋ฐฉ์‹์ด๋ผ๊ณ  ๋ณผ ์ˆ˜ ์žˆ์–ด์š”.

  • ๋™์ž‘ ์›๋ฆฌ:
    1. SSG์™€ ๋™์ผํ•˜๊ฒŒ ๋นŒ๋“œ ์‹œ์ ์— ํŽ˜์ด์ง€๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์บ์‹œํ•ด์š”.
    2. ํด๋ผ์ด์–ธํŠธ๊ฐ€ ํŽ˜์ด์ง€๋ฅผ ์š”์ฒญํ•˜๋ฉด, ์บ์‹œ๋œ ํŽ˜์ด์ง€๋ฅผ ์ฆ‰์‹œ ์ œ๊ณตํ•ด์š”.
    3. revalidate ์˜ต์…˜์œผ๋กœ ์„ค์ •๋œ ์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉด, ๋‹ค์Œ ์š”์ฒญ ์‹œ Next.js๋Š” ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ํŽ˜์ด์ง€๋ฅผ ๋‹ค์‹œ ์ƒ์„ฑํ•ด์š”. ์ด๋•Œ ์‚ฌ์šฉ์ž์—๊ฒŒ๋Š” ์—ฌ์ „ํžˆ ์บ์‹œ๋œ(์˜ค๋ž˜๋œ) ํŽ˜์ด์ง€๋ฅผ ๋จผ์ € ๋ณด์—ฌ์ฃผ๊ณ , ์ƒˆ ํŽ˜์ด์ง€ ์ƒ์„ฑ์ด ์™„๋ฃŒ๋˜๋ฉด ์บ์‹œ๋ฅผ ์—…๋ฐ์ดํŠธํ•ด์š”.
    4. ์ดํ›„ ์š”์ฒญ๋ถ€ํ„ฐ๋Š” ์ƒˆ๋กœ ์—…๋ฐ์ดํŠธ๋œ ํŽ˜์ด์ง€๋ฅผ ์ œ๊ณตํ•ด์š”.
  • App Router์—์„œ์˜ ๊ตฌํ˜„: fetch ์š”์ฒญ ์‹œ { next: { revalidate: 60 } }์™€ ๊ฐ™์ด revalidate ์˜ต์…˜์— ์‹œ๊ฐ„(์ดˆ ๋‹จ์œ„)์„ ์ง€์ •ํ•˜์—ฌ ์‚ฌ์šฉํ•ด์š”. ์ด ์„ค์ •์€ ํ•ด๋‹น ๋ฐ์ดํ„ฐ๊ฐ€ 60์ดˆ๋งˆ๋‹ค ํ•œ ๋ฒˆ์”ฉ ์žฌ๊ฒ€์ฆ๋˜๋„๋ก ์ง€์‹œํ•ด์š”.
  • ์žฅ์ : SSG์ฒ˜๋Ÿผ ๋น ๋ฅธ ์ดˆ๊ธฐ ๋กœ๋”ฉ ์†๋„๋ฅผ ์ œ๊ณตํ•˜๋ฉด์„œ๋„, ๋ฐ์ดํ„ฐ ์—…๋ฐ์ดํŠธ ์œ ์—ฐ์„ฑ์„ ํ™•๋ณดํ•  ์ˆ˜ ์žˆ์–ด์š”. ๋นŒ๋“œ ์‹œ๊ฐ„์„ ์ ˆ์•ฝํ•  ์ˆ˜ ์žˆ๊ณ ์š”.
  • ๋‹จ์ : ์žฌ๊ฒ€์ฆ ์ฃผ๊ธฐ ๋™์•ˆ์€ ์˜ค๋ž˜๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋…ธ์ถœ๋  ์ˆ˜ ์žˆ์–ด์š”. ์บ์‹ฑ ์ „๋žต์„ ์‹ ์ค‘ํ•˜๊ฒŒ ๊ณ ๋ คํ•ด์•ผ ํ•ด์š”.

๐Ÿงช App Router์—์„œ ๊ฐ ์ „๋žต ์ ์šฉ ๋ฐ ์ตœ์ ํ™” ์˜ˆ์‹œ

์ด์ œ App Router ํ™˜๊ฒฝ์—์„œ ๊ฐ ๋ Œ๋”๋ง ์ „๋žต์„ ์–ด๋–ป๊ฒŒ ์ ์šฉํ•˜๊ณ  ์ตœ์ ํ™”ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๊ตฌ์ฒด์ ์ธ ์ฝ”๋“œ ์˜ˆ์‹œ์™€ ํ•จ๊ป˜ ์‚ดํŽด๋ณผ๊ฒŒ์š”.

0๏ธโƒฃ SSR (Server-Side Rendering) ์˜ˆ์‹œ: ์‹ค์‹œ๊ฐ„ ์ฃผ์‹ ์ •๋ณด ํŽ˜์ด์ง€

์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ณ€ํ•˜๋Š” ์ฃผ์‹ ์ •๋ณด๋‚˜ ์‚ฌ์šฉ์ž ๋กœ๊ทธ์ธ ์ƒํƒœ์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง€๋Š” ๋Œ€์‹œ๋ณด๋“œ์™€ ๊ฐ™์€ ํŽ˜์ด์ง€์— SSR์ด ์ ํ•ฉํ•ด์š”. ๋งค ์š”์ฒญ๋งˆ๋‹ค ์ตœ์‹  ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€์•ผ ํ•˜๋ฏ€๋กœ ์บ์‹œ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋„๋ก ์„ค์ •ํ•ด์š”.

// app/stocks/[symbol]/page.tsx interface StockPageProps { params: { symbol: string }; } async function getStockPrice(symbol: string) { // fetch ์š”์ฒญ ์‹œ ์บ์‹œ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋„๋ก 'no-store' ์˜ต์…˜ ์ง€์ • const res = await fetch(`https://api.example.com/stocks/${symbol}`, { cache: 'no-store', // ์ด ์˜ต์…˜์œผ๋กœ SSR ๋™์ž‘์„ ์œ ๋„ํ•ด์š” }); if (!res.ok) { throw new Error('Failed to fetch stock data'); } return res.json(); } export default async function StockPage({ params }: StockPageProps) { const stock = await getStockPrice(params.symbol); return ( <div> <h1>{stock.name} ({stock.symbol})</h1> <p>ํ˜„์žฌ ๊ฐ€๊ฒฉ: {stock.price}</p> <p>์—…๋ฐ์ดํŠธ ์‹œ๊ฐ„: {new Date().toLocaleTimeString()}</p> </div> ); }
์ •๋ณด

fetch ์š”์ฒญ์— { cache: 'no-store' } ์˜ต์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋Š” ์บ์‹œ๋˜์ง€ ์•Š๊ณ , ๋งค ์š”์ฒญ๋งˆ๋‹ค ์„œ๋ฒ„์—์„œ ์ƒˆ๋กœ ๊ฐ€์ ธ์˜ค๊ฒŒ ๋˜๋ฏ€๋กœ SSR์ฒ˜๋Ÿผ ๋™์ž‘ํ•˜๊ฒŒ ๋ผ์š”. ์ด๋Š” getServerSideProps์™€ ์œ ์‚ฌํ•œ ํšจ๊ณผ๋ฅผ ๋‚ธ๋‹ต๋‹ˆ๋‹ค.

1๏ธโƒฃ SSG (Static Site Generation) ์˜ˆ์‹œ: ๋ธ”๋กœ๊ทธ ํฌ์ŠคํŠธ ๋ชฉ๋ก ๋ฐ ์ƒ์„ธ ํŽ˜์ด์ง€

๋ธ”๋กœ๊ทธ ํฌ์ŠคํŠธ์ฒ˜๋Ÿผ ์ฝ˜ํ…์ธ ์˜ ๋ณ€๊ฒฝ ์ฃผ๊ธฐ๊ฐ€ ๋น„๊ต์  ๊ธธ๊ณ , ๋ชจ๋“  ์‚ฌ์šฉ์ž์—๊ฒŒ ๋™์ผํ•œ ๋‚ด์šฉ์„ ๋ณด์—ฌ์ฃผ๋Š” ํŽ˜์ด์ง€์— SSG๊ฐ€ ์•„์ฃผ ํšจ๊ณผ์ ์ด์—์š”. ๋นŒ๋“œ ์‹œ์ ์— ๋ฏธ๋ฆฌ ๋ชจ๋“  ํŽ˜์ด์ง€๋ฅผ ์ƒ์„ฑํ•ด๋‘๋ฉด ๋งค์šฐ ๋น ๋ฅธ ๋กœ๋”ฉ ์†๋„๋ฅผ ๊ธฐ๋Œ€ํ•  ์ˆ˜ ์žˆ์–ด์š”.

// app/blog/page.tsx (๋ธ”๋กœ๊ทธ ๋ชฉ๋ก ํŽ˜์ด์ง€) async function getBlogPosts() { // revalidate ์˜ต์…˜์ด ์—†์œผ๋ฉด ๊ธฐ๋ณธ์ ์œผ๋กœ SSG์ฒ˜๋Ÿผ ๋™์ž‘ํ•ด์š” (๋นŒ๋“œ ์‹œ fetch) const res = await fetch('https://api.example.com/blog/posts'); if (!res.ok) { throw new Error('Failed to fetch posts'); } return res.json(); } export default async function BlogListPage() { const posts = await getBlogPosts(); return ( <div> <h1>๋ธ”๋กœ๊ทธ ํฌ์ŠคํŠธ</h1> <ul> {posts.map((post: any) => ( <li key={post.id}> <a href={`/blog/${post.slug}`}>{post.title}</a> </li> ))} </ul> </div> ); }
// app/blog/[slug]/page.tsx (๋ธ”๋กœ๊ทธ ์ƒ์„ธ ํŽ˜์ด์ง€) interface BlogPostPageProps { params: { slug: string }; } // ๋นŒ๋“œ ์‹œ์ ์— ์ƒ์„ฑํ•  ๋ชจ๋“  slug ๋ชฉ๋ก์„ ์ •์˜ํ•ด์š” export async function generateStaticParams() { const res = await fetch('https://api.example.com/blog/slugs'); const slugs = await res.json(); return slugs.map((slug: string) => ({ slug: slug })); } async function getBlogPost(slug: string) { // revalidate ์˜ต์…˜์ด ์—†์œผ๋ฉด ๊ธฐ๋ณธ์ ์œผ๋กœ SSG์ฒ˜๋Ÿผ ๋™์ž‘ํ•ด์š” const res = await fetch(`https://api.example.com/blog/posts/${slug}`); if (!res.ok) { throw new Error('Failed to fetch post'); } return res.json(); } export default async function BlogPostPage({ params }: BlogPostPageProps) { const post = await getBlogPost(params.slug); return ( <div> <h1>{post.title}</h1> <p>{post.content}</p> </div> ); }
์œ ์šฉํ•œ ํŒ

generateStaticParams๋Š” ๋™์  ๊ฒฝ๋กœ๋ฅผ SSG ๋ฐฉ์‹์œผ๋กœ ๋ฏธ๋ฆฌ ์ƒ์„ฑํ•  ๋•Œ ์‚ฌ์šฉํ•ด์š”. ์ด ํ•จ์ˆ˜๊ฐ€ ์ •์˜๋˜๋ฉด Next.js๋Š” ๋นŒ๋“œ ์‹œ์ ์— ๋ฐ˜ํ™˜๋œ params ๊ฐ’๋“ค์„ ๊ฐ€์ง€๊ณ  ํ•ด๋‹น ๊ฒฝ๋กœ์˜ ํŽ˜์ด์ง€๋“ค์„ ๋ชจ๋‘ ์ƒ์„ฑํ•œ๋‹ต๋‹ˆ๋‹ค. ๋งŒ์•ฝ generateStaticParams๊ฐ€ ์—†๋Š” ๋™์  ๊ฒฝ๋กœ๋ผ๋ฉด, ๊ธฐ๋ณธ์ ์œผ๋กœ SSR์ฒ˜๋Ÿผ ๋™์ž‘ํ•˜๊ฑฐ๋‚˜ notFound()๋กœ ์ฒ˜๋ฆฌ๋  ์ˆ˜ ์žˆ์–ด์š”.

2๏ธโƒฃ ISR (Incremental Static Regeneration) ์˜ˆ์‹œ: ์ œํ’ˆ ๋ฆฌ๋ทฐ ๋ชฉ๋ก ํŽ˜์ด์ง€

์ œํ’ˆ ๋ฆฌ๋ทฐ ๋ชฉ๋ก์ฒ˜๋Ÿผ ๋ฐ์ดํ„ฐ๊ฐ€ ์ฃผ๊ธฐ์ ์œผ๋กœ ์—…๋ฐ์ดํŠธ๋˜์ง€๋งŒ, ๋งค ์š”์ฒญ๋งˆ๋‹ค ์ตœ์‹ ์ผ ํ•„์š”๋Š” ์—†๋Š” ๊ฒฝ์šฐ ISR์ด ๋งค์šฐ ํšจ์œจ์ ์ด์—์š”. ์ผ์ • ์‹œ๊ฐ„๋งˆ๋‹ค ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐฑ์‹ ํ•˜์—ฌ ํŽ˜์ด์ง€๋ฅผ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ์–ด์š”.

// app/products/[id]/reviews/page.tsx interface ProductReviewsPageProps { params: { id: string }; } async function getProductReviews(productId: string) { // 60์ดˆ๋งˆ๋‹ค ๋ฐ์ดํ„ฐ๋ฅผ ์žฌ๊ฒ€์ฆํ•˜๋„๋ก revalidate ์˜ต์…˜ ์ง€์ • const res = await fetch(`https://api.example.com/products/${productId}/reviews`, { next: { revalidate: 60 }, // 60์ดˆ๋งˆ๋‹ค ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ๋ฐ์ดํ„ฐ ๊ฐฑ์‹ ์„ ์‹œ๋„ํ•ด์š” }); if (!res.ok) { throw new Error('Failed to fetch reviews'); } return res.json(); } export default async function ProductReviewsPage({ params }: ProductReviewsPageProps) { const reviews = await getProductReviews(params.id); return ( <div> <h1>์ œํ’ˆ ๋ฆฌ๋ทฐ ({params.id})</h1> <ul> {reviews.map((review: any) => ( <li key={review.id}> <strong>{review.author}</strong>: {review.comment} </li> ))} </ul> </div> ); }
๊ฒฝ๊ณ 

ISR์€ ์ฒซ ์š”์ฒญ ์‹œ ์บ์‹œ๋œ(์˜ค๋ž˜๋œ) ํŽ˜์ด์ง€๋ฅผ ๋ณด์—ฌ์ฃผ๊ณ , ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ์ƒˆ ํŽ˜์ด์ง€๋ฅผ ์ƒ์„ฑํ•ด์š”. ๋”ฐ๋ผ์„œ revalidate ์ฃผ๊ธฐ๊ฐ€ ์งง์•„๋„ ์•„์ฃผ ์งง์€ ์‹œ๊ฐ„ ๋™์•ˆ์€ ์ด์ „ ๋ฐ์ดํ„ฐ๊ฐ€ ๋…ธ์ถœ๋  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์„ ์ธ์ง€ํ•˜๊ณ  ์žˆ์–ด์•ผ ํ•ด์š”. ์‹ค์‹œ๊ฐ„์„ฑ์ด ๋งค์šฐ ์ค‘์š”ํ•œ ๋ฐ์ดํ„ฐ์—๋Š” SSR์ด ๋” ์ ํ•ฉํ•  ์ˆ˜ ์žˆ๋‹ต๋‹ˆ๋‹ค.

3๏ธโƒฃ ๋ Œ๋”๋ง ์ „๋žต ์„ ํƒ ๊ฐ€์ด๋“œ๋ผ์ธ

ํ”„๋กœ์ ํŠธ์˜ ์š”๊ตฌ์‚ฌํ•ญ์— ๋”ฐ๋ผ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๋ Œ๋”๋ง ์ „๋žต์„ ์„ ํƒํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ด์š”. ๋‹ค์Œ ์งˆ๋ฌธ๋“ค์„ ํ†ตํ•ด ์–ด๋–ค ์ „๋žต์ด ์—ฌ๋Ÿฌ๋ถ„์˜ ์ƒํ™ฉ์— ๋งž๋Š”์ง€ ํŒ๋‹จํ•ด ๋ณด์„ธ์š”.

  • ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ ๋นˆ๋„:
    • ๊ฑฐ์˜ ๋ณ€๊ฒฝ ์—†์Œ: SSG (๋ธ”๋กœ๊ทธ, ์•ฝ๊ด€ ํŽ˜์ด์ง€)
    • ์ฃผ๊ธฐ์ ์œผ๋กœ ๋ณ€๊ฒฝ๋˜์ง€๋งŒ ์‹ค์‹œ๊ฐ„์€ ์•„๋‹˜: ISR (์ œํ’ˆ ๋ชฉ๋ก, ๋‰ด์Šค ๊ธฐ์‚ฌ)
    • ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ณ€๊ฒฝ๋˜์–ด์•ผ ํ•จ: SSR (์ฃผ์‹ ์ฐจํŠธ, ์‚ฌ์šฉ์ž ๋Œ€์‹œ๋ณด๋“œ)
  • ์‚ฌ์šฉ์ž ๊ฒฝํ—˜ (UX):
    • ๊ฐ€์žฅ ๋น ๋ฅธ ์ดˆ๊ธฐ ๋กœ๋”ฉ์ด ์ค‘์š”: SSG/ISR
    • ํ•ญ์ƒ ์ตœ์‹  ์ •๋ณด๊ฐ€ ์ค‘์š”: SSR
  • SEO ์š”๊ตฌ์‚ฌํ•ญ:
    • ๊ฒ€์ƒ‰ ์—”์ง„ ํฌ๋กค๋Ÿฌ๊ฐ€ ์ตœ์‹  ์ •๋ณด๋ฅผ ํ•„์š”๋กœ ํ•จ: SSR
    • ์ •์  ์ฝ˜ํ…์ธ ๋กœ๋„ ์ถฉ๋ถ„ํžˆ ํฌ๋กค๋ง ๊ฐ€๋Šฅ: SSG/ISR
  • ์„œ๋ฒ„ ๋ฆฌ์†Œ์Šค:
    • ์„œ๋ฒ„ ๋ถ€ํ•˜๋ฅผ ์ตœ์†Œํ™”ํ•ด์•ผ ํ•จ: SSG/ISR (CDN ํ™œ์šฉ)
    • ์„œ๋ฒ„ ๋ฆฌ์†Œ์Šค ์‚ฌ์šฉ์— ์—ฌ์œ ๊ฐ€ ์žˆ์Œ: SSR

๋Œ€๋ถ€๋ถ„์˜ ๋ณต์žกํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ๋Š” ๋‹จ์ผ ์ „๋žต๋งŒ์„ ์‚ฌ์šฉํ•˜๊ธฐ๋ณด๋‹ค๋Š”, ๊ฐ ํŽ˜์ด์ง€๋‚˜ ๋ฐ์ดํ„ฐ์˜ ํŠน์„ฑ์— ๋งž์ถฐ ์—ฌ๋Ÿฌ ๋ Œ๋”๋ง ์ „๋žต์„ ํ˜ผํ•ฉํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ผ๋ฐ˜์ ์ด์—์š”. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋ฉ”์ธ ํŽ˜์ด์ง€๋‚˜ ๋งˆ์ผ€ํŒ… ํŽ˜์ด์ง€๋Š” ISR๋กœ ๋น ๋ฅด๊ฒŒ ์ œ๊ณตํ•˜๊ณ , ์‚ฌ์šฉ์ž๋ณ„ ๋งž์ถค ์ •๋ณด๊ฐ€ ํ•„์š”ํ•œ ๋Œ€์‹œ๋ณด๋“œ๋Š” SSR๋กœ ๊ตฌํ˜„ํ•˜๋Š” ์‹์ด์ฃ .

๐Ÿ“ ์ •๋ฆฌ

์˜ค๋Š˜์€ Next.js App Router ํ™˜๊ฒฝ์—์„œ SSR, SSG, ISR ์„ธ ๊ฐ€์ง€ ์ฃผ์š” ๋ Œ๋”๋ง ์ „๋žต์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„๋ณด์•˜์–ด์š”. ๊ฐ ์ „๋žต์ด ์–ด๋–ค ์›๋ฆฌ๋กœ ๋™์ž‘ํ•˜๊ณ , ์–ด๋–ค ์ƒํ™ฉ์— ์ ํ•ฉํ•˜๋ฉฐ, ์–ด๋–ป๊ฒŒ ์ฝ”๋“œ๋กœ ๊ตฌํ˜„ํ•˜๋Š”์ง€ ์ดํ•ดํ•˜๋Š” ์‹œ๊ฐ„์ด ๋˜์…จ๊ธฐ๋ฅผ ๋ฐ”๋ผ์š”.

  • SSR (Server-Side Rendering): ๋งค ์š”์ฒญ๋งˆ๋‹ค ์„œ๋ฒ„์—์„œ ์ตœ์‹  HTML์„ ์ƒ์„ฑํ•ด์š”. ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ์™€ ๊ฐœ์ธํ™”๋œ ์ฝ˜ํ…์ธ ์— ์œ ๋ฆฌํ•˜์ง€๋งŒ, ์„œ๋ฒ„ ๋ถ€ํ•˜์™€ TTFB๊ฐ€ ์ฆ๊ฐ€ํ•  ์ˆ˜ ์žˆ์–ด์š”.
  • SSG (Static Site Generation): ๋นŒ๋“œ ์‹œ์ ์— ๋ชจ๋“  ํŽ˜์ด์ง€๋ฅผ ๋ฏธ๋ฆฌ ์ƒ์„ฑํ•ด์š”. ๋งค์šฐ ๋น ๋ฅธ ๋กœ๋”ฉ๊ณผ CDN ํ™œ์šฉ์ด ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ๋ฐ์ดํ„ฐ ์—…๋ฐ์ดํŠธ๋ฅผ ์œ„ํ•ด ์žฌ๋นŒ๋“œ๊ฐ€ ํ•„์š”ํ•ด์š”.
  • ISR (Incremental Static Regeneration): SSG์˜ ์žฅ์ ์„ ๊ฐ€์ ธ๊ฐ€๋ฉด์„œ๋„, ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ์ฃผ๊ธฐ์ ์œผ๋กœ ํŽ˜์ด์ง€๋ฅผ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ์–ด์š”. ์œ ์—ฐํ•œ ๋ฐ์ดํ„ฐ ๊ฐฑ์‹ ์ด ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ์ผ์ • ์‹œ๊ฐ„ ๋™์•ˆ์€ ์˜ค๋ž˜๋œ ๋ฐ์ดํ„ฐ๊ฐ€ ๋…ธ์ถœ๋  ์ˆ˜ ์žˆ๋‹ต๋‹ˆ๋‹ค.

Next.js์˜ ๊ฐ•๋ ฅํ•จ์€ ์ด๋Ÿฌํ•œ ๋‹ค์–‘ํ•œ ๋ Œ๋”๋ง ์˜ต์…˜์„ ์ œ๊ณตํ•˜์—ฌ ๊ฐœ๋ฐœ์ž๊ฐ€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์„ฑ๋Šฅ๊ณผ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ์ตœ์ ํ™”ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋•๋Š” ๋ฐ ์žˆ์–ด์š”. ์—ฌ๋Ÿฌ๋ถ„์˜ ํ”„๋กœ์ ํŠธ ํŠน์„ฑ๊ณผ ์š”๊ตฌ์‚ฌํ•ญ์— ๋งž์ถฐ ํ˜„๋ช…ํ•œ ๋ Œ๋”๋ง ์ „๋žต์„ ์„ ํƒํ•˜๊ณ , ์บ์‹ฑ ์ „๋žต๊ณผ ํ•จ๊ป˜ ์ž˜ ํ™œ์šฉํ•˜์—ฌ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ตœ๊ณ ์˜ ๊ฒฝํ—˜์„ ์ œ๊ณตํ•ด ์ฃผ์‹œ๊ธธ ๋ฐ”๋ผ์š”!

๐Ÿ“ฎ ์ฐธ๊ณ 

์—ฐ๊ด€๋œ ํฌ์ŠคํŠธ