필사 모드: Astro 5 심층 해부: Server Islands · Content Layer · View Transitions로 다시 그리는 '콘텐츠 사이트의 표준'
한국어> "정적이라는 단어를 다시 정의하자. 캐시할 수 있는 모든 것은 캐시하고, 진짜로 사람마다 달라야 하는 부분만 서버에서 늦게 그린다."
> — Astro 5 Server Islands의 디자인 한 줄 요약
프롤로그 — '단순한 정적 사이트 생성기'의 시대는 끝났다
2022년의 Astro는 마크다운 블로그용 정적 사이트 생성기였습니다. 2024년 12월 3일에 공개된 Astro 5는, 같은 이름을 달고 있지만 다른 물건입니다. **콘텐츠 중심 사이트의 사실상 표준** 이라고 불러도 과하지 않습니다.
이번 글에서 답하고 싶은 질문은 단순합니다.
- Astro 5는 정확히 무엇이 바뀌었는가
- Server Islands와 Content Layer는 어떤 문제를 푸는가
- 같은 카드에서 싸우는 Next.js의 RSC · Server Actions, SvelteKit과 비교하면 무엇이 다른가
- 콘텐츠 사이트, 마케팅 사이트, 문서, 커머스 스토어프런트 — 어디서 Astro가 이기고, 어디서 지는가
- Astro 4에서 5로 어떻게 옮겨가는가
이 글은 광고가 아닙니다. Astro가 잘하는 일과 못하는 일을 같은 무게로 적습니다. 결정은 마지막 표 한 장에서 하시면 됩니다.
1. 아일랜드 아키텍처 복습 — Astro가 처음부터 다르게 했던 한 가지
먼저 짧게 복습합니다. 다른 프레임워크가 SPA에서 SSR로 갔다가 다시 RSC로 우회하는 동안, Astro는 처음부터 다른 길을 갔습니다.
1.1 "모든 페이지는 HTML이다"
기본 출력물은 **HTML**입니다. JavaScript는 필요한 컴포넌트에만 명시적으로 붙입니다. 이 정책의 이름이 바로 **아일랜드 아키텍처(Islands Architecture)** 입니다.
페이지 전체가 하나의 React 트리가 아니라, 정적인 HTML 바다 위에 인터랙티브한 "섬"이 듬성듬성 떠 있는 그림입니다. 섬마다 자기 번들과 자기 하이드레이션 시점을 가집니다. 그 결과 평균적인 콘텐츠 페이지에서 클라이언트로 내려가는 JS가 압도적으로 적습니다.
1.2 클라이언트 디렉티브
섬을 만드는 방법은 컴포넌트 옆에 디렉티브 한 줄을 붙이는 것입니다.
- `client:load` — 페이지 로드 시 즉시 하이드레이트
- `client:idle` — 브라우저가 한가할 때
- `client:visible` — 뷰포트에 들어올 때
- `client:media="(max-width: 600px)"` — 미디어 쿼리 충족 시
- `client:only="react"` — 서버에서 렌더하지 않고 클라이언트에서만
이 한 줄의 차이로 "이 페이지의 4킬로바이트 JS"와 "이 페이지의 300킬로바이트 JS"가 갈립니다.
1.3 프레임워크 어그노스틱
같은 페이지 안에 React, Svelte, Vue, Solid, Preact, Lit을 섞을 수 있습니다. 실무에서 이걸 적극적으로 활용하는 팀은 드물지만, **레거시 위젯을 점진적으로 흡수**할 수 있다는 의미는 큽니다. 디자인 시스템은 Svelte, 인터랙티브 데모는 React 같은 분할이 자연스럽습니다.
2. Astro 5가 가져온 큰 그림 — 6가지 헤드라인 변화
Astro 5의 핵심을 한 화면에 담으면 다음과 같습니다.
| 영역 | Astro 4 | Astro 5 |
|---|---|---|
| 콘텐츠 모델 | Content Collections (파일 기반) | **Content Layer API** (어떤 소스든) |
| 동적 페이지 | 전체 페이지 SSR 또는 정적 | **Server Islands** (정적 위에 서버 섬) |
| 번들러 | Vite 5 | **Vite 6**, 이후 6.x 라인에서 Vite 7 합류 |
| 폼/뮤테이션 | 직접 핸들러 | **Astro Actions** (타입 안전) |
| 라우팅 | 정적 + 부분 SSR | `prerender` per-route 정교화 |
| i18n | 실험적 | **안정화 + fallback/도메인 라우팅** |
이걸 한 줄로 줄이면 — **"정적 우선을 유지한 채로, 풀스택의 일부를 받아들였다"** 입니다. Next.js와 반대 방향에서 같은 지점에 도달하는 중입니다. Next.js는 클라이언트 React에서 출발해 RSC로 정적/서버 경계를 다시 그렸고, Astro는 정적 HTML에서 출발해 Server Islands로 서버를 다시 받아들였습니다.
3. Server Islands — '정적 우선'을 깨지 않고 개인화를 끼워 넣는 법
Server Islands는 Astro 5의 얼굴입니다. 한 문장으로:
> "페이지를 CDN에서 정적으로 캐시하고, 사람마다 달라야 하는 작은 조각만 서버에서 늦게 그려서 클라이언트가 뒤따라 끼워 넣는다."
3.1 문제 — "캐시할 수 있는 99%와 캐시할 수 없는 1%"
전형적인 콘텐츠 사이트의 페이지를 떠올려 보세요. 헤더, 본문, 사이드바, 푸터 — 거의 모든 픽셀이 모든 방문자에게 동일합니다. 다만 우측 상단의 "로그인됨/안 됨", "장바구니 (3)", "내 추천 글" 같은 작은 조각이 사람마다 다릅니다.
전통적 선택지:
1. **전체 페이지 SSR** — 1%를 위해 99%를 매번 다시 그린다. 캐시가 무용지물.
2. **전체 정적 + 클라이언트 fetch** — JS 로드 → fetch → 렌더링 → 레이아웃 시프트. 코어 웹 바이탈 손상.
3. **ESI / Edge Side Includes** — 이론적으론 좋지만 CDN 의존, 디버깅 지옥.
Server Islands는 4번째 길입니다.
3.2 사용법 — `server:defer` 한 줄
// src/pages/index.astro
// src/components/Avatar.astro
const user = await getUserFromCookie(Astro.request)
{user ? (
) : (
)}
`server:defer`가 붙은 컴포넌트는:
1. 빌드 타임에는 **렌더되지 않습니다.** 대신 `slot="fallback"`이 자리를 차지합니다.
2. 페이지는 정적 HTML로 CDN에 캐시됩니다. 0.5kB 안팎의 스크립트와 placeholder만 들어 있습니다.
3. 브라우저는 그 자리에 들어갈 HTML을 별도 엔드포인트(`/_server-islands/Avatar`)에서 가져옵니다.
4. 응답이 도착하면 placeholder가 실제 HTML로 교체됩니다.
핵심은 — **본문은 캐시되고, 섬만 사람마다 다르다**는 점입니다. CDN을 100% 활용하면서 개인화가 됩니다.
3.3 GA에서 추가된 디테일
베타 동안 다음이 더해지면서 5.0 GA에 올라왔습니다.
- **헤더 설정** — Server Island 응답에 `Cache-Control`, `Set-Cookie` 같은 헤더를 따로 붙일 수 있음
- **자동 압축 플랫폼 호환** — 기본 압축을 강제하는 호스팅에서도 작동
- **Props 자동 암호화** — Server Island에 넘긴 props는 자동으로 암호화돼서, URL이나 placeholder를 통해 클라이언트가 들여다볼 수 없음. 권한 정보 같은 걸 넣어도 안전
3.4 언제 쓰고, 언제 쓰지 말아야 하는가
**쓸 때:**
- 99/1 페이지 — 본문은 모두에게 같고, 헤더의 사용자 상태/장바구니 같은 작은 조각만 다름
- 위젯 단위 개인화 — "방금 본 글", "추천 상품 3개"
- 로그인 여부에 따른 작은 UI 차이
**쓰지 말아야 할 때:**
- 페이지 전체가 사용자마다 다른 경우 (대시보드, 메일함, 콘솔) — 그냥 SSR 또는 SPA
- LCP 위의 위 (above-the-fold) 핵심 콘텐츠 — 늦게 채워지면 사용자 인식에 직격타
- 외부 API에 동기적으로 의존하는데 그 API가 느린 경우 — 차라리 클라이언트 페치가 나음
4. Content Layer API — '콘텐츠 컬렉션'을 '어떤 소스든' 으로 일반화
두 번째 큰 변화는 Content Layer입니다. Astro 4의 Content Collections는 **파일 시스템의 마크다운/MDX** 가 1급 시민이었습니다. Astro 5는 그것을 한 단계 추상화해서, **로더가 곧 컬렉션**이 되도록 만들었습니다.
4.1 모델 — Loader + Schema
// src/content.config.ts
const blog = defineCollection({
loader: glob({ pattern: '**/*.md', base: './src/content/blog' }),
schema: z.object({
title: z.string(),
pubDate: z.coerce.date(),
tags: z.array(z.string()).default([]),
draft: z.boolean().default(false),
}),
})
export const collections = { blog }
- `loader` — 데이터를 어디서 가져올지
- `schema` — Zod로 타입과 검증을 동시에
`glob` 외에 공식 `file` 로더가 있고, 그 너머는 자유입니다.
4.2 커스텀 로더 — HTTP, DB, CMS 모두
가장 흥미로운 부분입니다. 임의의 데이터 소스를 컬렉션으로 만들 수 있습니다.
// src/loaders/notion.ts
export function notionLoader(opts: { databaseId: string }): Loader {
return {
name: 'notion-loader',
async load({ store, parseData, meta, generateDigest }: LoaderContext) {
const lastSynced = meta.get('last-synced')
const pages = await fetchNotionPages(opts.databaseId, { since: lastSynced })
for (const p of pages) {
const data = await parseData({
id: p.id,
data: {
title: p.properties.Title.title[0].plain_text,
slug: p.properties.Slug.rich_text[0].plain_text,
body: p.body,
updatedAt: p.last_edited_time,
},
})
const digest = generateDigest(data)
store.set({ id: p.id, data, digest })
}
meta.set('last-synced', new Date().toISOString())
},
}
}
// src/content.config.ts
const articles = defineCollection({
loader: notionLoader({ databaseId: process.env.NOTION_DB_ID! }),
schema: z.object({
title: z.string(),
slug: z.string(),
body: z.string(),
updatedAt: z.coerce.date(),
}),
})
export const collections = { articles }
이제 페이지에서는 똑같이 씁니다.
const articles = await getCollection('articles')
{articles.map(a => <li><a href={`/articles/${a.data.slug}`}>{a.data.title}</a></li>)}
데이터가 마크다운 파일이든, Notion이든, Sanity든, 자체 PostgreSQL이든 — 페이지 코드는 모릅니다. 이게 Content Layer의 본질입니다.
4.3 빌드 캐시와 인크리멘털
Content Layer는 SQLite 기반 캐시를 깔고 있어, 변경된 엔트리만 다시 처리합니다. 1만 개 콘텐츠 사이트의 두 번째 빌드가 첫 빌드보다 압도적으로 빠른 이유입니다. 로더는 `meta.get/set`으로 자기 마지막 동기화 시점을 기억할 수 있고, `generateDigest`로 콘텐츠 해시를 만들어 변경 여부를 판단합니다.
4.4 외부 로더 생태계
5.0 발표 이후 단기간에 공식·서드파티 로더가 우르르 등장했습니다 — Storyblok, Hygraph, WordPress, Ghost, Strapi, Sanity 등. 즉 "Astro = 헤드리스 CMS의 보편적 프런트엔드" 라는 포지셔닝이 실제로 작동하기 시작했습니다.
4.5 Live Loaders — 런타임 콘텐츠
GA 이후 추가된 흐름이 **Live Content Loaders** 입니다. 빌드 타임이 아니라 요청 시점에 데이터를 가져오는 로더로, "정적 80% + 라이브 20%" 시나리오(가격, 재고, 환율)에 적합합니다. 같은 `getCollection` API를 유지하면서 라이브로 갈 수 있다는 점이 인상적입니다.
5. Astro Actions — 폼과 뮤테이션을 타입 안전하게
세 번째 큰 변화는 Astro Actions입니다. 한마디로 "타입 안전한 서버 함수, Zod 입력 스키마와 함께".
5.1 정의
// src/actions/index.ts
export const server = {
subscribe: defineAction({
accept: 'form',
input: z.object({
email: z.string().email(),
utm: z.string().optional(),
}),
handler: async (input, ctx) => {
const ip = ctx.request.headers.get('x-forwarded-for')
await saveSubscriber({ email: input.email, utm: input.utm, ip })
return { ok: true }
},
}),
}
5.2 호출 — 서버에서 그대로
const result = Astro.getActionResult(actions.subscribe)
{result?.data?.ok && <p>고맙습니다!</p>}
{result?.error && <p class="err">에러: 다시 시도해 주세요.</p>}
JS가 꺼져 있어도 폼은 작동합니다. JS가 켜져 있으면 점진적으로 강화된 UX가 됩니다. 클라이언트 JS에서도 `actions.subscribe(input)` 으로 호출 가능합니다.
5.3 무엇이 좋은가
- **입력 검증과 타입이 단일 소스** — Zod 스키마 하나로 런타임 검증, TS 타입, 자동완성이 동시에 됩니다
- **점진적 강화 친화** — 일반 HTML 폼으로도 작동
- **Server Islands와 잘 어울림** — 액션이 끝난 뒤 페이지 일부를 무효화/재렌더 가능
Next.js의 Server Actions와 컨셉상 형제지만, Astro는 "정적 페이지 위에 폼 한 개"라는 경량 시나리오에 더 가볍게 맞습니다.
6. Vite 6 / Vite 7 통합 — 빌드의 속살
Astro 5는 Vite 6 위에서 출시됐고, 이후 5.x/6.x 라인에서 Vite 7 합류 작업이 진행됐습니다. 개발자 입장에서 느끼는 변화:
- **Environment API** — 같은 빌드 그래프 안에서 클라이언트/서버/엣지 같은 다중 환경을 일관되게 다룸. Server Islands를 비롯해 서버 코드 분리가 더 깔끔
- **빠른 콜드 스타트** — 큰 사이트의 첫 `astro dev`가 체감상 더 가벼움
- **CSS 변경 감지** — HMR이 더 정확. CSS 한 글자 바꿔도 풀 리로드 안 함
- **롤업 4.x / 5.x** 라인 활용
여기서 중요한 시사점은 — **Astro 팀이 Vite 코어 개발자와 거의 한 팀처럼 움직인다**는 점입니다. Vite의 변화가 Astro에 빠르게 흘러들어옵니다.
7. View Transitions와 prefetching — SPA처럼 매끄럽게, MPA처럼 가볍게
콘텐츠 사이트의 약점 중 하나는 페이지 이동마다 흰 화면이 깜빡인다는 점이었습니다. View Transitions API와 핵심 prefetching이 이걸 풀어냅니다.
7.1 View Transitions
이 한 줄을 레이아웃에 넣으면, 같은 사이트 안 내비게이션이 **MPA 그대로** 동작하면서 화면 전환에 브라우저 네이티브 View Transitions가 입혀집니다. 헤더는 유지되고 본문만 페이드되거나, 썸네일이 다음 페이지의 히어로 이미지로 자연스럽게 모핑되는 식입니다.
요소별로 이름을 주면 페이지 간 동일 요소가 트래킹됩니다.
7.2 prefetching — 코어로 흡수
prefetch는 Astro 3.5에서 코어로 들어왔고, 5에서는 기본 ON이 좀 더 합리적인 휴리스틱으로 다듬어졌습니다.
// astro.config.mjs
export default defineConfig({
prefetch: {
prefetchAll: true,
defaultStrategy: 'viewport',
},
})
전략은 `tap`, `hover`, `viewport`, `load`. 링크별로 `data-astro-prefetch="hover"` 같이 오버라이드 가능. 결과는 — **사용자가 클릭하기 전에 다음 페이지가 이미 와 있다**.
7.3 i18n 개선
i18n은 4.x에서 안정화에 들어갔고 5.x에서 다듬어졌습니다.
- 기본 로캘과 로캘 목록을 한 번에 선언
- URL 전략 — prefix-other-locales(기본 로캘만 prefix 없음), prefix-always, 도메인 기반
- `getRelativeLocaleUrl`, `getAbsoluteLocaleUrl` 같은 헬퍼
- 누락된 페이지 fallback — 일본어 페이지가 없으면 영어로 대체
콘텐츠 사이트는 거의 모두 다국어를 결국 만나기 때문에, 이 부분이 1급으로 들어왔다는 것이 큰 의미입니다.
8. Astro vs Next.js vs SvelteKit — 결정 매트릭스
이제 본론입니다. 어디서 무엇을 쓸지.
8.1 철학 한 줄
- **Astro 5** — 정적 우선. 필요한 부분만 서버/클라이언트 섬으로.
- **Next.js (App Router + RSC)** — 서버 우선. 정적은 캐시의 한 형태.
- **SvelteKit** — 라우터 우선. 컴파일러로 런타임을 줄이는 통합 풀스택.
8.2 항목별 비교
| 항목 | Astro 5 | Next.js (RSC) | SvelteKit |
|---|---|---|---|
| 기본 JS 페이로드 | 가장 적음 (0이 기본) | 중간~높음 | 적음 |
| 풀스택 깊이 | 얕음~중간 | 깊음 | 중간 |
| 콘텐츠 모델 | Content Layer (1급) | App Router + MDX (애드온) | 직접 구성 |
| 폼/뮤테이션 | Actions | Server Actions | form actions |
| 동적 개인화 | Server Islands | RSC + Suspense | streaming + load |
| 다국어 | 코어 i18n | 별도 라이브러리 | 별도 라이브러리 |
| 호스팅 | Static + 어디든 어댑터 | Vercel 최적 | 어댑터 다양 |
| 학습 곡선 | 낮음 | 중간~높음 | 낮음~중간 |
| 컴포넌트 호환성 | React/Svelte/Vue/Solid 등 | React 전용 | Svelte 전용 |
8.3 시나리오별 추천
- **블로그, 문서, 마케팅 사이트, 미디어**: **Astro 5**. Server Islands로 헤더 개인화 정도는 자연스럽게 처리됨. 코어 웹 바이탈에서 거의 이길 곳이 없음
- **e커머스 스토어프런트 (헤드리스 CMS + 결제)**: **Astro 5** 우세. 상품 페이지 정적, 장바구니/추천만 Server Island. 단, 체크아웃 깊이 들어가면 다른 프레임워크가 나을 수 있음
- **풀스택 SaaS, 대시보드**: **Next.js**. 인증, 권한, 실시간, 복잡한 폼, 깊은 라우팅 트리는 RSC가 더 자연스러움
- **소셜/실시간 앱**: **Next.js** 또는 **SvelteKit**. Astro의 영역 아님
- **앱스러운 SPA + 약간의 서버**: **SvelteKit**. 코드 양이 가장 적게 나옴
- **다국어 콘텐츠 허브, 매우 큰 사이트**: **Astro 5**. Content Layer + i18n이 이 시나리오를 위해 만들어진 것 같음
한 줄로 — **콘텐츠가 1순위면 Astro, 애플리케이션이 1순위면 Next.js/SvelteKit**.
9. 실제 적용 사례 — 콘텐츠 헤비 사이트에서의 모양
가상의 미디어 회사를 가정합니다. 월 1억 PV의 뉴스 사이트. 페이지 구성을 Astro 5 기준으로 어떻게 짤지 살펴봅니다.
9.1 페이지 단위 결정
- **`/` 홈** — 정적 빌드, Server Island로 "로그인 헤더"와 "추천 섹션"만
- **`/articles/[slug]`** — 정적 빌드 (Content Layer가 CMS에서 가져옴), Server Island로 "헤더 + 댓글 수 + 좋아요 상태"
- **`/search`** — SSR (검색 쿼리가 캐시 키를 망가뜨림)
- **`/me`, `/me/bookmarks`** — SSR 또는 클라이언트 페치
- **`/auth/*`** — SSR + Actions
CDN 캐시 적중률이 95% 이상이 됩니다. 99/1 페이지에 99/1의 비용 구조가 따라옵니다.
9.2 데이터 흐름
- **CMS (예: Sanity, Storyblok)** — Content Layer 로더로 빌드 타임 동기화. 변경된 글만 재빌드(인크리멘털).
- **사용자/세션** — Server Island가 쿠키로 직접 읽음. 본문 캐시와 무관.
- **추천 알고리즘** — Server Island가 요청 시점에 추천 API 호출.
- **댓글** — Live Loader 또는 클라이언트 컴포넌트.
9.3 빌드 시간
- 1만 글 콜드 빌드: 수 분
- 1만 글 + 100개 변경 인크리멘털 빌드: 수십 초
- 캐시는 SQLite로 저장돼 CI 캐시에 그대로 올림
같은 규모의 Next.js 정적 빌드보다 빠를 가능성이 높습니다. 단, Next.js의 ISR(Incremental Static Regeneration) + 온디맨드 재검증 모델은 또 다른 매력이 있어, 절대 우위는 아닙니다.
10. Astro 4 → 5 마이그레이션 — 솔직한 이야기
가장 현실적인 질문 — 4에서 5로 옮기는 게 얼마나 아픈가.
10.1 좋은 소식
- 페이지/컴포넌트 문법은 그대로
- 라우팅 그대로
- 통합(Integrations) 대부분 그대로
10.2 손이 가는 부분
1. **Content Collections → Content Layer**
- `src/content/config.ts`에 `loader: glob({...})` 추가
- `getEntry`/`getCollection`의 일부 시그니처 변경
- 빌드 타임 캐시가 새로 생기므로 `.astro/` 같은 캐시 디렉터리 CI에 마운트
2. **`Astro.glob` 제거**
- 위 Content Layer로 흡수됨. 마크다운 페이지 수집을 직접 하던 코드가 있다면 `getCollection`으로 옮김
3. **Image 처리 정책 변화**
- `astro:assets`의 옵션 일부 정리. 외부 이미지 도메인 화이트리스트는 더 엄격해짐
4. **Adapter 업데이트**
- Vercel, Netlify, Cloudflare, Node 어댑터 모두 5.x 버전 필요
5. **Vite 6 환경 호환**
- 커스텀 Vite 플러그인을 끼고 있다면 5/6 호환성 확인
10.3 마이그레이션 절차
1. Astro 4 최신 패치로 올린 뒤 deprecation 경고를 0으로
2. `pnpm dlx @astrojs/upgrade`로 일괄 메이저 점프
3. `astro check` 통과시키기
4. 한 페이지에 Server Island 시험 도입
5. 한 컬렉션부터 Content Layer로 이주
6. 점진 확장
큰 사이트라도 보통 며칠 단위로 끝납니다. Next.js의 Pages → App Router 마이그레이션보다 훨씬 가볍습니다.
11. 솔직한 한계 — Astro가 여전히 지지 않는 곳, 지는 곳
광고를 빼고 적습니다.
11.1 여전히 강한 곳
- 콘텐츠 사이트 / 문서 / 마케팅 페이지에서 코어 웹 바이탈은 거의 무패
- 헤드리스 CMS 통합이 가장 자연스러움 (Content Layer 효과)
- 다국어 사이트의 1급 지원
- 빌드 시간 (인크리멘털 캐시)
- 다중 프레임워크 위젯 공존
11.2 약한 곳
- **깊은 풀스택** — 인증, 권한, 워크플로우, 큐, 백그라운드 작업이 페이지 코드와 강하게 엮인 시나리오. Astro는 의도적으로 얕음.
- **앱스러운 SPA** — 모든 페이지가 동적이고 상태 공유가 깊다면, Astro의 정적 우선 모델이 이점을 잃음.
- **에코시스템 깊이** — Next.js 대비 라이브러리/예제/구인 시장이 작음.
- **호스팅 락인 없음**의 그림자 — Vercel만큼 매끄럽게 통합된 호스팅이 부재. 어댑터 품질이 호스팅마다 다름.
- **개발 도구** — 강력하지만 Next.js의 RSC 디버깅/캐시 시각화 만큼 무르익지 않음.
- **Server Islands의 함정** — 너무 많이 깔면 페이지 위가 placeholder투성이가 되고 사용자 인식이 나빠짐. "본문은 정적, 작은 섬만 동적" 원칙을 지켜야 함.
11.3 결정 한 줄
> "당신의 사이트가 책이라면 Astro. 당신의 사이트가 도구라면 Next.js. 그 중간이면 SvelteKit도 같이 평가하라."
에필로그 — 체크리스트와 다음 글 예고
12.1 Astro 5를 도입할 때 체크리스트
- [ ] 페이지의 캐시 가능 비율이 80% 이상인가 (Server Islands가 빛나는 임계)
- [ ] 콘텐츠 소스가 1개 이상이고, 그중 일부가 외부 CMS/DB인가 (Content Layer 적합)
- [ ] 다국어가 필요한가 (코어 i18n 활용)
- [ ] 빌드 시간이 늘면 곤란한가 (인크리멘털 캐시 필요)
- [ ] 컴포넌트 라이브러리가 React/Svelte/Vue 중 하나로 고정되어 있는가 (호환성 점검)
- [ ] 호스팅 어댑터(Vercel/Netlify/Cloudflare/Node)가 안정 버전인지 확인했는가
- [ ] 폼은 Actions로, 페이지 일부 개인화는 Server Island로, 진짜 동적 페이지만 SSR로 — 룰을 합의했는가
12.2 안티패턴
- 페이지의 70%를 Server Island로 만든다 (그러면 그냥 SSR이 낫다)
- LCP 영역 위에 Server Island를 둔다 (지연이 사용자에게 직격)
- Content Layer를 우회해 페이지 컴포넌트에서 직접 fetch를 흩뿌린다 (캐시·타입 둘 다 잃음)
- Actions를 거치지 않고 직접 API 라우트만 만든다 (점진적 강화 못함)
- `client:load`로 모든 컴포넌트를 하이드레이트한다 (Astro 쓰는 의미가 사라짐)
- View Transitions 도입하면서 페이지마다 다른 레이아웃을 쓴다 (요소 추적이 깨짐)
12.3 다음 글 예고
- "Astro Server Islands로 e커머스 스토어프런트 만들기 — 본문 캐시 95%를 지키는 법"
- "Content Layer 커스텀 로더 패턴 — Notion, Postgres, S3에서 컬렉션 끌어오기"
- "Astro Actions와 점진적 강화 폼 — JS 0kb 폼이 가능한 이유"
- "Astro 6를 향한 로드맵 — Live Loaders 안정화와 그 다음"
이 시리즈의 한 줄 약속 — **"콘텐츠 사이트의 표준은 다시 바뀌었고, 그 이름은 Astro 5다."**
참고 / References
- [Astro 5.0 Release Blog (2024-12-03)](https://astro.build/blog/astro-5/)
- [Astro 5.0 Beta Release](https://astro.build/blog/astro-5-beta/)
- [Server Islands — Astro Docs](https://docs.astro.build/en/guides/server-islands/)
- [Server Islands Announcement](https://astro.build/blog/future-of-astro-server-islands/)
- [Islands Architecture — Astro Docs](https://docs.astro.build/en/concepts/islands/)
- [Content Layer — Deep Dive](https://astro.build/blog/content-layer-deep-dive/)
- [Content Collections — Astro Docs](https://docs.astro.build/en/guides/content-collections/)
- [Content Loader API Reference](https://docs.astro.build/en/reference/content-loader-reference/)
- [Astro Actions — Docs](https://docs.astro.build/en/guides/actions/)
- [Actions API Reference](https://docs.astro.build/en/reference/modules/astro-actions/)
- [View Transitions — Docs](https://docs.astro.build/en/guides/view-transitions/)
- [View Transitions Router Reference](https://docs.astro.build/en/reference/modules/astro-transitions/)
- [Astro 2024 Year in Review](https://astro.build/blog/year-in-review-2024/)
- [Live Content Loaders Roadmap Issue #1151](https://github.com/withastro/roadmap/issues/1151)
- [Storyblok Loader for Content Layer](https://www.storyblok.com/mp/announcing-storyblok-loader-astro-content-layer-api)
- [Hygraph Astro Content Loader](https://hygraph.com/blog/introducing-hygraph-astro-content-loader)
- [Content Layer for Headless WordPress](https://andrewkepson.com/blog/headless-wordpress/build-time-astro-content-layer-api/)
- [Comparing JS Frameworks for Content Sites — DatoCMS](https://www.datocms.com/blog/comparing-js-frameworks-for-content-heavy-sites)
- [Astro 4.0 Release](https://astro.build/blog/astro-4/)
- [Astro 3.5 i18n Routing](https://astro.build/blog/astro-350/)
현재 단락 (1/276)
2022년의 Astro는 마크다운 블로그용 정적 사이트 생성기였습니다. 2024년 12월 3일에 공개된 Astro 5는, 같은 이름을 달고 있지만 다른 물건입니다. **콘텐츠 중심...