Cloudflare Workers 로 Next.js 정적 배포

Next.js 정적 내보내기 결과물인 out 폴더를 Cloudflare Workers 정적 자산으로 올리면 서버 없이 사용자 지정 도메인과 301 이동까지 Worker 하나로 처리합니다.

Cloudflare 에 Next.js 정적 배포를 할 때 Cloudflare 는 새 프로젝트에 Pages 대신 Workers 정적 자산을 권장합니다. Pages 도 계속 동작하지만 새 기능은 Workers 에 먼저 들어갑니다. 절차는 output: "export" 로 만든 out/ 폴더를 wrangler deploy 로 올리는 것이 전부입니다.

시작하기 전에

항목조건
Next.js요청 시점에 서버가 필요한 기능을 쓰지 않는 사이트. 미들웨어, ISR, next.config 의 rewrites redirects headers, 기본 이미지 최적화는 정적 내보내기에서 동작하지 않음
Cloudflare사용할 도메인이 Cloudflare 에 연결된 계정
Wrangler4.x. npm i -D wrangler 로 설치하고 npx wrangler login 으로 로그인

정적 내보내기 설정

Next.js 정적 배포를 하려면 next.config.mjs 의 output 을 "export" 로 설정합니다.

예제: 정적 내보내기
next.config.mjs
const config = {
  output: "export",
};

export default config;

next build 를 실행하면 화면마다 HTML 파일이 out/ 에 생깁니다. /about 화면은 out/about.html 이 됩니다.

Wrangler 설정

out/ 을 정적 자산으로 올리려면 wrangler.jsonc 의 assets.directory 를 ./out 으로 지정합니다. 아래 예제는 graphite.is 의 설정에서 제외 패턴 일부를 줄였습니다.

예제: Workers 정적 자산
wrangler.jsonc
{
  "name": "graphite",
  "compatibility_date": "2026-10-19",
  "main": "worker/redirect.js",
  "routes": [
    { "pattern": "graphite.is", "custom_domain": true },
    { "pattern": "www.graphite.is", "custom_domain": true }
  ],
  "workers_dev": false,
  "preview_urls": false,
  "assets": {
    "directory": "./out",
    "binding": "ASSETS",
    "not_found_handling": "404-page",
    "html_handling": "auto-trailing-slash",
    "run_worker_first": ["/*", "!/_next/*", "!/*.png", "!/*.xml"]
  }
}
이름설명
assets.directory올릴 폴더. Next.js 정적 내보내기 결과인 ./out
assets.not_found_handling404-page 는 없는 주소에 404.html 을 404 상태로 응답
assets.html_handlingauto-trailing-slash 는 /about 요청에 about.html 을 응답
main, assets.binding301 이동이나 API 를 Worker 코드로 처리할 때만 지정. 순수 정적 사이트는 생략
routes 의 custom_domain사용자 지정 도메인 연결. DNS 레코드와 인증서를 Cloudflare 가 만듦
workers_dev, preview_urls*.workers.dev 주소와 미리보기 주소의 사용 여부

배포

빌드와 업로드를 한 번에 하려면 package.json 에 배포 스크립트를 추가합니다.

예제: 배포 스크립트
package.json
{
  "scripts": {
    "deploy": "next build && wrangler deploy"
  }
}
터미널
npm run deploy

배포가 끝나면 연결된 도메인과 버전 ID 가 출력됩니다.

출력
Deployed graphite triggers
  graphite.is (custom domain)
  www.graphite.is (custom domain)
Current Version ID: 44c6a94f-c07c-40ed-83d7-9bb07aa21e00

요청 비용

정적 자산 요청은 무료이고 횟수 제한이 없습니다. Worker 스크립트를 거치는 요청만 Workers 요금 기준으로 계산합니다.

run_worker_first 에 /* 를 넣으면 모든 요청이 Worker 를 먼저 거칩니다. 스크립트, 이미지, 데이터 파일처럼 Worker 가 손댈 필요 없는 요청은 ! 로 시작하는 제외 패턴으로 빼서 정적 자산으로 바로 응답하게 합니다. 무료 요금제에서 한도를 넘으면 Worker 를 거치는 요청은 정적 자산으로 대신 응답하지 않고 429 를 돌려줍니다. 제외 패턴으로 뺀 요청은 이 영향을 받지 않습니다.

실무 메모

graphite.is 를 배포하면서 확인한 내용입니다.

  • Pages 에서 Workers 로 이전: 2026-10-23 에 Pages 로 처음 설정했다가 같은 날 Workers 정적 자산으로 옮겼습니다. next.config 는 그대로 두고 wrangler.jsonc 만 추가했습니다.
  • 301 이동은 Worker 에서 처리: next.config 의 redirects 는 정적 내보내기에서 동작하지 않습니다. www.graphite.is 와 *.workers.dev 요청을 graphite.is 로, 이전 /blog/… 주소를 /posts/… 로 보내는 일은 worker/redirect.js 가 맡습니다.
  • workers.dev 주소가 로그인을 우회함: 비공개 화면을 Cloudflare Access 로 막았는데, Access 앱의 대상 주소가 graphite.is 라서 *.workers.dev 주소의 같은 파일은 로그인 없이 열렸습니다. workers_dev 와 preview_urls 를 false 로 두어 두 주소를 껐습니다.
  • 방문자 수는 D1 하나로 집계: 같은 Worker 의 /api/visit 이 D1 에 날짜별 합계만 저장합니다. 정적 사이트에 작은 API 하나를 붙일 때 별도 서버가 필요 없습니다.

더 보기