# 애드센스 한 줄이면 약관 위반입니다 — Vercel에서 Cloudflare로 Next.js 옮긴 기록 Vercel Hobby 상업적 사용 금지 조항과 Next.js Cloudflare 이전. vinext·OpenNext 선택과 깨진 것들. - source: https://polroute.com/posts/vercel-to-cloudflare-migration/ - category: 트러블슈팅 - published: 2026-09-14 --- Vercel Hobby 플랜을 쓰다가 사이트에 애드센스를 붙였다면, 그 순간부터 약관 위반입니다. 용량을 초과해서가 아니라 조항 자체가 그렇습니다. 저는 한도 걱정을 하다가 이걸 알았습니다. 한도는 아직 한참 남아 있었는데, 정작 문제는 다른 데 있었습니다. ## 이사 트리거는 용량이 아니라 약관이었습니다 공식 Fair Use 문서의 문장입니다. > Hobby teams are restricted to non-commercial personal use only. All commercial usage of the platform requires either a Pro or Enterprise plan. 여기까지는 알려진 얘기입니다. 문제는 "상업적 사용"의 정의가 생각보다 훨씬 넓다는 겁니다. > any Deployment that is used for the purpose of financial gain of **anyone** involved in **any part of the production** of the project, including a paid employee or consultant writing the code 프로젝트 제작에 관여한 **누구든** 금전적 이득을 얻으면 해당됩니다. 문서가 직접 드는 예시는 이렇습니다. - 방문자에게 결제를 요청하거나 처리하는 모든 방식 - 제품이나 서비스의 판매를 광고하는 것 - 사이트를 만들거나 수정하거나 호스팅하는 대가를 받는 것 - 제휴 링크가 사이트의 주목적인 경우 - 구글 애드센스를 포함한 광고 게재 마지막 줄에 개인 블로그 상당수가 걸립니다. 애드센스 한 줄이면 끝입니다. 반대로 **기부 요청은 상업적 사용이 아닙니다.** 문서에 명시돼 있습니다. 외주로 만들어준 사이트를 Hobby에 올려둔 경우도 걸립니다. 사이트가 돈을 못 벌어도 코드를 쓴 사람이 돈을 받았으면 해당되니까요. ## Hobby 플랜 실제 한도 참고로 한도는 이렇습니다. 대부분은 여기에 걸리기 전에 위 조항에 먼저 걸립니다. | 항목 | Hobby | |---|---| | Fast Data Transfer | 100 GB | | Fast Origin Transfer | 10 GB | | Function Invocations | 1M | | Active CPU | 4 CPU-hrs | | Provisioned Memory | 360 GB-hrs | | 이미지 변환 | 5K/월 | ## 옮길 가치가 있는 프로젝트, 없는 프로젝트 전부 옮길 필요는 없습니다. 기준은 단순합니다. **옮길 가치가 있는 것** — 광고나 결제가 붙은 사이트, 외주 결과물, 정적 사이트에 가까운 블로그·랜딩페이지. 특히 정적이면 이사에 손댈 게 거의 없습니다. 이 블로그도 Astro 정적 빌드라 Cloudflare Pages에 올리는 데 [10분 걸렸습니다](/posts/cloudflare-pages-deploy-custom-domain/). **남겨둘 것** — 순수 토이 프로젝트, ISR과 이미지 최적화에 깊이 기댄 앱, Next.js 최신 기능을 계속 따라가야 하는 앱. 뒤에 나올 호환성 문제를 감수할 이유가 없습니다. ## 2026년 9월, 배포 경로가 또 바뀌었습니다 여기가 이 글에서 제일 중요한 부분입니다. 검색해서 나오는 마이그레이션 글은 대부분 `@opennextjs/cloudflare`를 쓰라고 합니다. 그 전 세대 글은 `@cloudflare/next-on-pages`를 쓰라고 하고요. 지금은 둘 다 최신 권장안이 아닙니다. Cloudflare의 OpenNext 문서 맨 위에 이렇게 적혀 있습니다. > Cloudflare recommends vinext instead of OpenNext for new Next.js applications on Cloudflare Workers. OpenNext 페이지는 이제 **기존 앱을 유지보수하는 사람**을 위한 문서입니다. 새 프로젝트의 기본 경로는 vinext입니다. Next.js API를 Vite 위에서 다시 구현한 물건이고 Next.js 16 API 표면의 약 94%를 덮습니다. 그런데 저장소 경고를 읽어보면 바로 결정이 섭니다. > Under active development. vinext supports substantial Next.js applications today, but it is not yet a drop-in replacement for every application or production workload. Expect compatibility gaps, especially in newer App Router features. Next.js 16.x에서만 돌아가고, Vercel 전용 기능과 `next export`, Turbopack/webpack 설정, `next/jest`는 아예 지원하지 않습니다. **그래서 제 결론은 이렇습니다.** 지금 돌아가는 앱을 옮기는 거라면 OpenNext입니다. 권장에서 밀려났을 뿐 문서와 경로가 살아 있고, 깨지는 지점이 이미 알려져 있습니다. vinext는 Next.js 16을 쓰고 있고 호환성 구멍을 직접 확인할 여유가 있을 때 고르세요. "공식 권장"이라는 말만 보고 프로덕션 앱을 먼저 올리면 안 됩니다. ## 실제로 깨진 것들 경로를 골랐으면 이제 깨집니다. 자주 나오는 순서대로입니다. Edge Runtime을 강제하는 어댑터에서는 이게 먼저 뜹니다. ``` Error: Dynamic Code Evaluation (e.g. 'eval', 'new Function', 'WebAssembly.compile') is not allowed in Edge Runtime. ``` 의존성 하나가 내부에서 `eval`을 쓰면 걸립니다. 내 코드가 아니라 남의 패키지라 고칠 수도 없습니다. Node 내장 모듈이 없어서 나는 것도 같은 뿌리입니다. ``` [Error] Cannot find module 'crypto' imported from '/functions/api/auth/token.func.js' ``` 둘 다 `nodejs_compat`으로 해결합니다. 이게 빠지면 아래 에러가 따라옵니다. ``` TypeError: Cannot read properties of undefined (reading 'MY_VAR') ``` `compatibility_date`가 2025년 4월 이전이면 `process.env`가 자동으로 채워지지 않습니다. 환경변수를 제대로 넣었는데 `undefined`가 나오면 여기를 보세요. 설정은 결국 이 두 줄입니다. ```toml compatibility_date = "2026-09-14" compatibility_flags = ["nodejs_compat"] ``` `compatibility_date`는 2024-09-23 이후여야 하고, 공식 문서는 그냥 오늘 날짜를 넣으라고 합니다. ## 옮기고 나서 잃은 것 정직하게 씁니다. Vercel이 편했던 것들이 그냥 없어집니다. ISR, 이미지 최적화, PR마다 자동으로 생기는 프리뷰 배포. 특히 `next/image`에 기대고 있었다면 대체재를 직접 붙여야 합니다. 작지만 성가신 것도 있습니다. `next.config.ts`의 `headers()`로 보안 헤더를 걸어뒀다면, 정적으로 내보내는 순간 그게 안 따라옵니다. Cloudflare에서는 `public/_headers` 파일로 다시 써야 합니다. 이 블로그도 그렇게 합니다. ## 비용 | | Vercel | Cloudflare Workers | |---|---|---| | 무료 | Hobby (비상업용만) | 10만 요청/일 | | 유료 시작 | Pro $20/월 (좌석 1개 포함) | $5/월 | | 유료 포함량 | Fast Data Transfer 1 TB, Edge Request 1,000만 | 1,000만 요청/월 | | 전송량 과금 | 있음 | **없음** | | 정적 자산 | 전송량에 포함 | 무료·무제한 | 상업적 사용을 하려면 Vercel은 Pro가 강제입니다. Cloudflare는 무료 플랜에 상업적 사용 제한이 없고 egress 과금도 없습니다. 정적 자산 비중이 큰 사이트일수록 차이가 벌어집니다. 같은 계산을 DB 쪽에도 적용한 글이 [Supabase 무료 티어 한계](/posts/supabase-free-tier-limits/)이고, 이 구성을 어떻게 짰는지는 [1인 개발자 최소 인프라](/posts/minimal-infra-vercel-supabase/)에 있습니다.