📚 목차
[Next.js] Next.js를 Vercel에 배포하면 HTML은 어디서 만들어질까?
Next.js를 공부하다 보면 SSR, SSG, ISR, CDN, Route Handler, Middleware 같은 용어를 자주 만나게 된다.
개념만 보면 어느 정도 이해할 수 있다.
- SSG는 빌드 시점에 HTML을 만든다.
- SSR은 요청 시점에 HTML을 만든다.
- ISR은 정적 HTML을 캐싱하다가 필요할 때 다시 생성한다.
- Route Handler는 서버 측 API 로직을 처리한다.
그런데 실제로 Vercel에 배포하고 나면 이런 질문이 생긴다.
- SSG로 만든 HTML은 어디에 저장될까?
- SSR은 Vercel의 어디에서 실행될까?
- Route Handler는 브라우저 코드일까, 서버 코드일까?
- CDN은 JS/CSS만 캐싱할까, HTML도 캐싱할까?
이 질문에 답하려면 Next.js의 렌더링 방식을 배포 인프라 관점에서 이해해야 한다.
핵심은 단순하다.
Next.js 앱은 Vercel 위에서 하나의 서버로만 동작하지 않는다. 정적 자산은 CDN에서, 동적 렌더링은 Function에서, 요청 제어는 Edge에서, 데이터는 외부 DB/API에서 처리된다.
이 글에서는 Next.js를 Vercel에 배포했을 때 실제 요청이 어떻게 흐르고, SSR, SSG, ISR, Route Handler, CDN이 각각 어디서 동작하는지 정리해본다.
1. 왜 많은 Next.js 프로젝트는 Vercel을 선택할까?
Next.js는 Vercel이 아니어도 배포할 수 있다.
AWS, GCP, Azure, Docker 기반 서버, Kubernetes, Netlify, Cloudflare 등 다양한 선택지가 있다.
그럼에도 많은 Next.js 프로젝트가 Vercel을 선택하는 이유는 단순히 배포가 쉽기 때문만은 아니다.
더 중요한 이유는 Next.js가 필요로 하는 인프라 요소들이 Vercel에 기본 내장되어 있고, Next.js의 기능과 자동으로 연결되기 때문이다.
Next.js 앱을 제대로 운영하려면 생각보다 많은 요소가 필요하다.
예를 들어, Next.js 운영에 필요한 요소는 아래와 같다.
- Build System
- CDN
- Edge Network
- Serverless Function
- Edge Runtime
- Cache Layer
- ISR Revalidation
- Image Optimization
- Environment Variables
- Preview Deployment
- Middleware Routing
- Custom Domain / HTTPS
Vercel은 이 요소들을 플랫폼 차원에서 기본 제공한다.
예를 들어 Next.js에서 SSG 페이지를 만들면 Vercel은 이를 정적 HTML로 판단하고 CDN에 배포한다.
SSR 페이지나 Route Handler를 만들면 Vercel Function으로 자동 분리한다.
ISR을 사용하면 HTML 캐시와 재검증 로직을 플랫폼 캐싱 계층과 연결한다.
Middleware를 사용하면 요청 초기에 Edge에서 실행되도록 연결한다.
즉 개발자는 Next.js 방식으로 코드를 작성하면 된다.
Next.js 코드 작성
↓
Vercel Build
↓
정적 파일은 CDN
SSR / Route Handler는 Function
Middleware는 Edge
ISR은 CDN Cache + Revalidation이 점이 Vercel의 가장 큰 장점이다.
AWS로 직접 배포하면 무엇이 달라질까?
물론 AWS로도 Next.js를 배포할 수 있다.
오히려 대규모 서비스나 복잡한 보안, 네트워크, 비용 최적화 요구사항이 있다면 AWS를 직접 구성하는 방식이 더 적합할 수도 있다.
하지만 AWS에 직접 배포하면 Vercel이 자동으로 해주던 것들을 대부분 직접 조합해야 한다.
AWS 직접 구성 예시는 아래와 같다.
- S3: Static Assets 저장
- CloudFront: CDN 캐싱
- Lambda: SSR / API 실행
- Lambda@Edge or CloudFront Functions: Edge Middleware
- API Gateway: API 라우팅
- ECS / EC2: Node 서버 실행
- CodePipeline / GitHub Actions: CI/CD
- CloudWatch: 로그와 모니터링
- Route 53: 도메인 연결
- ACM: HTTPS 인증서
- Cache-Control Header: 캐싱 정책 직접 설계
- Image Optimization: 별도 Lambda 또는 이미지 서버 구성
- ISR Revalidation: 직접 구현 또는 별도 어댑터 필요
즉 AWS는 자유도가 높은 대신, 설계하고 운영해야 할 책임도 커진다.
정리를 하면 아래와 같다.
Vercel
- Next.js에 필요한 CDN, Function, Edge, Cache가 기본 내장
- Next.js 코드와 자동 연결
- 빠르게 배포하고 운영하기 좋음
AWS 직접 구성
- 필요한 인프라를 직접 선택하고 조합
- 자유도와 확장성은 높음
- 대신 설계, 운영, 캐싱, 배포 파이프라인 책임이 커짐
즉, Vercel은 Next.js에 최적화된 완성형 배포 플랫폼이기 때문에 인프라에 집중하는 대신 비즈니스 로직에 더 집중할 수 있다는 것이 큰 장점이다.
2. 전체 구조 - Vercel은 요청을 어떻게 나눠 처리할까?
Next.js 프로젝트를 Vercel에 배포하면, 결과물이 하나의 서버에 통째로 올라가는 것이 아니다.
빌드 단계에서 결과물이 성격에 따라 나뉜다.
Vercel Build Output
- Static Assets
- JS / CSS / Fonts / Images
- Pre-rendered HTML
- SSG HTML / ISR Initial HTML
- Serverless Functions
- SSR / Route Handler / BFF
- Cache Metadata
- revalidate, cache policy, route config
그리고 사용자의 요청은 먼저 Vercel Edge Network / CDN 으로 들어간다.
Browser
↓
Vercel Edge Network / CDN
↓
요청 종류 판단
↓
Static / SSG / ISR / SSR / Route Handler로 분기이때 Vercel은 요청을 보고 다음처럼 처리한다.

즉 Vercel은 단순한 정적 호스팅 서버가 아닌,
Build System, Serverless Functions, Edge Middleware, Cache Layer, Image Optimization 등이 기본적으로 통합된 배포 플랫폼이라고 볼 수 있다.
Next.js 코드가 어떤 렌더링 전략을 사용하는지에 따라, Vercel은 해당 결과물을 적절한 인프라 계층으로 자동 배치한다.
3. SSG와 Static Assets - 미리 만든 결과물은 CDN에서 바로 나간다
가장 단순한 경우는 정적 파일과 SSG 페이지다.
정적 파일은 예를 들어 다음과 같다.
- JS bundle
- CSS
- Fonts
- public image
- favicon
SSG 페이지는 소개페이지, 랜딩페이지, 블로그 글 같은 화면에 적합하다. 이들은 배포 시점에 미리 만들어진다.
흐름은 아래와 같다.
Developer
↓
GitHub Push
↓
Vercel Build
↓
HTML / JS / CSS 생성
↓
Vercel CDN에 배포
↓
사용자 요청 시 CDN에서 바로 응답SSG 페이지는 사용자가 요청할 때 서버에서 HTML을 새로 만들지 않는다.
이미 빌드 시점에 만들어진 HTML이 있고, 그 결과물이 CDN에 캐싱되어 있다.
따라서 사용자가 /about, /posts/nextjs-vercel 같은 페이지에 접근하면 Vercel Function을 실행하지 않고 CDN에서 HTML을 바로 내려줄 수 있다.
정적 자산도 마찬가지다.
/_next/static/chunks/main-a1b2c3.js
/_next/static/css/app-f9e8d7.css
/logo.png
/favicon.ico이런 파일들은 CDN에서 바로 응답된다. 여기서 중요한 점은 main-a1b2c3.js, app-f9e8d7.css와 같이 파일명에 hash가 붙는다는 것이다.
파일 내용이 바뀌면 hash도 바뀐다.
그래서 브라우저와 CDN은 기존 파일과 새 파일을 구분할 수 있고, 변경되지 않은 파일은 오래 캐싱할 수 있다.
정리를 하면,
SSG와 Static Assets는 빌드 시점에 만들어지고, 사용자 요청 시 CDN에서 바로 응답된다.
4. SSR과 Route Handler: 요청마다 필요한 로직은 Vercel Function에서 실행된다
반대로 요청마다 계산이 필요한 경우도 있다.
예를 들어 로그인한 사용자별 마이페이지, 항상 최신 데이터가 필요한 화면, 요청마다 권한이 달라지는 페이지 등은 미리 HTML을 만들어두기 어렵다.
이런 경우 SSR을 사용한다.
SSR 흐름은 다음과 같다.

즉 SSR의 HTML은 CDN에 미리 저장되어 있는 파일이 아니다.
요청이 들어온 시점에 Vercel Function이 실행되고, 그 안에서 데이터를 가져온 뒤 HTML을 생성한다.
Route Handler도 같은 관점에서 이해할 수 있다.
App Router에서는 다음과 같은 API를 만들 수 있다.
// app/api/user/route.ts
export async function GET() {
const res = await fetch('https://backend.example.com/user', {
headers: {
Authorization: `Bearer ${process.env.API_SECRET}`,
},
});
const user = await res.json();
return Response.json(user);
}이 코드는 브라우저 번들에 포함되는 코드가 아니다.
Vercel에 배포되면 서버에서 실행되는 Function으로 분리된다.
요청 흐름은 다음과 같다.

그래서 Route Handler는 BFF 계층으로도 활용할 수 있다.
BFF는 Backend for Frontend의 약자로, 프론트엔드를 위한 백엔드 계층이다.
즉,
SSR과 Route Handler는 정적 파일처럼 CDN에서 바로 나가는 것이 아니라, Vercel Function에서 실행된다.
5. ISR: CDN의 속도와 서버 재생성을 함께 사용한다
ISR은 SSG와 SSR의 중간에 있는 방식이다.
SSG처럼 HTML을 캐싱해서 빠르게 응답하지만, 일정 시간이 지나면 다시 생성할 수 있다.
예를 들어 상품 목록 페이지를 생각해보자.
이 페이지는 빠르게 떠야 한다. 하지만 상품 정보가 하루에도 몇 번씩 바뀔 수 있다.
매 요청마다 SSR을 하면 서버 비용이 커질 수 있고, 완전 SSG로 만들면 데이터가 오래될 수 있는데, 이럴 때 ISR이 잘 맞는다.
ISR의 흐름은 다음과 같다.

즉 사용자는 대부분의 경우 CDN에 캐시된 HTML을 빠르게 받는다.
그리고 캐시가 오래되었을 때만 Function이 개입해서 새 HTML을 만든다.
상품 목록, 여행 정보, 공지사항 등과 같은 페이지에 적합하다.
즉,
ISR은 CDN에서 빠르게 응답하되, 정해진 조건에 따라 Function이 HTML을 다시 생성하는 방식이다.
6. Middleware, Server Component, Client Component는 어디서 동작할까?
Next.js App Router를 쓰면 Middleware, Server Component, Client Component도 함께 이해해야 한다.
먼저 Middleware는 요청이 실제 페이지나 API로 가기 전에 실행된다.
Browser Request
↓
Vercel Edge / Middleware
↓
redirect / rewrite / next 결정
↓
CDN 응답 또는 Function 실행예를 들어 로그인 여부 검사, locale redirect 등과 같은 작업에 사용된다.
즉 Middleware는 페이지 렌더링 로직이라기보다는, 요청을 어디로 보낼지 먼저 판단하는 Edge Logic에 가깝다.
다음은 Server Component다.
Server Component는 이름 그대로 브라우저에서 실행되지 않는다.
다만 중요한 점은 실행 위치는 서버지만, 실행 시점은 렌더링 전략에 따라 다르다는 것이다.
-
SSG 페이지의 Server Component
- 빌드 시점에 실행
-
SSR 페이지의 Server Component
- 요청 시점에 Function에서 실행
-
ISR 페이지의 Server Component
- 초기 생성 또는 재검증 시점에 실행
즉 Server Component라고 해서 항상 요청마다 실행되는 것은 아니다.
반대로 Client Component는 브라우저에서 실행된다.
'use client';
export default function Button() {
return <button onClick={() => alert('click')}>Click</button>;
}이런 코드는 빌드 시 JS bundle에 포함된다.
Vercel Build
↓
Client Component JS Bundle 생성
↓
CDN에서 JS 다운로드
↓
Browser에서 hydration / interaction 실행정리하면 다음과 같다.
- Middleware
- 요청 초기에 Edge에서 실행
- Server Component
- 서버에서 실행되지만, 실행 시점은 SSG/SSR/ISR에 따라 다름
- Client Component
- JS bundle로 내려가 브라우저에서 실행
전체 요청 흐름 정리
마지막으로 전체 구조를 요청 기준으로 다시 정리해보자.

| 종류 | 생성 시점 | 응답 위치 |
|---|---|---|
| Static Assets | Build Time | CDN |
| SSG HTML | Build Time | CDN |
| ISR HTML | Build / Revalidate Time | CDN + Function |
| SSR HTML | Request Time | Vercel Function |
| Route Handler | Request Time | Vercel Function |
| BFF | Request Time | Vercel Function |
| Middleware | Request Start | Edge |
| Client Component JS | Build Time | CDN → Browser |
| Server Component | Build / Request / Revalidate | 렌더링 전략에 따라 다름 |
Next.js를 Vercel에 배포하면, 정적인 것은 CDN에서 빠르게 응답하고, 동적인 것은 Function에서 실행하며, 그 사이에 ISR과 Cache Layer가 성능과 최신성의 균형을 잡는다.
마무리
Next.js의 SSR, SSG, ISR을 개념으로만 공부하면 각각의 차이는 알 수 있다.
하지만 실제 배포 환경에서 어떻게 동작하는지까지 이해해야 성능 최적화나 아키텍처 설계 판단을 제대로 할 수 있다.
Vercel에 배포된 Next.js 앱은 단순히 하나의 Node 서버에서 모든 요청을 처리하는 구조가 아니다.
- 정적 자산과 SSG HTML은 CDN
- SSR과 Route Handler는 Function
- ISR은 CDN Cache와 Function 재생성
- Middleware는 Edge
- 데이터는 외부 DB/API
이렇게 역할이 분리되어 있다.
SSG, SSR, ISR, Route Handler를 단순히 기능으로 고르는 것이 아니라 성능, 보안, 비용, 유지보수 관점에서 적절한 아키텍처로 선택할 수 있다.
결국 Next.js on Vercel의 핵심은 다음과 같다.
정적 결과물은 CDN에, 동적 로직은 Function에, 요청 제어는 Edge에, 데이터는 외부 저장소에 배치하는 구조다.
이 구조를 이해하면 Next.js의 렌더링 전략은 더 이상 추상적인 개념이 아니라, 실제 서비스의 응답 경로를 설계하는 도구가 된다.