테마 전환

Cloudflare Pages 프런트엔드 앱 배포 완벽 가이드: React/Vue/Next.js 설정과 오류 해결

Easton editorial illustration: orchestration hub with branches

들어가며

React 프로젝트를 완성해 인터넷에 배포하려고 Cloudflare Pages 설정 화면을 열었는데, “Build Command”와 “Build Output Directory” 두 입력란을 보고 한참 멈춰 있었던 적이 있습니다. Build Command에는 npm run buildnpm build 중 무엇을 넣어야 할까요? Output Directory는 build일까요, dist일까요? 환경 변수는 어떻게 설정해야 할까요?

이 글에서는 React, Vue, Next.js 프로젝트를 Cloudflare Pages에 배포하는 과정을 단계별로 안내합니다. 전체 설정 목록과 환경 변수 설정 방법, 자주 발생하는 오류 5가지의 해결 방법을 다루며, 특히 Next.js의 nodejs_compat 오류를 자세히 설명합니다.


Cloudflare Pages를 선택한 이유

이미 Vercel과 Netlify가 있는데 왜 Cloudflare Pages를 써야 하는지 궁금할 수 있습니다.

저도 처음에는 Vercel을 사용했습니다. Vercel이 나쁜 것은 아니지만 무료 플랜에는 분명 제약이 있습니다. 작은 프로젝트 몇 개를 운영했더니 합산 트래픽이 한 달에 100GB를 넘어 Vercel에서 속도 제한이 걸리기 시작했습니다.

세 플랫폼을 비교해 보니 Cloudflare Pages의 무료 플랜이 꽤 매력적이었습니다.

무제한
무료 트래픽
Vercel과 Netlify는 월 100GB
월 500회
빌드 횟수
Vercel은 월 6,000분, Netlify는 월 300분
300개 이상
CDN 노드
전 세계 분산, HTTPS 자동 지원
지원
상업용 프로젝트
Vercel은 제한이 있고 Netlify는 지원

특히 무제한 트래픽이 매력적입니다. 현재 제 개인 프로젝트 몇 개를 모두 CF Pages에 올려 두었고 트래픽을 전혀 걱정하지 않습니다.

Cloudflare Pages에 적합한 경우:

  • 개인 블로그 및 포트폴리오 사이트
  • 중소 규모 프런트엔드 프로젝트(SPA, 정적 사이트)
  • 글로벌 가속이 필요한 프로젝트
  • 트래픽 규모를 예측하기 어려운 프로젝트(무료 무제한 트래픽이 큰 장점)

적합하지 않은 경우:

  • 복잡한 SSR 기능이 필요한 대규모 Next.js 앱(CF Pages의 Next.js 지원은 Vercel만큼 완전하지 않음)
  • 자주 빌드해야 하는 프로젝트(월 500회 빌드 제한)
  • Edge Middleware 등 Vercel 전용 기능이 필요한 프로젝트

배포 전 준비 사항

시작하기 전에 다음을 준비해야 합니다.

  1. Cloudflare 계정 등록
  2. 코드 저장소 준비
    • 코드를 GitHub 또는 GitLab에 푸시합니다.
    • CF Pages가 Git 저장소에서 코드를 직접 가져와 빌드합니다.
  3. 프로젝트 빌드 설정 확인
    • Create React App과 Vite 중 무엇을 사용했는지 확인합니다.
    • 빌드 명령이 무엇인지 확인합니다. 일반적으로 npm run build입니다.
    • 빌드 결과물이 저장되는 디렉터리를 확인합니다. CRA는 build, Vite는 dist입니다.

준비가 끝났다면 실제 배포를 시작해 보겠습니다.


React 앱 배포 전체 과정

React는 가장 많이 사용하는 프런트엔드 프레임워크 중 하나입니다. 저도 여러 React 프로젝트를 CF Pages에 배포하면서 안정적으로 사용할 수 있는 설정 목록을 정리했습니다.

React 프로젝트 빠르게 만들기(프로젝트가 없는 경우)

따라 해 볼 기존 프로젝트가 없다면 다음 명령으로 빠르게 만들 수 있습니다.

# 방법 1: Vite 사용(권장, 빌드가 더 빠름)
npm create vite@latest my-react-app -- --template react
cd my-react-app
npm install
# 방법 2: Create React App 사용(전통적인 방식)
npx create-react-app my-react-app
cd my-react-app

개인적으로는 빌드 속도가 훨씬 빠른 Vite를 권합니다. CRA 프로젝트는 규모가 커지면 빌드가 비교적 느려집니다.

Cloudflare Pages 설정 목록

Cloudflare Dashboard에 로그인해 Pages 화면으로 이동하고 “Create a project” → “Connect to Git”을 클릭한 뒤 GitHub 저장소를 선택합니다.

이후 나타나는 설정 화면이 핵심입니다.

설정 항목 설명:

설정 항목Vite 프로젝트CRA 프로젝트
Framework presetNoneCreate React App
Build commandnpm run buildnpm run build
Build output directorydistbuild
Root directory/(기본값)/(기본값)
Environment variablesVITE_* 접두사REACT_APP_* 접두사

주의 사항:

  • Vite 프로젝트의 Framework preset은 “None”을 선택하면 됩니다. CF Pages가 자동으로 감지합니다.
  • CRA 프로젝트는 “Create React App” 프리셋을 선택하면 설정이 자동으로 입력됩니다.
  • 출력 디렉터리를 가장 자주 혼동합니다. Vite는 dist, CRA는 build이므로 반대로 입력하지 마세요.

환경 변수 설정

React 프로젝트의 환경 변수에는 특별한 규칙이 있습니다. 클라이언트에서 접근하려면 특정 접두사를 반드시 붙여야 합니다.

Vite 프로젝트:

  • 접두사는 반드시 VITE_여야 합니다.
  • 예: VITE_API_URL, VITE_API_KEY

CRA 프로젝트:

  • 접두사는 반드시 REACT_APP_여야 합니다.
  • 예: REACT_APP_API_URL, REACT_APP_API_KEY

설정 방법:

  1. Cloudflare Pages에서 설정(권장):
    • 프로젝트 → Settings → Environment variables로 이동합니다.
    • “Add variable”을 클릭합니다.
    • Production 또는 Preview 환경을 선택합니다.
    • 변수 이름과 값을 입력합니다.
  2. 코드에서 사용:
// Vite 프로젝트
const apiUrl = import.meta.env.VITE_API_URL;
// CRA 프로젝트
const apiUrl = process.env.REACT_APP_API_URL;

로컬 개발 환경 변수:

프로젝트 루트 디렉터리에 .env.local 파일을 만듭니다.

# Vite 프로젝트
VITE_API_URL=https://api.example.com
VITE_API_KEY=your-api-key-here
# CRA 프로젝트
REACT_APP_API_URL=https://api.example.com
REACT_APP_API_KEY=your-api-key-here

중요:

  • .env.local 파일을 Git에 커밋하지 마세요. .gitignore.env*.local을 추가합니다.
  • 환경 변수를 수정한 뒤에는 반드시 다시 배포해야 적용됩니다.

SPA 라우트 404 문제 해결

React Router를 사용하는 React 프로젝트는 배포 후 페이지를 새로 고칠 때 404가 발생할 수 있습니다.

SPA 프로젝트의 모든 라우트가 index.html을 가리켜야 하지만 서버는 기본적으로 해당 경로의 파일을 찾기 때문입니다.

해결 방법:

프로젝트의 public 디렉터리에 _redirects 파일을 만듭니다.

/* /index.html 200

이 한 줄은 모든 경로를 index.html로 리디렉션하고 상태 코드 200을 반환하도록 서버에 지시합니다.

저장하고 다시 배포하면 라우트가 정상적으로 작동합니다.

배포 성공 확인

“Save and Deploy”를 클릭하면 CF Pages가 빌드를 시작합니다. “Deployments” 화면에서 빌드 로그를 볼 수 있습니다.

빌드 성공 여부 확인:

  • 로그에 “Success: Deployed to…”가 표시됩니다.
  • xxx.pages.dev 형식의 접속 링크가 제공됩니다.
  • 링크를 열면 프로젝트가 표시됩니다.

빌드가 실패한 경우:

  • 로그에서 오류 메시지를 확인합니다.
  • 자주 발생하는 원인은 다음과 같습니다.
    • 출력 디렉터리를 잘못 입력함(Vite에 build 또는 CRA에 dist를 입력)
    • Node 버전이 너무 낮음(NODE_VERSION=18 환경 변수 설정 필요)
    • 의존성 설치 실패(package.json 확인)

Vue 앱 배포 전체 과정

Vue 배포는 React와 비슷하지만 몇 가지 세부 사항에 주의해야 합니다.

Vue 프로젝트 빠르게 만들기(선택 사항)

# 방법 1: Vite 사용(권장)
npm create vite@latest my-vue-app -- --template vue
cd my-vue-app
npm install
# 방법 2: Vue CLI 사용
vue create my-vue-app
cd my-vue-app

여기서도 성능이 더 좋은 Vite를 권합니다.

Cloudflare Pages 설정 목록

설정 항목Vite 프로젝트Vue CLI 프로젝트
Framework presetNoneVue
Build commandnpm run buildnpm run build
Build output directorydistdist
Root directory/(기본값)/(기본값)
Environment variablesVITE_* 접두사VUE_APP_* 접두사

핵심:

  • Vue CLI와 Vite의 출력 디렉터리는 모두 dist입니다. React와는 조금 다릅니다.
  • 환경 변수 접두사는 Vite가 VITE_, Vue CLI가 VUE_APP_로 다릅니다.

환경 변수 설정

Vite + Vue 프로젝트:

# .env.local
VITE_API_BASE_URL=https://api.example.com
VITE_APP_TITLE=My Vue App

Vue CLI 프로젝트:

# .env.production
VUE_APP_API_BASE_URL=https://api.example.com
VUE_APP_TITLE=My Vue App

코드에서 사용:

// Vite 프로젝트
const apiUrl = import.meta.env.VITE_API_BASE_URL;
// Vue CLI 프로젝트
const apiUrl = process.env.VUE_APP_API_BASE_URL;

Vue Router 라우트 설정

Vue Router, 특히 History 모드를 사용한다면 새로 고침 시 404가 발생하지 않도록 반드시 리디렉션을 설정해야 합니다.

방법 1: _redirects 파일 사용(권장)

public 디렉터리에 _redirects 파일을 만듭니다.

/* /index.html 200

방법 2: vite.config.js에서 설정(Vite 프로젝트)

루트 디렉터리가 아닌 곳에 프로젝트를 배포한다면 base를 설정해야 합니다.

// vite.config.js
export default {
  base: '/', // 루트 경로인지 확인
}

자주 발생하는 문제 점검

문제 1: 정적 리소스 404

vue.config.js(Vue CLI) 또는 vite.config.js(Vite)의 publicPathbase 설정을 확인합니다.

// vue.config.js (Vue CLI)
module.exports = {
  publicPath: '/', // 루트 경로인지 확인
}

문제 2: Vite 빌드 중 “Unknown file extension” 오류

대개 Node 버전이 너무 낮아서 발생합니다. CF Pages 환경 변수에 다음을 추가합니다.

NODE_VERSION=18

그런 다음 다시 배포합니다.


Next.js 앱 배포 전체 과정(중요)

솔직히 Next.js를 Cloudflare Pages에 배포하는 과정은 이 세 프레임워크 중 가장 복잡합니다. 처음 배포했을 때 nodejs_compat 오류 때문에 오후 내내 막혀 있었고, 여러 자료를 찾아본 뒤에야 해결했습니다.

Next.js 프로젝트에서 SSR 기능을 많이 사용한다면 Vercel을 권합니다. 하지만 정적 사이트나 간단한 SSR이라면 CF Pages로 충분하고 무료 무제한 트래픽도 큰 장점입니다.

Next.js 배포의 특수성

시작하기 전에 몇 가지 중요한 점을 알아야 합니다.

  1. Cloudflare Pages는 Vercel처럼 Next.js 전용 플랫폼이 아니므로 추가 설정이 필요합니다.
  2. 배포 방법은 두 가지입니다. 정적 내보내기가 가장 간단하며 SSR 모드에는 어댑터가 필요합니다.
  3. SSR을 사용하려면 @opennextjs/cloudflare 어댑터가 필요합니다. 기존 @cloudflare/next-on-pages는 더 이상 사용되지 않습니다.

방법 1: 정적 내보내기(가장 간단하며 초보자에게 권장)

Next.js 프로젝트에서 서버 렌더링, API Routes, ISR 등의 기능이 필요하지 않다면 정적 내보내기가 가장 간단합니다.

적합한 경우:

  • 개인 블로그
  • 문서 사이트
  • 단순 정보 제공 사이트
  • 동적 데이터가 필요하지 않은 프로젝트

설정 단계:

  1. next.config.js 수정:
/** @type {import('next').NextConfig} */
const nextConfig = {
  output: 'export', // 핵심: 정적 내보내기 활성화
  images: {
    unoptimized: true, // CF Pages는 Next.js Image Optimization을 지원하지 않음
  },
}
module.exports = nextConfig
  1. Cloudflare Pages 설정:
설정 항목입력 내용
Framework presetNext.js (Static HTML Export)
Build commandnpm run build
Build output directoryout
Root directory/(기본값)
  1. 배포:

설정을 저장하고 바로 배포하면 됩니다. 빌드가 성공하면 정적 사이트가 생성됩니다.

제한 사항:

  • ❌ API Routes 미지원
  • ❌ ISR(Incremental Static Regeneration) 미지원
  • ❌ Server Components 미지원
  • ❌ 동적 라우트의 서버 렌더링 미지원

이러한 제한을 받아들일 수 있다면 정적 내보내기로 충분합니다.

방법 2: SSR 모드(OpenNext 어댑터 사용)

API Routes, SSR, 동적 라우트 등의 기능이 필요하다면 어댑터를 사용해야 합니다. 조금 더 복잡하지만 최대한 명확하게 설명하겠습니다.

어댑터 설치:

npm install @opennextjs/cloudflare

next.config.js 설정:

/** @type {import('next').NextConfig} */
const nextConfig = {
  // output: 'export'를 설정할 필요 없음
  images: {
    unoptimized: true,
  },
}
module.exports = nextConfig

Cloudflare Pages 설정:

설정 항목입력 내용
Framework presetNone
Build commandnpx @opennextjs/cloudflare
Build output directory.worker-next
Root directory/

중요! Compatibility Flags 설정(가장 자주 문제가 발생하는 부분):

이 단계가 매우 중요합니다. 많은 사용자가 여기서 막힙니다. 저도 첫 배포 때 이 설정을 하지 않아 계속 nodejs_compat is not defined 오류가 발생했습니다.

  1. 프로젝트 → SettingsFunctions로 이동합니다.
  2. Compatibility flags 섹션을 찾습니다.
  3. Configure Production compatibility flag를 클릭합니다.
  4. nodejs_compat 플래그를 추가합니다.
  5. Compatibility Date를 최소 2024-09-23 또는 이후 날짜로 설정합니다.

주의:

  • Production과 Preview 환경에 모두 설정해야 합니다.
  • 이 플래그를 설정하지 않으면 배포 후 바로 500 오류가 발생합니다.

Edge Runtime 요구 사항:

API Routes 또는 Server Components를 사용한다면 Edge Runtime 선언을 반드시 추가해야 합니다.

// app/api/hello/route.js
export const runtime = 'edge'; // 핵심! 반드시 추가
export async function GET(request) {
  return new Response(JSON.stringify({ message: 'Hello from CF Pages' }), {
    headers: { 'content-type': 'application/json' },
  });
}
// pages/api/hello.js (Pages Router)
export const config = {
  runtime: 'edge', // 핵심! 반드시 추가
};
export default function handler(req) {
  return new Response(JSON.stringify({ message: 'Hello from CF Pages' }), {
    headers: { 'content-type': 'application/json' },
  });
}

서버에서 실행되는 모든 파일에 이 선언을 추가해야 하며, 누락하면 배포가 실패합니다.

Next.js 환경 변수 설정

Next.js 환경 변수는 두 종류로 나뉩니다.

1. 클라이언트 변수(접두사 필수):

# .env.local
NEXT_PUBLIC_API_URL=https://api.example.com
NEXT_PUBLIC_SITE_NAME=My Next.js Site

2. 서버 변수(접두사 불필요):

# .env.local
DATABASE_URL=postgresql://...
API_SECRET=your-secret-key

Cloudflare Pages에서 설정:

Settings → Environment variables로 이동하고 변수를 추가할 때 Production 또는 Preview 환경을 선택합니다.

코드에서 사용:

// 클라이언트
const apiUrl = process.env.NEXT_PUBLIC_API_URL;
// 서버(API Route 또는 Server Component)
const dbUrl = process.env.DATABASE_URL;

Next.js에서 자주 발생하는 오류와 해결 방법(중요)

제가 직접 겪었던 문제를 바탕으로 가장 흔한 오류 5가지와 해결 방법을 정리했습니다.

오류 1: nodejs_compat is not defined 또는 500 오류

오류 메시지:

Error: The global scope does not support nodejs_compat

또는 배포는 성공했지만 페이지를 열면 500 오류가 발생합니다.

원인:

nodejs_compat 호환성 플래그가 없습니다.

해결 방법:

  1. 프로젝트 → SettingsFunctions로 이동합니다.
  2. Compatibility flags를 찾습니다.
  3. Production과 Preview 환경에 모두 nodejs_compat를 추가합니다.
  4. 다시 배포합니다.

저도 이 문제로 오래 막혔지만 설정을 추가하자 바로 해결되었습니다.

오류 2: 배포는 성공했지만 페이지에 404 표시

증상:

  • 빌드 로그에는 성공으로 표시됩니다.
  • xxx.pages.dev에 접속하면 404가 표시됩니다.
  • 또는 홈페이지만 열리고 다른 페이지는 404가 표시됩니다.

원인:

  • Edge Runtime을 올바르게 설정하지 않았습니다.
  • 또는 Build output directory가 잘못되었습니다.

해결 방법:

  1. 모든 API Routes와 Server Components에 runtime = 'edge'를 추가했는지 확인합니다.
  2. Build output directory가 어댑터 사용 시 .worker-next, 정적 내보내기 시 out인지 확인합니다.
  3. 정적 내보내기라면 _redirects 파일을 만들었는지 확인합니다.

오류 3: FinalizationRegistry is not defined

오류 메시지:

ReferenceError: FinalizationRegistry is not defined

원인:

Compatibility Date가 너무 오래되어 새로운 JavaScript 기능을 지원하지 않습니다.

해결 방법:

  1. Settings → Functions로 이동합니다.
  2. Compatibility Date2024-09-23 또는 이후 날짜로 변경합니다.
  3. 다시 배포합니다.

오류 4: 빌드 시간이 너무 길거나 빌드 실패

증상:

  • 빌드가 10분 넘게 끝나지 않습니다.
  • 또는 “Build exceeded maximum duration”이 표시됩니다.

원인:

  • Turbopack(next dev --turbo)을 사용했습니다.
  • 또는 프로젝트 규모가 크고 의존성이 너무 많습니다.

해결 방법:

  1. Build command가 npx @opennextjs/cloudflare인지 확인하고 --turbo 인수를 사용하지 마세요.
  2. npm prune으로 불필요한 의존성을 정리합니다.
  3. 가능하다면 정적 내보내기 방식을 고려합니다.

오류 5: Image Optimization 오류

오류 메시지:

Error: Image Optimization using Next.js' default loader is not compatible with `output: 'export'`.

원인:

Cloudflare Pages는 Next.js의 Image Optimization API를 지원하지 않습니다.

해결 방법:

next.config.js에서 비활성화합니다.

module.exports = {
  images: {
    unoptimized: true,
  },
}

이미지 최적화가 필요하다면 다음 방법을 사용할 수 있습니다.

  • Cloudflare Images(유료 서비스)
  • Cloudinary 같은 서드파티 CDN
  • 이미지를 직접 압축한 뒤 업로드

환경 변수 관리 심화

저도 처음에는 개발, 미리 보기, 프로덕션 환경을 어떻게 구분해야 할지 몰라 환경 변수 관리가 혼란스러웠습니다. 여러 번 사용하면서 비교적 명확한 관리 방법을 정리했습니다.

세 가지 환경 구분

Cloudflare Pages는 세 가지 환경을 지원합니다.

환경실행 조건용도
Productionmain 같은 기본 브랜치에 푸시사용자가 접속하는 프로덕션 환경
Preview다른 브랜치나 PR에 푸시새 기능을 테스트하는 미리 보기 환경
Development로컬 개발개발자의 컴퓨터에서만 사용하는 개발 환경

Cloudflare Dashboard에서 설정

프로젝트 → SettingsEnvironment variables로 이동합니다.

두 개의 탭이 표시됩니다.

  • Production: 프로덕션 환경 변수
  • Preview: 미리 보기 환경 변수

권장 설정:

  1. 프로덕션 환경 변수(실제 API Key, 데이터베이스 연결 등):
    • Secret 유형을 선택합니다. 값이 암호화되어 저장되고 로그에는 표시되지 않습니다.
    • 예: API_KEY=prod-key-12345
  2. 미리 보기 환경 변수(테스트용 API Key):
    • Plain text를 선택할 수 있습니다.
    • 예: API_KEY=test-key-67890

로컬 개발 환경 변수

권장 파일 구조:

my-project/
├── .env.local          # 로컬 개발 변수(Git에 커밋하지 않음)
├── .env.example        # 변수 템플릿(Git에 커밋)
├── .gitignore          # 민감한 파일 제외

.env.local 예시:

# API 설정
VITE_API_BASE_URL=http://localhost:3000/api
VITE_API_KEY=local-dev-key
# 기능 플래그
VITE_ENABLE_DEBUG=true
VITE_ENABLE_ANALYTICS=false
# 서드파티 서비스
VITE_GOOGLE_ANALYTICS_ID=G-XXXXXXXXXX

.env.example 예시:

# API 설정
VITE_API_BASE_URL=your-api-url-here
VITE_API_KEY=your-api-key-here
# 기능 플래그
VITE_ENABLE_DEBUG=false
VITE_ENABLE_ANALYTICS=true

중요:

  • .env.local은 Git에 커밋하지 마세요.
  • .env.example은 팀원이 참고할 수 있도록 Git에 커밋합니다.
  • .gitignore.env*.local을 추가합니다.

환경 변수 접두사 요약

프레임워크마다 접두사 규칙이 다르므로 빠르게 확인할 수 있도록 표로 정리했습니다.

프레임워크/도구클라이언트 변수 접두사서버 변수 접두사
Vite(모든 프레임워크)VITE_접두사 없음(클라이언트에서는 접근 불가)
Create React AppREACT_APP_서버 변수 없음
Vue CLIVUE_APP_서버 변수 없음
Next.jsNEXT_PUBLIC_접두사 없음

기억할 점:

  • 브라우저에서 접근할 변수에는 반드시 접두사가 있어야 합니다.
  • API Key나 데이터베이스 비밀번호처럼 서버에서만 사용할 변수에는 접두사가 필요 없습니다.

환경 변수가 적용되지 않을 때 점검 방법

환경 변수를 설정했는데도 적용되지 않는 문제를 여러 번 겪으면서 다음 점검 목록을 정리했습니다.

점검 순서:

  1. 접두사가 올바른지 확인

    • Vite 프로젝트에 REACT_APP_ 접두사를 사용했나요? VITE_를 사용해야 합니다.
    • Next.js 클라이언트 변수에 NEXT_PUBLIC_을 빠뜨렸나요?
  2. 다시 배포했는지 확인

    • 환경 변수를 수정한 뒤에는 새 배포를 시작해야 적용됩니다.
    • Git에 작은 변경을 푸시하거나 Dashboard에서 “Retry deployment”를 클릭할 수 있습니다.
  3. 환경이 올바른지 확인

    • Production 환경을 수정했는데 Preview 링크에 접속한 것은 아닌가요?
    • 또는 그 반대인가요?
  4. 빌드 로그 확인

    • 빌드 로그에서 변수 이름을 검색합니다.
    • 변수가 올바르게 읽혔는지 확인합니다. Secret 유형의 변수 값은 표시되지 않습니다.
  5. 코드의 참조 방식 확인

    // ❌ 잘못된 방식(Vite 프로젝트)
    const apiUrl = process.env.VITE_API_URL;
    // ✅ 올바른 방식(Vite 프로젝트)
    const apiUrl = import.meta.env.VITE_API_URL;

고급 팁과 모범 사례

배포 성공은 첫 단계일 뿐입니다. 다음 고급 팁을 적용하면 프로젝트를 더 전문적으로 운영할 수 있습니다.

사용자 지정 도메인 연결

xxx.pages.dev 도메인보다 자체 도메인이 더 전문적으로 보입니다. 연결 방법은 간단합니다.

단계:

  1. Cloudflare Pages에서 도메인 추가:
    • 프로젝트 → Custom domains로 이동합니다.
    • Set up a custom domain을 클릭합니다.
    • blog.example.com 같은 도메인을 입력합니다.
  2. DNS 레코드 설정:
    • 도메인이 이미 Cloudflare에 등록되어 있다면 CNAME 레코드가 자동으로 추가됩니다.
    • 다른 서비스 업체에서 관리하는 도메인이라면 다음과 같이 직접 추가해야 합니다.
      CNAME  blog  your-project.pages.dev
  3. SSL 인증서 생성 대기:
    • Cloudflare가 무료 SSL 인증서를 자동으로 발급합니다.
    • 보통 5~10분이면 완료됩니다.

이제 자체 도메인으로 접속할 수 있고 HTTPS도 자동으로 지원됩니다.

Preview Deployments(미리 보기 배포)

이 기능은 팀 협업에 특히 유용합니다. 기본 브랜치가 아닌 다른 브랜치에 코드를 푸시하거나 Pull Request를 만들 때마다 CF Pages가 자동으로 미리 보기 환경을 만듭니다.

사용 방법:

  1. 새 브랜치를 만듭니다.
    git checkout -b feature/new-button
  2. 코드를 수정하고 푸시합니다.
    git add .
    git commit -m "Add new button"
    git push origin feature/new-button
  3. CF Pages가 자동으로 빌드하고 미리 보기 링크를 생성합니다.
    https://abc123.your-project.pages.dev
  4. PR에서 미리 보기 링크를 열어 새 기능을 테스트합니다.
  5. 기본 브랜치에 병합하면 프로덕션 환경에 자동 배포됩니다.

장점:

  • 기능 브랜치마다 독립적인 미리 보기 환경을 사용할 수 있습니다.
  • 제품 관리자와 디자이너가 결과를 직접 확인할 수 있습니다.
  • 프로덕션 환경에 영향을 주지 않습니다.

빌드 캐시 최적화

프로젝트 빌드가 매번 오래 걸린다면 빌드 캐시를 최적화해 볼 수 있습니다.

프로젝트에 캐시 설정 추가:

Cloudflare Pages가 node_modules를 자동으로 캐시하지만 다음 방법으로 더 최적화할 수 있습니다.

  1. npm보다 빠른 pnpm 사용:
    # 프로젝트에 .npmrc 추가
    echo "package-manager=pnpm" > .npmrc
  2. CF Pages 설정 변경:
    • Build command를 pnpm install && pnpm build로 변경합니다.
  3. 불필요한 의존성 제거:
    npm prune

제 경험:

pnpm으로 전환한 뒤 빌드 시간이 5분에서 2분으로 줄어 효과가 꽤 컸습니다.

사용자 지정 Headers 설정

보안 정책이나 캐시 제어 같은 사용자 지정 HTTP Headers를 추가하려면 프로젝트 루트 디렉터리에 _headers 파일을 만듭니다.

# _headers 파일 예시
/*
  X-Frame-Options: DENY
  X-Content-Type-Options: nosniff
  Referrer-Policy: no-referrer-when-downgrade
/static/*
  Cache-Control: public, max-age=31536000, immutable
/api/*
  Cache-Control: no-cache

저장하고 다시 배포하면 Headers가 적용됩니다.


마무리

내용이 길었지만 핵심은 세 가지입니다.

1. 프로젝트 빌드 설정을 정확히 파악합니다.

  • Build command는 무엇인가요? 일반적으로 npm run build입니다.
  • 출력 디렉터리는 어디인가요? Vite는 dist, CRA는 build, Next.js는 배포 방식에 따라 다릅니다.
  • 어떤 환경 변수가 필요한가요? 접두사 규칙에 주의해야 합니다.

2. 자주 발생하는 문제에 특히 주의합니다.

  • Next.js의 nodejs_compat 플래그를 설정하지 않으면 500 오류가 발생합니다.
  • 환경 변수 접두사는 Vite에서 VITE_, Next.js에서 NEXT_PUBLIC_입니다.
  • SPA 라우트의 404 문제를 막으려면 _redirects 파일을 추가해야 합니다.

3. Preview 환경을 잘 활용합니다.

  • 프로덕션 환경에서 직접 테스트하지 마세요.
  • 브랜치로 Preview 환경을 만듭니다.
  • 테스트에 문제가 없을 때 기본 브랜치에 병합합니다.

솔직히 Cloudflare Pages는 그리 어렵지 않습니다. 처음 설정할 때만 조금 시간이 필요합니다. 한 번 설정하면 이후에는 Git Push만으로 자동 배포되어 매우 편리합니다.

무료 무제한 트래픽도 큰 장점입니다. 현재 제 개인 프로젝트 몇 개를 모두 CF Pages에 올려 두었고 트래픽에 대한 걱정이 전혀 없습니다.

문제가 발생하면:

  • 먼저 이 글의 “자주 발생하는 오류” 부분을 확인하세요. 대부분 제가 직접 겪었던 문제입니다.
  • 빌드 로그를 확인하세요. 오류 메시지를 통해 문제가 발생한 위치를 알 수 있습니다.
  • 공식 문서는 영어이지만 상당히 자세합니다. Cloudflare Pages Docs를 참고하세요.

다음 단계:

  • 첫 프로젝트를 Cloudflare Pages에 바로 배포해 보세요.
  • 사용자 지정 도메인을 연결해 보세요.
  • Preview Deployments의 편리함을 경험해 보세요.

문제가 있다면 댓글로 남겨 주세요. 확인하는 대로 답변하겠습니다. 배포가 순조롭게 진행되기를 바랍니다!

React/Vue/Next.js 앱을 Cloudflare Pages에 배포하는 전체 과정

준비부터 배포 설정까지의 전체 단계와 환경 변수 설정, 자주 발생하는 오류의 해결 방법, 특히 Next.js의 nodejs_compat 설정을 자세히 설명합니다.

Estimated time: PT30M

  1. 1

    Step 1: 준비 및 Cloudflare Pages를 선택하는 이유

    Cloudflare 계정 등록:
  2. 2

    Step 2: React 앱 배포(Vite와 CRA)

    Cloudflare Pages 설정 목록:
  3. 3

    Step 3: Vue 앱 배포(Vite와 Vue CLI)

    Cloudflare Pages 설정 목록:
  4. 4

    Step 4: Next.js 앱 배포(정적 내보내기와 SSR 모드)

    Next.js 배포의 특수성:
  5. 5

    Step 5: Next.js의 자주 발생하는 오류 해결 및 환경 변수 관리

    Next.js에서 자주 발생하는 오류와 해결 방법:
  6. 6

    Step 6: 환경 변수 관리 심화 및 모범 사례

    세 가지 환경 구분:

FAQ

Vercel이나 Netlify 대신 Cloudflare Pages를 선택하는 이유는 무엇이며, 무료 플랜에는 어떤 장점이 있나요?
Cloudflare Pages의 무료 플랜은 정말 매력적입니다.

기능 비교:
• 무료 트래픽 무제한(Vercel과 Netlify는 월 100GB)
• 월 500회 빌드(Vercel은 월 6,000분, Netlify는 월 300분)
• 상업용 프로젝트 지원(Vercel은 제한이 있고 Netlify는 지원)
• 300개 이상의 CDN 노드(전 세계에 분산되며 HTTPS 자동 지원)

특히 무제한 트래픽은 큰 장점입니다. 현재 제 개인 프로젝트 몇 개를 모두 CF Pages에 올려 두었고 트래픽을 전혀 걱정하지 않습니다.

Cloudflare Pages에 적합한 경우:
• 개인 블로그 및 포트폴리오 사이트
• 중소 규모 프런트엔드 프로젝트(SPA, 정적 사이트)
• 글로벌 가속이 필요한 프로젝트
• 트래픽 규모를 예측하기 어려운 프로젝트

적합하지 않은 경우:
• 복잡한 SSR 기능이 필요한 대규모 Next.js 앱(CF Pages의 Next.js 지원은 Vercel만큼 완전하지 않음)
• 자주 빌드해야 하는 프로젝트(월 500회 빌드 제한)
• Edge Middleware 등 Vercel 전용 기능이 필요한 프로젝트
React/Vue/Next.js 프로젝트의 빌드 설정은 어떻게 다르며 출력 디렉터리는 무엇인가요?
React 프로젝트 설정:

Vite 프로젝트:
• Framework preset은 None 선택(CF Pages가 자동 감지)
• Build command는 npm run build
• Build output directory는 dist
• Root directory는 /(기본값)
• Environment variables는 VITE_* 접두사 사용

CRA 프로젝트:
• Framework preset은 Create React App 선택(설정 자동 입력)
• Build command는 npm run build
• Build output directory는 build
• Root directory는 /(기본값)
• Environment variables는 REACT_APP_* 접두사 사용

주의: 출력 디렉터리를 가장 자주 혼동합니다. Vite는 dist, CRA는 build이므로 반대로 입력하지 마세요.

Vue 프로젝트 설정:

Vite 프로젝트:
• Framework preset은 None
• Build command는 npm run build
• Build output directory는 dist
• Root directory는 /(기본값)
• Environment variables는 VITE_* 접두사 사용

Vue CLI 프로젝트:
• Framework preset은 Vue
• Build command는 npm run build
• Build output directory는 dist
• Root directory는 /(기본값)
• Environment variables는 VUE_APP_* 접두사 사용

핵심: Vue CLI와 Vite의 출력 디렉터리는 모두 dist이지만 환경 변수 접두사는 Vite가 VITE_, Vue CLI가 VUE_APP_로 다릅니다.

Next.js 프로젝트 설정:

정적 내보내기:
• Framework preset은 Next.js (Static HTML Export)
• Build command는 npm run build
• Build output directory는 out
• Root directory는 /(기본값)

SSR 모드:
• Framework preset은 None
• Build command는 npx @opennextjs/cloudflare
• Build output directory는 .worker-next
• Root directory는 /
환경 변수 접두사 규칙은 무엇이며 프레임워크마다 어떻게 다른가요?
환경 변수 접두사 규칙:

React 프로젝트:
• Vite 프로젝트는 VITE_ 접두사가 필수(예: VITE_API_URL, VITE_API_KEY)
• CRA 프로젝트는 REACT_APP_ 접두사가 필수(예: REACT_APP_API_URL, REACT_APP_API_KEY)

Vue 프로젝트:
• Vite+Vue 프로젝트는 VITE_ 접두사가 필수(예: VITE_API_BASE_URL, VITE_APP_TITLE)
• Vue CLI 프로젝트는 VUE_APP_ 접두사가 필수(예: VUE_APP_API_BASE_URL, VUE_APP_TITLE)

Next.js 프로젝트:
• 클라이언트 변수는 NEXT_PUBLIC_ 접두사가 필수(예: NEXT_PUBLIC_API_URL, NEXT_PUBLIC_SITE_NAME)
• 서버 변수는 접두사가 필요 없음(예: DATABASE_URL, API_SECRET)

환경 변수 접두사 요약:
• Vite(모든 프레임워크): 클라이언트 변수는 VITE_, 서버 변수는 접두사 없음(클라이언트에서는 접근 불가)
• Create React App: 클라이언트 변수는 REACT_APP_, 서버 변수 없음
• Vue CLI: 클라이언트 변수는 VUE_APP_, 서버 변수 없음
• Next.js: 클라이언트 변수는 NEXT_PUBLIC_, 서버 변수는 접두사 없음

기억할 점:
• 브라우저에서 접근할 변수에는 반드시 접두사가 있어야 합니다.
• API Key나 데이터베이스 비밀번호처럼 서버에서만 사용할 변수에는 접두사가 필요 없습니다.

코드에서 사용:
• Vite 프로젝트: import.meta.env.VITE_API_URL
• CRA 프로젝트: process.env.REACT_APP_API_URL
• Vue CLI 프로젝트: process.env.VUE_APP_API_BASE_URL
• Next.js 클라이언트: process.env.NEXT_PUBLIC_API_URL
• Next.js 서버: process.env.DATABASE_URL
Next.js를 Cloudflare Pages에 배포할 때 핵심 설정은 무엇이며 nodejs_compat 오류는 어떻게 해결하나요?
Next.js 배포의 특수성:
• Cloudflare Pages는 Vercel처럼 Next.js 전용 플랫폼이 아니므로 추가 설정이 필요합니다.
• 배포 방법은 정적 내보내기(가장 간단함)와 SSR 모드(어댑터 필요) 두 가지입니다.
• SSR을 사용하려면 @opennextjs/cloudflare 어댑터를 사용해야 합니다. 기존 @cloudflare/next-on-pages는 더 이상 사용되지 않습니다.

정적 내보내기:
• next.config.js를 수정해 다음을 추가합니다.
- output: 'export'(핵심: 정적 내보내기 활성화)
- images: { unoptimized: true }(CF Pages는 Next.js Image Optimization을 지원하지 않음)
• Cloudflare Pages 설정:
- Framework preset은 Next.js (Static HTML Export)
- Build command는 npm run build
- Build output directory는 out

제한 사항:
• API Routes 미지원
• ISR 미지원
• Server Components 미지원
• 동적 라우트의 서버 렌더링 미지원

SSR 모드:
• 어댑터 설치: npm install @opennextjs/cloudflare
• next.config.js 설정(output: 'export'는 설정하지 않고 images: { unoptimized: true } 사용)
• Cloudflare Pages 설정:
- Framework preset은 None
- Build command는 npx @opennextjs/cloudflare
- Build output directory는 .worker-next

중요! Compatibility Flags를 설정해야 합니다. 가장 자주 문제가 발생하는 부분입니다.
• 프로젝트 → Settings → Functions로 이동
• Compatibility flags 섹션에서 Configure Production compatibility flag 클릭
• nodejs_compat 플래그 추가
• Compatibility Date를 최소 2024-09-23 또는 이후 날짜로 설정

주의: Production과 Preview 환경에 모두 설정해야 합니다. 이 플래그가 없으면 배포 후 바로 500 오류가 발생합니다.

Edge Runtime 요구 사항:
• API Routes 또는 Server Components를 사용하면 Edge Runtime 선언을 반드시 추가해야 합니다.
- App Router: export const runtime = 'edge'
- Pages Router: export const config = { runtime: 'edge' }
• 서버에서 실행되는 모든 파일에 이 선언을 추가해야 하며, 누락하면 배포가 실패합니다.
SPA 라우트의 404 문제와 Next.js 배포 후 나타나는 404는 어떻게 해결하나요?
React SPA 라우트의 404 문제:
• React Router를 사용하는 React 프로젝트는 배포 후 페이지를 새로 고치면 404가 발생할 수 있습니다.
• SPA의 모든 라우트가 index.html을 가리켜야 하지만 서버는 기본적으로 해당 경로의 파일을 찾기 때문입니다.

해결 방법:
• 프로젝트의 public 디렉터리에 _redirects 파일을 만들고 /* /index.html 200을 입력합니다.
• 이 한 줄은 모든 경로를 index.html로 리디렉션하고 상태 코드 200을 반환하도록 서버에 지시합니다.
• 저장하고 다시 배포하면 라우트가 정상 작동합니다.

Vue Router 라우트 설정:
• Vue Router, 특히 History 모드를 사용한다면 새로 고침 시 404가 나지 않도록 반드시 리디렉션을 설정해야 합니다.

방법 1: _redirects 파일 사용(권장)
• public 디렉터리에 _redirects 파일을 만들고 /* /index.html 200을 입력합니다.

방법 2: vite.config.js에서 설정(Vite 프로젝트)
• 루트 디렉터리가 아닌 곳에 배포한다면 base: '/'를 설정해야 합니다.

Next.js 배포 후 404가 표시되는 경우:
• 오류 2: 배포는 성공했지만 페이지에 404가 표시됨
• 증상: 빌드 로그는 성공인데 xxx.pages.dev 접속 시 404가 나오거나 홈페이지만 열리고 다른 페이지는 404가 나옴
• 원인: Edge Runtime을 올바르게 설정하지 않았거나 Build output directory가 잘못됨

해결 방법:
• 모든 API Routes와 Server Components에 runtime = 'edge'를 추가했는지 확인합니다.
• Build output directory가 어댑터 사용 시 .worker-next, 정적 내보내기 시 out인지 확인합니다.
• 정적 내보내기라면 _redirects 파일을 만들었는지 확인합니다.
환경 변수가 적용되지 않을 때 어떻게 점검하며 개발, 미리 보기, 프로덕션 환경은 어떻게 구분하나요?
환경 변수 문제 점검 순서:

1) 접두사가 올바른지 확인:
• Vite 프로젝트에 REACT_APP_ 접두사를 사용했나요? VITE_를 사용해야 합니다.
• Next.js 클라이언트 변수에 NEXT_PUBLIC_을 빠뜨렸나요?

2) 다시 배포했는지 확인:
• 환경 변수를 수정한 뒤에는 새 배포를 시작해야 적용됩니다.
• Git에 작은 변경을 푸시하거나 Dashboard에서 Retry deployment를 클릭할 수 있습니다.

3) 환경이 올바른지 확인:
• Production 환경을 수정하고 Preview 링크에 접속한 것은 아닌지, 또는 그 반대인지 확인합니다.

4) 빌드 로그 확인:
• 빌드 로그에서 변수 이름을 검색해 올바르게 읽혔는지 확인합니다.
• Secret 유형 변수의 값은 로그에 표시되지 않습니다.

5) 코드의 참조 방식 확인:
• Vite 프로젝트의 잘못된 방식: process.env.VITE_API_URL
• 올바른 방식: import.meta.env.VITE_API_URL

세 가지 환경 구분:
• Cloudflare Pages는 세 가지 환경을 지원합니다.
- Production(프로덕션): main과 같은 기본 브랜치에 푸시하면 사용자용 프로덕션 환경에 배포
- Preview(미리 보기): 다른 브랜치나 PR에 푸시하면 새 기능 테스트용 환경에 배포
- Development(개발): 개발자의 컴퓨터에서만 실행하는 로컬 개발 환경

Cloudflare Dashboard에서 설정:
• 프로젝트 → Settings → Environment variables로 이동
• Production과 Preview 탭이 표시됩니다.

권장 설정:
• 실제 API Key와 데이터베이스 연결 등 프로덕션 환경 변수는 Secret 유형을 선택합니다. 값은 암호화되어 저장되고 로그에 표시되지 않습니다. 예: API_KEY=prod-key-12345
• 테스트용 API Key 같은 미리 보기 환경 변수는 Plain text를 선택할 수 있습니다. 예: API_KEY=test-key-67890

로컬 개발 환경 변수:
• 권장 파일 구조:
- .env.local(로컬 개발 변수, Git에 커밋하지 않음)
- .env.example(변수 템플릿, Git에 커밋)
- .gitignore(민감한 파일 제외)

중요:
• .env.local은 Git에 커밋하지 마세요.
• .env.example은 팀원이 참고할 수 있도록 Git에 커밋합니다.
• .gitignore에 .env*.local을 추가합니다.

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

댓글

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

Easton BlogEaston Blog