테마 전환

Astro SSR 설정 완전 가이드: 3단계로 서버 사이드 렌더링 활성화하기

Easton editorial illustration: rendering-mode selector

Astro 블로그가 아주 빠르게 동작하고 Lighthouse 점수도 95점 이상이라 만족하고 있는데, 갑자기 상사가 “사용자 로그인 기능을 추가하자”고 말합니다. 정적 사이트에서 사용자 로그인을 어떻게 구현해야 할까요? 공식 문서를 펼치면 SSR, SSG, Hybrid, adapter 같은 개념이 한꺼번에 쏟아져 나와 읽을수록 혼란스러워집니다.

저도 Astro SSR을 처음 접했을 때 똑같았습니다. Astro의 장점은 분명 “빠르다”는 것인데 서버 사이드 렌더링을 추가하면 느려지는 건 아닐까요? Vercel, Netlify, Node.js 등 어댑터도 많은데 무엇을 골라야 할까요? 설정 파일의 outputprerender는 대체 무엇을 뜻할까요?

실제로 Astro SSR 설정은 생각만큼 복잡하지 않습니다. 이 글에서는 가장 이해하기 쉬운 방식으로 언제 SSG 대신 SSR을 꼭 써야 하는지, 여러 어댑터를 빠르게 설정하는 방법, 한 프로젝트에서 SSR과 SSG를 함께 쓰는 방법(Hybrid 모드)을 설명합니다. 글을 다 읽으면 자신의 프로젝트에 SSR이 필요한지 스스로 판단하고 30분 안에 설정할 수 있습니다.

1장: SSR 기본 개념과 기술 선택

SSG 대신 SSR은 언제 필요한가요?

먼저 가장 간단한 판단 기준부터 보겠습니다. 콘텐츠가 빌드 시점에 이미 정해지나요, 아니면 방문할 때마다 달라질 수 있나요?

SSG(Static Site Generation)는 식당이 미리 준비해 둔 세트 메뉴와 같습니다. 아침에 요리사가 음식을 준비해 두면 손님이 왔을 때 바로 내놓을 수 있어 매우 빠릅니다. 블로그 글, 제품 소개 페이지, 회사 소개처럼 거의 변하지 않는 콘텐츠에는 SSG가 완벽합니다.

SSR(Server-Side Rendering)은 주문을 받은 뒤 바로 조리하는 것과 같습니다. 손님이 주문하면 요구에 맞춰 그 자리에서 요리합니다. 로그인 뒤 표시되는 “다시 오신 것을 환영합니다, 홍길동 님”, 실시간 주가, 장바구니 상품 수처럼 사람마다 보이는 내용이 다르다면 SSR이 필요합니다.

그렇다면 내 프로젝트에 SSR이 필요한지 궁금할 것입니다. 아래 다섯 가지 중 하나라도 해당한다면 SSR을 고려해야 합니다.

1. 사용자 인증과 개인화 콘텐츠

가장 대표적인 사례는 로그인입니다. 빌드할 때는 누가 로그인하고 어떤 사용자 이름을 표시할지 알 수 없습니다. 예전에 만든 학습 플랫폼은 홈에 “이어서 학습: 5강”을 표시해야 했습니다. 로그인한 사용자의 학습 진도에 따라 동적으로 생성해야 하므로 SSR이 필요합니다.

2. 실시간 데이터 표시

일기예보, 주가, 스포츠 경기 점수는 매분 바뀝니다. 사이트를 매분 다시 빌드할 수는 없습니다. SSR을 사용하면 사용자가 방문할 때마다 최신 데이터를 가져올 수 있습니다.

3. 데이터베이스 조회

전자상거래 사이트의 상품 검색 결과는 검색어마다 다릅니다. 가능한 모든 검색 결과 페이지를 미리 만들 수는 없습니다. SSR을 사용하면 사용자가 검색할 때 실시간으로 데이터베이스를 조회해 결과를 반환합니다.

4. API 라우트

폼 제출, 파일 업로드, 서드파티 API 호출에는 백엔드 로직이 필요합니다. Astro의 SSR 모드에서는 API 라우트(src/pages/api/xxx.js)를 만들 수 있으므로 별도의 백엔드 서버를 구축하지 않아도 됩니다.

5. A/B 테스트와 개인화 추천

사용자의 위치, 방문 시간, 과거 행동에 따라 다른 콘텐츠를 표시합니다. 예를 들어 Taobao 홈의 추천 상품은 사람마다 다릅니다. 이런 개인화에는 SSR이 필요합니다.

여기까지 들으면 “블로그 글 상세 페이지도 SSR로 만들 수 있나요?”라는 질문이 나옵니다. 가능하지만 그럴 필요는 없습니다. 글 내용은 고정되어 있으므로 SSG로 정적 HTML을 만들고 CDN에서 직접 제공하는 편이 더 빠르고 서버 비용도 낮습니다. SSR은 만능이 아니므로 기술 자체를 쓰기 위해 도입하지 마세요.

Hybrid 모드: 두 가지 장점을 모두 얻는 방법

Astro 2.0에서 도입한 Hybrid 모드는 한 프로젝트의 정적 페이지에는 SSG, 동적 페이지에는 SSR을 사용할 수 있게 해 줍니다. 예를 들어 전자상거래 사이트라면 다음과 같이 나눌 수 있습니다.

  • 홈, About 페이지, 도움말 문서 → SSG(빠른 로딩)
  • 로그인 페이지, 사용자 센터, 장바구니 → SSR(동적 콘텐츠)
  • 상품 상세 페이지 → SSG(고정 콘텐츠)
  • 검색 결과 페이지 → SSR(실시간 조회)

이렇게 설정하면 정적 페이지의 속도는 전혀 떨어지지 않으면서 동적 기능도 온전히 구현할 수 있습니다. 지인의 블로그도 글 목록과 상세 페이지는 SSG, 댓글 영역은 SSR을 사용하며 Lighthouse 점수를 여전히 95점 이상으로 유지하고 있습니다.

2장: 빠른 시작 - 3단계로 SSR 모드 활성화하기

처음부터 Astro SSR 설정하기(Node.js 어댑터)

프로젝트에 SSR이 필요하다고 판단했다면 설정을 시작해 보겠습니다. 가장 범용적이며 자체 서버나 VPS 배포에 적합한 Node.js 어댑터로 먼저 설명합니다.

1단계: 한 번에 어댑터 설치하기

Astro 공식 자동 설정 명령은 매우 간단합니다. 프로젝트 루트에서 다음 명령을 실행합니다.

npx astro add node

이 명령 하나가 자동으로 세 가지 작업을 처리합니다.

  1. @astrojs/node 패키지 설치
  2. astro.config.mjs 설정 파일 수정
  3. package.json 의존성 업데이트

실행이 끝나면 터미널에 여러 개의 초록색 체크 표시가 나타납니다. 설정이 성공했다는 뜻입니다. 버전을 지정해야 하는 등의 이유로 직접 설치하려면 다음 명령을 사용할 수도 있습니다.

npm install @astrojs/node

그다음 설정 파일을 직접 수정합니다. 이 내용은 다음 단계에서 설명합니다.

2단계: 설정 파일 수정하기

프로젝트 루트의 astro.config.mjs를 엽니다. 자동 설정 명령을 사용했다면 이미 다음 내용이 들어 있습니다.

// astro.config.mjs
import { defineConfig } from 'astro/config';
import node from '@astrojs/node';

export default defineConfig({
  output: 'server', // SSR 모드 활성화
  adapter: node({
    mode: 'standalone' // 독립 서버 모드
  }),
});

두 설정 항목을 자세히 살펴보겠습니다.

output 설정:

  • 'static'(기본값): 모든 페이지를 SSG로 만들고 순수 정적 HTML 출력
  • 'server': 모든 페이지를 SSR로 처리하고 요청할 때마다 동적으로 생성
  • 'hybrid': 기본값은 SSG이며 페이지별로 SSR 활성화(권장)

mode 설정:

  • 'standalone': Astro가 독립 Node.js 서버를 시작하며 직접 배포하기에 적합
  • 'middleware': Express, Koa 같은 프레임워크에 통합할 수 있는 미들웨어 생성

저는 보통 standalone을 사용합니다. Astro 내장 서버만으로도 충분해 별도로 통합할 필요가 없기 때문입니다. 기존 프로젝트에 Express 백엔드가 있고 Astro를 그 일부로 넣고 싶다면 middleware를 사용하면 됩니다.

3단계: 빌드하고 실행하기

설정을 마쳤다면 프로젝트를 빌드합니다.

npm run build

빌드가 끝나면 dist/ 디렉터리에 server/ 폴더가 생기고 그 안에 entry.mjs 파일이 있습니다. 이것이 SSR 서버의 진입점입니다.

SSR 서버를 실행합니다.

node ./dist/server/entry.mjs

기본적으로 http://localhost:4321에서 서비스가 시작됩니다. 사이트에 접속하면 모든 페이지가 SSR로 바뀐 것을 확인할 수 있습니다.

개발 환경 디버깅

개발 중에는 수정할 때마다 빌드할 필요가 없습니다. 다음 명령만 실행하면 됩니다.

npm run dev

개발 서버가 SSR을 자동 지원하고 코드 변경 사항도 즉시 반영하므로 매우 편리합니다.

자주 발생하는 문제 해결

  1. 포트 사용 중: 4321 포트를 이미 사용하고 있다면 환경 변수를 설정합니다.

    PORT=3000 node ./dist/server/entry.mjs
  2. adapter 모듈을 찾지 못함: @astrojs/node가 설치되었는지 확인하고 npm install을 실행해 의존성을 다시 설치합니다.

  3. 페이지 404: src/pages/ 디렉터리의 파일이 올바른지 확인합니다. SSR 모드에서도 Astro의 라우팅 규칙은 그대로 적용됩니다.

솔직히 SSR 설정은 정말 이 정도로 간단합니다. 저도 처음 설정했을 때 시작부터 실행 성공까지 5분도 걸리지 않았습니다. Vercel이나 Netlify에 배포한다면 전용 어댑터가 있어 설정이 더 간단합니다. 다음 장에서 자세히 알아보겠습니다.

3장: 주요 어댑터 설정 상세 가이드

Vercel, Netlify, Cloudflare 중 무엇을 선택해야 할까요?

프로젝트를 Vercel, Netlify 또는 Cloudflare에 호스팅한다면 SSR 설정은 더 간단합니다. 각 플랫폼에는 Astro가 공식 유지 관리하는 전용 어댑터가 있어 별도 설정 없이 배포할 수 있습니다.

Vercel 어댑터 - Serverless 함수의 강자

Vercel은 제가 가장 자주 사용하는 배포 플랫폼입니다. 개인 프로젝트에는 무료 할당량도 충분하고 설정도 매우 간단합니다.

npx astro add vercel

이 명령이 모든 것을 자동으로 설정합니다. 설정 파일은 다음과 같습니다.

// astro.config.mjs
import { defineConfig } from 'astro/config';
import vercel from '@astrojs/vercel/serverless';

export default defineConfig({
  output: 'server',
  adapter: vercel(),
});

Vercel의 대표 기능: ISR(증분 정적 재생성)

Vercel만의 이 기능을 사용하면 SSR 페이지도 SSG처럼 빠르게 제공할 수 있습니다. 첫 방문 때 SSR로 페이지를 생성한 뒤 일정 시간 캐시하고, 이후 방문에는 캐시를 바로 사용하다가 만료되면 다시 생성하는 방식입니다.

adapter: vercel({
  isr: {
    expiration: 60, // 60초 캐시
  },
}),

예를 들어 뉴스 사이트의 글 상세 페이지는 요청마다 데이터베이스를 조회하지 않고 1분에 한 번만 갱신해도 충분할 수 있습니다. ISR을 사용하면 SSR의 유연성과 SSG의 속도를 모두 얻을 수 있습니다.

Vercel 배포 과정:

  1. 어댑터 설정
  2. 코드를 GitHub에 푸시
  3. Vercel 콘솔에서 프로젝트 가져오기
  4. 빌드 명령: npm run build(자동 인식)
  5. 배포 버튼 클릭, 완료!

Netlify 어댑터 - Edge Functions의 강자

Netlify도 널리 사용하는 배포 플랫폼이며 특히 정적 사이트에 동적 기능을 더한 구성에 잘 맞습니다.

npx astro add netlify

설정 파일은 다음과 같습니다.

// astro.config.mjs
import { defineConfig } from 'astro/config';
import netlify from '@astrojs/netlify';

export default defineConfig({
  output: 'server',
  adapter: netlify({
    edgeMiddleware: true, // Edge 미들웨어 활성화
  }),
});

edgeMiddleware란 무엇인가요?

간단히 말해 인증이나 리디렉션 같은 미들웨어 로직을 엣지 노드에서 실행해 응답을 더 빠르게 만드는 기능입니다. 사용자 위치에 따라 언어를 다르게 표시하는 등 위치 관련 기능이 있다면 edge가 매우 유용합니다.

Netlify 리디렉션 설정

Netlify는 리디렉션을 자동 처리하기 편리합니다. 예를 들어 /old-page/new-page로 리디렉션하려면 프로젝트 루트에 _redirects 파일을 만들고 다음 내용을 넣으면 됩니다.

/old-page  /new-page  301

배포하면 코드 수정 없이 자동으로 적용됩니다.

Cloudflare 어댑터 - 전 세계 CDN 가속

사용자가 전 세계에 분포한다면 Cloudflare가 가장 좋은 선택입니다. Workers가 전 세계 300개 이상의 데이터 센터에서 실행되므로 지연 시간이 매우 짧습니다.

npx astro add cloudflare

설정 파일은 다음과 같습니다.

// astro.config.mjs
import { defineConfig } from 'astro/config';
import cloudflare from '@astrojs/cloudflare';

export default defineConfig({
  output: 'server',
  adapter: cloudflare(),
});

Cloudflare의 제한 사항

Cloudflare Workers 실행 환경은 Node.js와 완전히 같지 않으므로 fs 파일 시스템 같은 일부 Node.js API를 사용할 수 없습니다. 프로젝트가 이런 API에 의존한다면 Cloudflare가 적합하지 않을 수 있습니다.

어댑터 비교표

어댑터적합한 상황핵심 장점주요 제한
Node.js자체 서버, VPS완전한 제어, 제한 없음직접 운영해야 하며 비용이 높음
Vercel개인 프로젝트, 소규모 팀별도 설정 불필요, ISR 지원무료 할당량 제한(월 100GB 대역폭)
Netlify정적 사이트 + 동적 기능빠른 Edge Functions빌드 시간 제한(무료 월 300분)
Cloudflare전 세계 사용자, 짧은 지연 시간엣지 컴퓨팅, 낮은 가격Workers 환경 제한, 일부 Node API 사용 불가

제 선택 기준:

  • 블로그, 문서 사이트: 무료 할당량이 충분하고 배포가 간단한 Vercel 또는 Netlify 우선
  • 전자상거래, SaaS 애플리케이션: ISR이 유용한 Vercel 또는 완전히 제어할 수 있는 자체 Node.js 서버
  • 국제화 제품: 전 세계 가속을 제공하는 Cloudflare
  • 기업 프로젝트: 데이터 프라이버시와 완전한 통제를 위한 자체 Node.js

절대적인 정답은 없습니다. 프로젝트 요구 사항과 예산에 맞춰 선택하면 됩니다. 제 블로그에는 Vercel을 사용하고 고객사의 기업 웹사이트에는 자체 서버를 사용하는데 둘 다 잘 작동합니다.

4장: Hybrid 혼합 렌더링 실전

한 프로젝트에서 SSR과 SSG 함께 사용하기

지금까지 순수 SSR 설정을 살펴봤습니다. 이제 핵심인 Hybrid 모드를 알아보겠습니다. 한 프로젝트에서 SSG의 속도와 SSR의 유연성을 모두 누릴 수 있게 해 주는 Astro의 결정적인 기능입니다.

Hybrid 모드 설정하기

output'hybrid'로 바꾸기만 하면 됩니다.

// astro.config.mjs
import { defineConfig } from 'astro/config';
import node from '@astrojs/node';

export default defineConfig({
  output: 'hybrid', // 기본 SSG, 필요할 때 SSR
  adapter: node(),
});

설정이 끝나면 기본적으로 모든 페이지가 SSG가 됩니다. SSR이 필요한 페이지에 코드 한 줄을 추가해 SSR을 활성화할 수 있습니다.

페이지별 렌더링 방식 제어

특정 페이지에서 SSR을 사용하려면 페이지 파일의 frontmatter에 한 줄을 추가합니다.

// src/pages/dashboard.astro (SSR)

---

export const prerender = false; // 사전 렌더링을 끄고 SSR 사용
const user = Astro.cookies.get('user');

---

<h1>다시 오신 것을 환영합니다, {user?.name} 님</h1>
<p>읽지 않은 알림이 {user?.notifications}개 있습니다.</p>

이것이 전부입니다. prerender = false는 “빌드할 때 만들지 말고 사용자가 방문할 때 동적으로 생성하라”는 뜻입니다.

반대로 output'server'(전체 SSR)로 설정한 상태에서 특정 페이지를 SSG로 만들려면 다음과 같이 작성합니다.

// src/pages/about.astro (SSG)

---

export const prerender = true; // 빌드할 때 강제로 생성

---

<h1>회사 소개</h1>
<p>이 페이지의 내용은 변하지 않습니다. 미리 생성하면 매우 빠르게 열립니다.</p>

핵심 정리(혼동하지 마세요):

output 설정기본 동작개별 페이지를 변경하는 방법
'hybrid'모든 페이지 SSGexport const prerender = false → 해당 페이지 SSR
'server'모든 페이지 SSRexport const prerender = true → 해당 페이지 SSG

저도 처음에는 자주 반대로 기억했습니다. 이렇게 외우면 쉽습니다. hybrid는 SSG 우선, server는 SSR 우선입니다.

실전 사례: 블로그 + 사용자 시스템

글을 보여 주는 기능과 사용자 로그인 기능을 갖춘 블로그 플랫폼을 만든다고 가정해 보겠습니다. 이상적인 설정은 다음과 같습니다.

프로젝트 구조:

src/pages/
├── index.astro          // 홈 (SSG)
├── about.astro          // 회사 소개 (SSG)
├── blog/
│   ├── [slug].astro     // 글 상세 (SSG)
│   └── index.astro      // 글 목록 (SSG)
├── login.astro          // 로그인 페이지 (SSR)
├── dashboard.astro      // 사용자 센터 (SSR)
└── api/
    └── comments.js      // 댓글 API (SSR)

설정 파일:

// astro.config.mjs
export default defineConfig({
  output: 'hybrid', // 기본 SSG
  adapter: vercel(), // Vercel에 배포
});

정적 페이지(특별한 설정 불필요):

// src/pages/blog/[slug].astro

---

// prerender 설정이 없으면 기본값은 SSG
import { getCollection } from 'astro:content';

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

const { post } = Astro.props;

---

<article>
  <h1>{post.data.title}</h1>
  <div set:html={post.body} />
</article>

동적 페이지(SSR 필요):

// src/pages/dashboard.astro

---

export const prerender = false; // SSR 활성화

// 사용자 로그인 상태 확인
const token = Astro.cookies.get('token')?.value;
if (!token) {
  return Astro.redirect('/login');
}

// 데이터베이스에서 사용자 정보 가져오기
const user = await fetch(`https://api.example.com/user`, {
  headers: { Authorization: `Bearer ${token}` }
}).then(res => res.json());

---

<div>
  <h1>환영합니다, {user.name} 님</h1>
  <p>이메일: {user.email}</p>
  <p>최근 로그인: {user.lastLogin}</p>
</div>

API 라우트(자동 SSR):

// src/pages/api/comments.js
export async function POST({ request }) {
  const { articleId, content } = await request.json();

  // 데이터베이스에 댓글 저장
  await db.comments.insert({
    articleId,
    content,
    createdAt: new Date(),
  });

  return new Response(JSON.stringify({ success: true }), {
    status: 200,
    headers: { 'Content-Type': 'application/json' }
  });
}

export async function GET({ url }) {
  const articleId = url.searchParams.get('articleId');

  // 데이터베이스에서 댓글 읽기
  const comments = await db.comments.findMany({
    where: { articleId },
    orderBy: { createdAt: 'desc' }
  });

  return new Response(JSON.stringify(comments), {
    headers: { 'Content-Type': 'application/json' }
  });
}

이 설정의 장점:

  1. 정적 페이지(글, 홈)는 여전히 번개처럼 빠르고 Lighthouse 점수 95점 이상을 유지하며 모두 CDN을 사용합니다.
  2. 동적 페이지(사용자 센터)는 실시간으로 데이터를 가져와 사용자마다 다른 내용을 보여 줍니다.
  3. API 라우트가 백엔드 기능을 제공하므로 별도 백엔드 서버를 구축할 필요가 없습니다.
  4. 빌드 시간이 짧습니다. 정적 페이지만 사전 렌더링하고 동적 페이지는 빌드 시간을 차지하지 않습니다.

예전에 진행한 프로젝트는 블로그 글 50개와 사용자 시스템을 갖췄지만 빌드에 20초밖에 걸리지 않았습니다. 배포 뒤 정적 페이지는 즉시 열렸고 동적 페이지의 응답 시간도 100ms 이내였습니다. Hybrid 모드는 정말 모범적인 선택입니다.

5장: 자주 발생하는 문제와 모범 사례

SSR 설정의 함정과 해결 방법

SSR을 설정하면서 여러 문제를 겪었습니다. 흔한 문제와 해결 방법을 정리했으니 같은 실수를 피하는 데 참고하세요.

문제 1: Astro.clientAddress is only available when using output: 'server' 오류

원인: 코드에서 사용자 IP를 가져오는 Astro.clientAddress를 사용했지만 설정 파일의 output이 여전히 'static'입니다.

해결 방법:

// astro.config.mjs
export default defineConfig({
  output: 'server', // 또는 'hybrid'
  adapter: node(),
});

Astro.clientAddress, Astro.cookies, Astro.redirect() 같은 동적 API는 SSR 모드에서만 사용할 수 있습니다.

문제 2: 로컬 개발에서는 정상인데 배포 뒤 페이지가 404

원인: 어댑터 설정이 잘못되었거나 배포 플랫폼의 빌드 명령 또는 출력 디렉터리가 잘못 설정되었습니다.

해결 방법:

Vercel 배포:

  • 빌드 명령: npm run build
  • 출력 디렉터리: .vercel/output(자동)
  • vercel.json에서 라우트를 직접 설정하지 말고 Astro가 처리하도록 합니다.

Netlify 배포:

  • 빌드 명령: npm run build

  • 게시 디렉터리: 정적 사이트는 dist, SSR은 .netlify

  • 계속 404가 발생하면 netlify.toml을 확인합니다.

    [build]
      command = "npm run build"
      publish = "dist"

문제 3: SSR 페이지 로딩이 2초를 넘을 만큼 느림

원인: 서버 성능이 부족하거나 데이터베이스 조회가 너무 느립니다.

해결 방법:

  1. 캐시 사용:

    // src/pages/api/news.js
    export async function GET() {
      const cached = await redis.get('news');
      if (cached) {
        return new Response(cached, {
          headers: {
            'Content-Type': 'application/json',
            'Cache-Control': 'public, max-age=60' // 60초 캐시
          }
        });
      }
    
      const news = await fetchNewsFromDB();
      await redis.set('news', JSON.stringify(news), 'EX', 60);
    
      return new Response(JSON.stringify(news), {
        headers: {
          'Content-Type': 'application/json',
          'Cache-Control': 'public, max-age=60'
        }
      });
    }
  2. 데이터베이스 조회 최적화:

    • 인덱스 추가
    • JOIN 줄이기
    • 필요한 필드만 조회
  3. ISR 고려(Vercel 사용 시):

    adapter: vercel({
      isr: { expiration: 300 } // 5분 캐시
    }),

문제 4: 클라이언트에서 환경 변수를 가져올 수 없음

원인: Astro의 환경 변수는 클라이언트용과 서버용으로 나뉩니다.

해결 방법:

서버에서 사용(SSR 페이지, API 라우트):

const secret = import.meta.env.SECRET_KEY; // 모든 환경 변수를 사용할 수 있음

클라이언트에서 사용(브라우저 JavaScript):

const apiUrl = import.meta.env.PUBLIC_API_URL; // 반드시 PUBLIC_로 시작해야 함

.env 파일 설정:

SECRET_KEY=abc123          # 서버에서만 사용 가능
PUBLIC_API_URL=https://api.example.com  # 클라이언트와 서버 모두 사용 가능

문제 5: adapter.setApp is not a function 오류

원인: Astro 버전과 어댑터 버전이 호환되지 않습니다.

해결 방법:

# 최신 버전으로 업데이트
npm update astro @astrojs/node

# 또는 호환되는 버전 지정(공식 문서 확인)
npm install astro@latest @astrojs/node@latest

일반적으로 Astro와 어댑터를 모두 최신 버전으로 유지하면 문제가 없습니다.

모범 사례 요약

  1. Hybrid 모드를 기본값으로 사용: 모든 페이지에 SSR이 필요한 경우가 아니라면 output: 'hybrid'가 가장 좋은 선택입니다.
  2. 필요할 때만 SSR 활성화: 동적 렌더링이 꼭 필요한 페이지에만 prerender = false를 설정합니다.
  3. 정적 리소스는 CDN 사용: 이미지, CSS, JS 파일을 public/ 디렉터리에 두면 SSR을 거치지 않고 자동으로 CDN을 사용합니다.
  4. 캐시 전략: 뉴스 목록처럼 자주 바뀌지 않는 동적 콘텐츠에는 캐시 또는 ISR을 사용해 서버 부담을 줄입니다.
  5. 환경 변수 분리: 민감한 정보에는 서버 환경 변수를 사용하고 공개 설정에는 PUBLIC_ 접두사를 붙입니다.
  6. 성능 모니터링: Vercel Analytics 또는 Google Analytics로 SSR 페이지 응답 시간을 확인하고 제때 최적화합니다.

결론

많은 내용을 설명했지만 핵심은 세 문장으로 정리할 수 있습니다.

1. SSR은 만능이 아니며 필요할 때만 사용해야 합니다

SSR이라는 말에 무조건 들뜨거나 SSG가 낡았다고 생각하지 마세요. 정적 페이지에는 SSG, 동적 페이지에는 SSR을 사용하고 대부분의 프로젝트에는 Hybrid 모드가 가장 적합합니다. 블로그 전체를 SSR로 바꿨다가 오히려 성능이 떨어진 사례도 봤습니다. 블로그 글은 내용이 변하지 않으므로 SSG로 만들어 CDN을 사용하는 편이 더 빠릅니다.

2. 배포 플랫폼에 맞춰 어댑터를 고르면 되며 설정은 매우 간단합니다

Vercel, Netlify, Cloudflare를 사용한다면 npx astro add [platform] 한 줄이면 됩니다. 자체 서버를 사용한다면 npx astro add node도 5분이면 충분합니다. 문서가 복잡해 보여도 실제 작업은 생각보다 훨씬 간단합니다.

3. Hybrid 모드로 두 가지 장점을 모두 얻을 수 있습니다

이것이 Astro의 핵심입니다. 정적 페이지는 Lighthouse 95점 이상을 유지하고 동적 페이지에는 개인화 기능을 구현할 수 있습니다. 빌드 시간은 늘지 않고 서버 비용도 급증하지 않습니다. 저는 요즘 프로젝트를 시작할 때 Hybrid 모드를 가장 먼저 선택합니다.

다음 단계

이 글을 읽었다면 이제 다음 작업을 해 볼 수 있습니다.

  1. 바로 시도하기: Astro 프로젝트를 열고 npx astro add node를 실행해 5분 안에 SSR을 경험해 보세요.
  2. 요구 사항 생각하기: 프로젝트에서 동적 렌더링이 필요한 페이지와 정적으로 유지할 수 있는 페이지를 나열해 보세요.
  3. 더 깊이 배우기: Astro가 최근 선보인 Server Islands(서버 아일랜드) 기능을 사용하면 SSG 페이지에 SSR 컴포넌트를 삽입할 수 있어 더 유연합니다.

설정 중 문제가 생기면 Astro 공식 Discord 커뮤니티에 질문해 보세요. 답변이 매우 빠르고 커뮤니티 분위기도 좋습니다.

마지막으로 한 번 더 강조합니다. 과도하게 최적화하지 마세요. 사이트 트래픽이 많지 않다면(일일 PV 1만 미만) 정적 사이트만으로도 충분하며 SSR을 도입해 복잡도를 높일 필요가 없습니다. 기술 선택은 비즈니스를 위한 것이어야 하며 기술 자체가 목적이 되어서는 안 됩니다.

설정이 순조롭게 끝나기를 바랍니다. 궁금한 점이 있다면 댓글로 함께 이야기해 주세요!

Astro SSR 설정 완전 가이드: 3단계로 서버 사이드 렌더링 활성화하기

SSR과 SSG의 차이를 이해하는 것부터 Vercel, Netlify, Node.js 어댑터 설정과 Hybrid 혼합 전략까지 30분 안에 익힙니다.

⏱️ Estimated time: 30 min

  1. 1

    Step 1: SSR과 SSG 이해하기: SSR은 언제 필요한가

    판단 기준:

    SSG(정적 사이트 생성)
    • 콘텐츠가 빌드 시점에 이미 정해짐
    • 블로그 글, 제품 소개 페이지, 회사 소개
    • 거의 변하지 않는 콘텐츠에는 SSG가 적합함

    SSR(서버 사이드 렌더링)
    • 방문할 때마다 바뀔 수 있음
    • 로그인 후 표시되는 '다시 오신 것을 환영합니다, 홍길동 님'
    • 실시간 주가, 장바구니 상품 수
    • 사용자마다 보이는 내용이 다르므로 SSR이 필요함

    SSR이 꼭 필요한 5가지 상황:

    1. 사용자 인증과 개인화 콘텐츠
    • 대표적인 사례는 로그인
    • 빌드 시점에는 누가 로그인하고 어떤 사용자 이름을 표시할지 알 수 없음
    • 예를 들어 학습 플랫폼 홈에서 '이어서 학습: 5강'을 표시해야 함
    • 로그인한 사용자의 학습 진도에 따라 동적으로 생성하려면 SSR이 필요함

    2. 실시간 데이터 표시
    • 일기예보, 주가, 스포츠 경기 점수
    • 이런 데이터는 매분 바뀜
    • 사이트를 매분 다시 빌드할 수는 없음
    • SSR을 사용하면 사용자가 방문할 때마다 최신 데이터를 가져옴

    3. 데이터베이스 조회
    • 전자상거래 사이트의 상품 검색
    • 검색어마다 결과가 다름
    • 가능한 모든 검색 결과 페이지를 미리 만들 수 없음
    • SSR을 사용해 검색 시 실시간으로 데이터베이스를 조회하고 결과를 반환함

    4. API 라우트
    • 폼 제출, 파일 업로드, 서드파티 API 호출
    • 모두 백엔드 로직이 필요함
    • Astro SSR 모드에서는 src/pages/api/xxx.js API 라우트를 만들 수 있음
    • 별도의 백엔드 서버를 구축하지 않아도 됨

    5. A/B 테스트와 개인화 추천
    • 사용자의 위치, 방문 시간, 과거 행동에 따라 다른 콘텐츠를 표시함
    • 예를 들어 Taobao 홈의 추천 상품은 사용자마다 다름
    • 이런 개인화에는 SSR이 필요함
  2. 2

    Step 2: 3단계로 SSR 활성화하기: 어댑터 설치와 설정

    1단계: 어댑터 설치

    Vercel 어댑터:
    • 실행: npx astro add vercel
    • Vercel 배포에 적합

    Netlify 어댑터:
    • 실행: npx astro add netlify
    • Netlify 배포에 적합

    Node.js 어댑터:
    • 실행: npx astro add node
    • 자체 서버 또는 Docker 배포에 적합

    2단계: astro.config.mjs 설정
    • output: 'server' 추가(SSR 모드 활성화)
    • 어댑터 설정 추가:
    import vercel from '@astrojs/vercel/serverless';
    export default {
    output: 'server',
    adapter: vercel()
    }

    3단계: 해당 플랫폼에 배포

    Vercel:
    • GitHub 저장소 연결
    • Vercel이 Astro SSR 설정을 자동 감지
    • 한 번에 배포

    Netlify:
    • GitHub 저장소 연결
    • Netlify에서 functions 디렉터리 설정 필요
    • 자동 배포

    Node.js:
    • npm run build로 dist 폴더 생성
    • node dist/server/entry.mjs로 서버 시작
    • 또는 Docker로 배포
  3. 3

    Step 3: Hybrid 혼합 모드: SSR과 SSG 함께 사용하기

    Hybrid 모드의 장점:
    • 한 프로젝트에서 SSR과 SSG를 함께 사용할 수 있음
    • 정적 페이지는 SSG 사용(블로그 글, Lighthouse 95점 이상 유지, CDN이 더 빠름)
    • 동적 페이지는 SSR 사용(사용자 센터, 개인화 기능 구현)
    • 빌드 시간이 늘지 않고 서버 비용도 급증하지 않음

    Hybrid 모드 설정:
    • astro.config.mjs에서 output: 'hybrid' 설정
    • 페이지 frontmatter에서 prerender: true/false로 제어
    - 정적 페이지는 prerender: true
    - 동적 페이지는 prerender: false 또는 설정하지 않음

    모범 사례:

    Hybrid 모드를 기본값으로 사용
    • 모든 페이지에 SSR이 필요한 경우가 아니라면 output: 'hybrid'가 가장 좋은 선택

    필요할 때만 SSR 활성화
    • 동적 렌더링이 꼭 필요한 페이지에만 prerender = false 설정

    정적 리소스는 CDN 사용
    • 이미지, CSS, JS 파일은 public/ 디렉터리에 배치
    • SSR을 거치지 않고 자동으로 CDN 사용

    캐시 전략
    • 뉴스 목록처럼 자주 바뀌지 않는 동적 콘텐츠는 캐시 또는 ISR로 서버 부담을 줄임

FAQ

SSG 대신 SSR은 언제 필요한가요?
판단 기준:
• 빌드할 때 이미 정해지는 콘텐츠에는 SSG를 사용합니다. 블로그 글, 제품 소개 페이지, 회사 소개처럼 거의 변하지 않는 콘텐츠에 적합합니다.
• 방문할 때마다 바뀔 수 있는 콘텐츠에는 SSR을 사용합니다. 로그인 후 보이는 '다시 오신 것을 환영합니다, 홍길동 님', 실시간 주가, 장바구니 상품 수처럼 사용자마다 다른 콘텐츠에는 SSR이 필요합니다.

SSR이 꼭 필요한 5가지 상황:

1) 사용자 인증과 개인화 콘텐츠:
• 대표적인 사례는 로그인입니다. 빌드 시점에는 누가 로그인하고 어떤 사용자 이름을 표시할지 알 수 없습니다.
• 예를 들어 학습 플랫폼 홈에 '이어서 학습: 5강'을 표시하려면 로그인 사용자의 학습 진도에 따라 SSR로 동적 생성해야 합니다.

2) 실시간 데이터 표시:
• 일기예보, 주가, 스포츠 경기 점수는 매분 바뀝니다.
• 사이트를 매분 다시 빌드할 수는 없으므로 SSR로 방문할 때마다 최신 데이터를 가져옵니다.

3) 데이터베이스 조회:
• 전자상거래 상품 검색은 검색어마다 결과가 다릅니다.
• 가능한 모든 결과 페이지를 미리 만들 수 없으므로 검색 시 SSR로 데이터베이스를 조회하고 결과를 반환합니다.

4) API 라우트:
• 폼 제출, 파일 업로드, 서드파티 API 호출에는 백엔드 로직이 필요합니다.
• Astro SSR 모드에서는 src/pages/api/xxx.js API 라우트를 만들 수 있어 별도의 백엔드 서버가 필요하지 않습니다.

5) A/B 테스트와 개인화 추천:
• 사용자 위치, 방문 시간, 과거 행동에 따라 다른 콘텐츠를 표시합니다.
• 예를 들어 Taobao 홈의 추천 상품은 사용자마다 다르므로 이런 개인화에는 SSR이 필요합니다.
Astro SSR은 어떻게 설정하나요? 구체적인 단계가 궁금합니다.
SSR 활성화 3단계:

1단계, 어댑터 설치:
• Vercel 어댑터: npx astro add vercel 실행, Vercel 배포에 적합
• Netlify 어댑터: npx astro add netlify 실행, Netlify 배포에 적합
• Node.js 어댑터: npx astro add node 실행, 자체 서버 또는 Docker 배포에 적합

2단계, astro.config.mjs 설정:
• output: 'server'를 추가해 SSR 모드 활성화
• 어댑터 설정 추가:
import vercel from '@astrojs/vercel/serverless';
export default { output: 'server', adapter: vercel() }

3단계, 해당 플랫폼에 배포:
• Vercel: GitHub 저장소를 연결하면 Vercel이 Astro SSR 설정을 자동 감지하고 배포합니다.
• Netlify: GitHub 저장소를 연결하고 functions 디렉터리를 설정하면 자동 배포됩니다.
• Node.js: npm run build로 dist 폴더를 만들고 node dist/server/entry.mjs로 서버를 시작하거나 Docker로 배포합니다.
Vercel, Netlify, Node.js 어댑터는 어떻게 선택하며 어떤 차이가 있나요?
어댑터 선택:

Vercel 어댑터:
• @astrojs/vercel/serverless, Vercel 배포에 적합
• npx astro add vercel 실행
• GitHub 저장소를 연결하면 Vercel이 Astro SSR 설정을 자동 감지하고 한 번에 배포

Netlify 어댑터:
• @astrojs/netlify/functions, Netlify 배포에 적합
• npx astro add netlify 실행
• GitHub 저장소를 연결하고 functions 디렉터리를 설정하면 자동 배포

Node.js 어댑터:
• @astrojs/node, 자체 서버 또는 Docker 배포에 적합
• npx astro add node 실행
• npm run build로 dist 폴더를 만들고 node dist/server/entry.mjs로 서버 시작

선택 팁: Vercel, Netlify, Cloudflare를 사용한다면 npx astro add [platform] 한 줄이면 됩니다. 자체 서버라면 npx astro add node도 5분이면 충분합니다. 문서가 복잡해 보여도 실제 설정은 훨씬 간단합니다.
Hybrid 혼합 모드란 무엇이며 어떻게 설정하나요?
Hybrid 모드의 장점:
• 한 프로젝트에서 SSR과 SSG를 함께 사용할 수 있습니다.
• 정적 페이지는 SSG를 사용해 블로그 글의 Lighthouse 95점 이상을 유지하고 빠른 CDN을 활용합니다.
• 동적 페이지는 SSR을 사용해 사용자 센터의 개인화 기능을 구현합니다.
• 빌드 시간이 늘지 않고 서버 비용도 급증하지 않습니다.

Hybrid 모드 설정:
• astro.config.mjs에서 output: 'hybrid' 설정
• 페이지 frontmatter에서 prerender: true/false로 제어
- 정적 페이지는 prerender: true
- 동적 페이지는 prerender: false 또는 설정하지 않음

모범 사례:
• 모든 페이지에 SSR이 필요한 경우가 아니라면 Hybrid 모드를 기본값으로 사용합니다.
• 동적 렌더링이 꼭 필요한 페이지에만 prerender = false를 설정합니다.
• 이미지, CSS, JS 파일은 public/ 디렉터리에 두어 SSR을 거치지 않고 CDN을 사용합니다.
• 뉴스 목록처럼 자주 바뀌지 않는 동적 콘텐츠에는 캐시 또는 ISR을 사용해 서버 부담을 줄입니다.

이것이 Astro의 핵심입니다. 정적 페이지는 Lighthouse 95점 이상을 유지하고 동적 페이지에는 개인화 기능을 구현할 수 있습니다.
SSR이 성능에 영향을 주나요? SSR이 필요하지 않은 때는 언제인가요?
SSR의 성능 영향:
• 요청할 때마다 서버에서 렌더링하므로 SSR은 SSG보다 다소 느립니다.
• 하지만 현대적인 서버와 CDN은 충분히 빠르므로 대부분의 애플리케이션에서는 성능 차이를 받아들일 만합니다.

과도하게 최적화하지 마세요:
• 사이트 트래픽이 많지 않다면(일일 PV 1만 미만) 정적 사이트만으로도 충분합니다.
• 복잡도를 높이면서까지 SSR을 도입할 필요가 없습니다.
• 기술 선택은 비즈니스를 위한 것이어야 하며, 기술 자체가 목적이 되어서는 안 됩니다.

SSR은 만능이 아니므로 필요할 때만 사용해야 합니다. SSR이라는 말에 무조건 들뜨거나 SSG가 낡았다고 생각하지 마세요. 정적 페이지에는 SSG, 동적 페이지에는 SSR을 사용하고 대부분의 프로젝트에는 Hybrid 모드가 가장 적합합니다.

블로그 전체를 SSR로 바꿨다가 오히려 성능이 떨어진 사례도 봤습니다. 블로그 글은 내용이 변하지 않으므로 SSG로 만들어 CDN을 사용하는 편이 더 빠릅니다.

4분 읽기 · 게시일: 2025년 12월 2일 · 수정일: 2026년 9월 4일

댓글

GitHub로 로그인하여 댓글을 남기세요

Easton BlogEaston Blog