본문으로 건너뛰기
김신건의 로그

Astro

· 수정 · 📖 약 2분 · 1,016자/단어 #framework #ssg #web #javascript #static-site
astro.build, astro framework, Astro SSG, Astro Islands, astro

정의

Astro 는 콘텐츠 중심 사이트를 위한 정적 사이트 프레임워크다. “Islands Architecture”로 필요한 부분만 hydration하기 때문에 기본 JS 전송량이 0에 가깝다.

이 블로그(shinkeonkim.com)가 Astro 6으로 구축됐다.

  • 마크다운 / MDX 콘텐츠 렌더링
  • 자체 remark 플러그인으로 위키링크 자동 변환 (BrainDB 참고)
  • D3 기반 그래프 페이지의 React Island 호스팅
  • GitHub Actions를 통한 정적 빌드 → GitHub Pages 배포

사용 상황

상황적합 여부
블로그, 문서 사이트
콘텐츠 중심 마케팅 페이지
SPA (풍부한 인터랙션 위주)❌ (Next.js / SvelteKit 추천)
서버 사이드 렌더링 위주 앱부분 적합 (adapter 필요)
다중 프레임워크 혼용✅ (React + Vue + Svelte 공존 가능)

Islands Architecture

flowchart TB
    SERVER["빌드 타임 서버"]
    HTML["정적 HTML 출력"]

    subgraph PAGE["렌더링된 페이지"]
        STATIC1["정적 마크다운 콘텐츠"]
        ISLAND1["Island: React 컴포넌트<br/>client:load"]
        STATIC2["정적 이미지 / 텍스트"]
        ISLAND2["Island: D3 그래프<br/>client:visible"]
    end

    BUNDLE1["React 번들 (즉시 hydration)"]
    BUNDLE2["D3 번들 (뷰포트 진입 시)"]

    SERVER --> HTML --> PAGE
    ISLAND1 -.->|"개별 번들"| BUNDLE1
    ISLAND2 -.->|"개별 번들"| BUNDLE2

핵심 개념: 페이지 대부분은 정적 HTML이고, 인터랙션이 필요한 “Island”만 JS 번들을 로드한다. 각 Island는 독립적으로 hydration된다.

client: 디렉티브

디렉티브언제 hydration
client:load즉시 (페이지 로드 시)
client:idle브라우저가 idle 상태일 때
client:visible뷰포트에 진입할 때
client:media="(max-width: 768px)"미디어 쿼리 충족 시
client:only="react"SSR 없이 클라이언트 전용

핵심 기능

Content Collections

타입 안전 콘텐츠 관리. src/content/ 아래 컬렉션을 content.config.ts에 스키마로 정의한다.

// src/content.config.ts
import { defineCollection, z } from 'astro:content';

const posts = defineCollection({
  schema: z.object({
    title: z.string(),
    date: z.date(),
    tags: z.array(z.string()).default([]),
  }),
});

export const collections = { posts };
// 페이지에서 타입 안전 쿼리
const allPosts = await getCollection('posts', ({ data }) => !data.draft);

Component Islands

React, Vue, Svelte 등 여러 프레임워크 컴포넌트를 같은 페이지에서 사용 가능하다:

---
import ReactCounter from './Counter.tsx';
import VueWidget from './Widget.vue';
---

<ReactCounter client:load />
<VueWidget client:visible />

Adapters (서버 배포)

기본은 정적 출력. 서버 기능 필요 시 adapter 추가:

Adapter플랫폼
@astrojs/vercelVercel Edge / Serverless
@astrojs/netlifyNetlify Functions
@astrojs/nodeNode.js (자체 서버)
@astrojs/cloudflareCloudflare Workers

View Transitions

페이지 전환 시 부드러운 애니메이션. MPA(Multi-Page App)에서 SPA처럼 느껴지는 전환을 제공한다.

---
import { ViewTransitions } from 'astro:transitions';
---

<head>
  <ViewTransitions />
</head>

특정 요소에 이름 부여해 전환 애니메이션 연결:

<img src={post.cover} transition:name="hero-image" />

Astro DB

내장 SQLite 기반 데이터베이스. 빌드 시 seed 데이터 주입 가능.

// db/config.ts
import { defineDb, defineTable, column } from 'astro:db';

const Comments = defineTable({
  columns: {
    id: column.number({ primaryKey: true }),
    postSlug: column.text(),
    body: column.text(),
  },
});

export default defineDb({ tables: { Comments } });

MDX 지원

마크다운에 JSX 컴포넌트를 삽입. @astrojs/mdx 통합으로 활성화된다.

import Chart from '../components/Chart.tsx';

# 2024년 데이터 분석

<Chart client:visible data={data} />

일반 마크다운과 컴포넌트를 혼용할 수 있다.

Integrations (통합)

공식 + 커뮤니티 통합을 astro.config.mjs에 추가한다:

import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';
import react from '@astrojs/react';
import sitemap from '@astrojs/sitemap';

export default defineConfig({
  integrations: [mdx(), react(), sitemap()],
  markdown: {
    remarkPlugins: [remarkWikiLink],
    rehypePlugins: [rehypePrettyCode],
  },
});

프로젝트 구조

src/
├── content/        ← Content Collections (posts, wiki, notes)
├── pages/          ← 파일 기반 라우팅 (.astro, .md, .mdx)
├── layouts/        ← 재사용 레이아웃 컴포넌트
├── components/     ← UI 컴포넌트 (Astro + React 혼용)
└── styles/         ← 글로벌 CSS

public/             ← 정적 파일 (이미지, 폰트, favicon)

실전 예시: 동적 라우팅

---
// src/pages/posts/[slug].astro
import { getCollection } from 'astro:content';

export async function getStaticPaths() {
  const posts = await getCollection('posts');
  return posts.map(post => ({
    params: { slug: post.slug },
    props: { post },
  }));
}

const { post } = Astro.props;
const { Content } = await post.render();
---

<article>
  <h1>{post.data.title}</h1>
  <Content />
</article>

대안

프레임워크특징선택 기준
Next.jsReact, SSR/SSG 혼합React 앱, 풍부한 인터랙션
GatsbyReact, GraphQL 기반CMS 연동, 플러그인 생태계
SvelteKitSvelte 기반, 경량빠른 개발, 작은 번들
Nuxt.jsVue 기반, SSR/SSGVue 팀 선택
Eleventy프레임워크 무관, 순수 정적극단적 단순함 선호
HugoGo 기반, 매우 빠른 빌드수천 개 이상 포스트

TIP

Astro는 콘텐츠 사이트에 강하다. 인터랙션이 핵심인 앱이라면 Next.js 또는 SvelteKit이 더 적합하다.

함정

WARNING

Islands 간 상태 공유 어려움: 각 Island가 독립적이라 Island 간 상태를 공유하려면 nanostore, zustand 같은 클라이언트 상태 라이브러리가 필요하다.

CAUTION

.astro 파일에서 async/await: getCollection() 등은 서버 전용이다. 클라이언트에서 document 접근은 브라우저 전용 Island 안에서만 가능하다.

WARNING

client:only SSR 누락: client:only는 서버에서 렌더링하지 않으므로, SEO가 중요한 콘텐츠에 사용하면 안 된다.

IMPORTANT

remark / rehype 플러그인 순서: MDX 플러그인 체인에서 순서가 중요하다. 특히 위키링크 변환 플러그인은 다른 플러그인보다 먼저 실행해야 할 수 있다.

WARNING

Content Collections 타입 갱신: frontmatter 스키마를 변경하면 .astro/types.d.ts를 재생성해야 한다. bun astro sync로 수동 갱신 가능.

관련 위키

  • BrainDB - 마크다운 콘텐츠 그래프 처리 (이 블로그에서 커스텀 구현)
  • D3 - 이 블로그 그래프 페이지의 렌더링 엔진
  • pagefind - Astro 정적 사이트 전문 검색
  • react - Astro Island로 통합 가능한 프레임워크
이 글의 용어 (4개)
[Voice AI] Agent 패턴: Supervisor, Handoff, ReAct, HITLai
정의 복잡한 음성 에이전트 = 여러 sub-agent + 조정 패턴. 단일 LLM 으로 처리하기 어려운 흐름. [!IMPORTANT] 각 sub-agent 내부는 VAD → ST…
BrainDBframeworks
정의 BrainDB 는 마크다운 파일을 SQLite 기반 데이터베이스로 인덱싱해, 위키링크 처리, 백링크 추출, 콘텐츠 그래프 생성, 깨진 링크 감지를 제공하는 통합 라이브러리다…
D3.jsframeworks
정의 D3 (Data-Driven Documents)는 데이터를 DOM 요소에 바인딩해 SVG, Canvas, HTML 기반 시각화를 만드는 JavaScript 라이브러리다. M…
Pagefind: 정적 사이트 전문 검색frameworks
정의 Pagefind 는 정적 사이트 (SSG) 용 클라이언트 사이드 전문 검색 엔진. 빌드 후 정적 인덱스 생성, 브라우저에서 WASM + fetch 로 검색. CloudCan…

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기