우리가 Next.js에서 Vite와 Hono로 마이그레이션한 이유
Source: Dev.to
Migration Overview (Late 2025)
2025년 말, 우리는 Pluslide를 Next.js에서 완전히 탈피시켰습니다.
새로운 스택은? 프론트엔드는 Vite + React, API 레이어는 Hono입니다.
이 결정은 가볍게 내린 것이 아니었습니다. Next.js는 현대 웹 개발을 형성했으며 많은 React 프로젝트의 기본 선택지로 남아 있습니다. 하지만 Cloudflare와의 호환성 문제, 보안 우려 증가, 그리고 아키텍처 복잡성에 몇 달간 좌절한 끝에, Next.js가 우리에게 더 이상 적합한 도구가 아니라는 결론에 도달했습니다.
아래는 우리가 발견한 내용의 요약입니다.
The Cloudflare Compatibility Problem
Pluslide는 Cloudflare 전용으로 운영됩니다. 이 인프라 선택은 성능과 비용 면에서 뛰어나지만, Next.js와 Cloudflare는 결코 완벽한 조합이 아니었습니다.
The Migration Pain
처음 Cloudflare에 Next.js를 배포했을 때 우리는 next‑on‑pages 를 사용했는데, 이는 원래 Cloudflare가 유지하던 어댑터였습니다. 경험은 결코 원활하지 않았습니다. 공식 지원이 있더라도 우리는 끊임없이 엣지 케이스와 제한에 부딪혔고, 이를 우회하기 위한 작업이 필요했습니다.
- 2025년 9월: Cloudflare가
next‑on‑pages프로젝트를 아카이브한다는 발표를 했습니다.
공식 권장 사항은 OpenNext 로, 커뮤니티가 유지하는 어댑터입니다.
next‑on‑pages 사용 경험을 바탕으로 우리는 어댑터 기반 솔루션에 대해 건강한 회의감을 갖게 되었습니다. 또한 이 경로를 선택하면 최신 Next.js 버전을 바로 사용할 수 없으며, 커뮤니티가 호환성을 맞추고 테스트할 때까지 기다려야 합니다.
Note:
next‑on‑pages에서 OpenNext로 마이그레이션하려면 Cloudflare Pages에서 Cloudflare Workers로 서비스도 옮겨야 합니다. 이는 작은 변화가 아닙니다. 만약 그런 규모의 마이그레이션을 어쩔 수 없이 진행한다면, 우리는 스스로에게 물어야 했습니다:
이게 올바른 길인가?
아니면 완전히 더 나은 옵션을 고려해야 하는가?
The Vercel Question
Cloudflare에 Next.js를 배포하면서 불편한 질문이 떠올랐습니다: Vercel은 정확히 무엇을 최적화하고 있는가?
- Next.js는 기술적으로 오픈 소스이지만, 최고의 배포 경험(특히 Edge Runtime)은 Vercel에 있습니다.
- Incremental Static Regeneration 같은 기능은 Vercel에서는 매끄럽게 동작하지만, 다른 환경에서는 상당한 노력이 필요합니다.
- “Vercel에서 실행된다”와 “다른 곳에서 실행된다” 사이의 격차는 점점 벌어지고 있습니다.
Vercel을 사용하지 않으면 2등 시민이 되는 셈이며, 우리는 그런 상황을 원하지 않았습니다.
Security Concerns That Accelerated Our Decision
2025년에 Next.js는 일련의 치명적인 보안 취약점에 직면했습니다. 이는 마이그레이션의 주요 이유는 아니었지만, 우리의 신뢰를 흔들었습니다.
CVE‑2025‑29927: Middleware Authorization Bypass
- Date: 2025년 3월
- Severity: CVSS 9.1
- Impact: 공격자가 특정 HTTP 헤더를 위조해 미들웨어 기반 접근 제어를 완전히 우회할 수 있었으며, 인증 검사, 권한 부여 로직, CSP 헤더를 무력화했습니다.
- Scope: Next.js 릴리즈 4년 이상에 걸친 버전이 영향을 받았습니다.
- Reference: Security Labs – Next.js Middleware Auth Bypass
CVE‑2025‑55182: Remote Code Execution
- Date: 2025년 말
- Severity: CVSS 10.0 (critical)
- Impact: 적극적으로 악용된 RCE를 통해 공격자는 클라우드 자격 증명을 탈취하고, 감염된 서버에 암호화폐 채굴기를 배포할 수 있었습니다.
- Reference: Wiz – Critical Vulnerability in React (CVE‑2025‑55182)
이 사건들은 프레임워크 복잡성은 보안 비용을 동반한다는 점을 일깨워 주었습니다. 추상화 레이어가 많을수록 공격 표면도 늘어납니다.
The Architecture Problem
우리의 Next.js 코드베이스는 뒤얽힌 상태가 되었습니다:
- tRPC 라우터가 React 컴포넌트와 함께 존재했습니다.
- 서버와 클라이언트 코드가 뒤섞여 있어, 어느 부분이 어디에서 실행되는지 파악하기 어려웠습니다.
- 페이지와 API 로직이 동일 파일에 공존하면서, 유지보수와 테스트가 급격히 어려워졌습니다.
이러한 구조적 문제들은 개발 속도를 저해하고, 새로운 기능을 도입하거나 버그를 수정할 때마다 큰 리스크를 안겨 주었습니다.
위와 같은 이유들로 우리는 Vite + React와 Hono 기반의 새로운 스택으로 전환하기로 결정했으며, 이후의 섹션에서는 마이그레이션 과정과 얻은 교훈을 자세히 다룰 예정입니다.
Source: …
t data flow difficult.
- Every file required mental overhead to determine whether it ran on the server, the client, or both.
We do not deny that part of this mess came from rapid prototyping where structure took a backseat to speed. This is not a flaw in Next.js per se, but the framework’s blurry boundaries between server and client made it too easy to let things get out of hand.
Practical consequences
- Architecture became hard to read and reason about.
- AI coding assistants frequently hallucinated about where code should run, generating server code in client files and vice‑versa.
- Turborepo cache was essentially useless—any change to UI or API code invalidated both caches.
- The build graph turned into a web of unnecessary dependencies.
Unifying on Cloudflare Workers
Before choosing our new stack we made another infrastructure decision: consolidate everything on Cloudflare Workers.
- The distinction between Pages and Workers has always been confusing; their responsibilities overlap significantly, and the developer experience differs in subtle but frustrating ways.
- In 2025 Cloudflare made their direction clear: they now recommend Pages users migrate to Workers (see the migration guide in the Pages documentation).
Bottom line: We were migrating to Workers no matter what.
Why Vite and Hono Became Our Answer
We needed tools with first‑class Workers support and a clean separation between frontend and backend.
Vite: Native Cloudflare Workers Integration
- Vite’s first‑class Cloudflare Workers support is provided by the Cloudflare Vite plugin.
- The plugin offers deep integration between Vite and the Workers runtime: you can run Vite’s dev server locally while executing your code directly in the Workers runtime.
Hono: Minimalist Edge‑Ready API Framework
- Hono is a tiny, standards‑based router designed for edge environments.
- It pairs perfectly with Workers, giving us a lightweight, type‑safe API layer without the heavy abstractions of Next.js.
최종 생각
Next.js에서 마이그레이션하는 것은 고통스러웠지만 필요한 여정이었습니다. UI는 Vite + React로, API는 Hono로 전환하고 두 서비스 모두 Cloudflare Workers에서 실행함으로써 우리는 다음을 얻었습니다:
- 예측 가능하고 일류 수준의 Edge 지원
- 관심사의 명확한 분리 (프론트엔드 vs. 백엔드)
- 더 간단하고 빠른 빌드 및 캐시
- 공격 표면 감소와 더 빠른 보안 패치
- 벤더 종속성에서 자유 (이제는 2등 시민이 아님)
마이그레이션은 이미 성능, 개발자 경험, 보안 측면에서 큰 이익을 가져왔습니다. 우리는 이제 Pluslide의 다음 장을 장기 목표에 부합하는 스택으로 구축하는 데 전념하고 있습니다.
No More “Works in Dev, Breaks in Production” Surprises
Vite 6에 도입된 Environment API는 Cloudflare Workers 팀의 직접적인 의견을 반영해 개발되었습니다. 이 API는 개발 환경과 프로덕션 환경 사이의 격차를 크게 줄여줍니다. 이제 전체 Vite 경험을 그대로 누리면서 엣지 환경을 직접 대상으로 개발할 수 있게 되었습니다.
성능 향상은 부수적인 혜택이었습니다. 개발 서버가 몇 초 안에 시작되고, Hot Module Replacement가 즉시 적용되며, 이전에 5분이 걸리던 프로덕션 빌드가 이제 2분 이하로 완료됩니다.
이러한 속도의 대부분은 Vite 8을 구동하는 새로운 Rust 기반 번들러 Rolldown 덕분입니다. 아직 베타 단계이지만, 우리의 프로덕션 워크플로우에서 이미 인상적인 결과를 보여주고 있습니다.
Hono: 엣지‑네이티브 프레임워크
Hono는 우리의 API 레이어를 담당합니다.
- 작고 (최소 프리셋 기준 12 KB 이하)
- 의존성 없음
- 웹 표준 API만 사용하며 Edge 런타임을 완벽히 지원합니다
이는 동일한 코드가 Cloudflare Workers, Deno, Bun, AWS Lambda, 혹은 Node.js에서 수정 없이 실행된다는 의미입니다.
Cloudflare는 내부적으로 Hono를 사용합니다. 그들의 공식 블로그 게시물에 따르면, 모든 Workers Logs 내부 및 고객용 API가 Hono를 사용해 Workers에서 실행됩니다. Cloudflare는 KV와 Queues의 내부에서도 Hono를 사용합니다. 플랫폼 제공자가 자체 제품을 프레임워크로 구축한다는 것은 그 프레임워크가 신뢰할 수 있음을 의미합니다.
개발자 경험이 뛰어납니다:
- 일류 TypeScript 지원
- API가 Express 개발자에게 친숙하지만 레거시 부담이 없습니다
- 미들웨어 구성은 깔끔하고 예측 가능합니다
Clear Boundaries
Vite와 Hono를 사용하면 구분이 명확합니다:
Frontend (Vite + React) – 순수히 클라이언트‑사이드. UI, 라우팅, 상태 관리를 담당합니다. 데이터베이스 스키마나 인증 로직에 대해서는 알지 못합니다.
API (Hono) – 순수히 서버‑사이드. 비즈니스 로직, 데이터 접근, 인증을 담당합니다. React 컴포넌트나 UI 상태에 대해서는 알지 못합니다.
Shared – 오직 TypeScript 타입 정의만 포함합니다. API가 내보내는 타입을 프론트엔드가 가져다 씁니다. 런타임 코드는 경계를 넘지 않습니다.
이러한 이점은 코드에 대한 이해를 쉽게 하는 것 이상이었습니다:
- Turborepo 캐시 히트가 크게 증가했습니다.
- 프론트엔드 개발자는 백엔드 구현 세부 사항을 몰라도 작업할 수 있습니다.
- 백엔드 개발자는 UI 코드를 깨뜨릴 걱정 없이 리팩터링할 수 있습니다.
이 깔끔한 분리는 AI‑지원 개발을 훨씬 더 효과적으로 만들었습니다. 모델이 각 레이어를 독립적으로 추론할 수 있어 혼합된 컨텍스트에 혼란을 겪지 않았습니다.
아마도 더 중요한 점은 디버깅이 간단해졌다는 것입니다. Next.js와 그 Cloudflare 어댑터를 사용할 때는 문제를 파악하는 데 지속적인 어려움이 있었습니다: 버그가 우리 코드에 있는가, Next.js 내부에 있는가, 아니면 어댑터 레이어에 있는가? OpenNext는 우회 방법, 성능 팁, 알려진 이슈에 대한 방대한 문서를 유지하고 있습니다. 우리는 이러한 문서화된 이슈가 호환성 문제의 빙산 일각에 불과하다고 생각합니다.
Next.js와 어댑터 레이어를 포기하고 완전한 프론트엔드‑백엔드 분리를 채택한 뒤, 버그 발생률이 70 % 이상 감소했습니다. 문제가 발생하더라도 소스가 항상 명확하기 때문에 훨씬 빠르게 식별하고 수정할 수 있습니다.
마이그레이션 후 얻은 것
-
빌드 시간이 5분에서 2분 이하로 감소했습니다.
우리 CI 파이프라인은 8개의 서로 다른 서비스를 빌드하고 10개 이상의 공유 패키지를 컴파일하므로 이 측정은 전체 모노레포를 포함합니다. -
Turborepo 캐시 적중률이 크게 증가했습니다.
프론트엔드와 API 사이에 명확한 경계가 생겨 하나를 변경해도 다른 쪽이 무효화되지 않습니다. 이제 대부분의 빌드가 변경되지 않은 패키지를 완전히 건너뛰게 됩니다. -
로컬 개발이 즉시 이루어집니다.
개발 서버가 몇 초 안에 시작됩니다. Hot Module Replacement(핫 모듈 교체)가 변경을 즉시 적용합니다. 피드백 루프가 “기다렸다가 새로 고침”에서 “저장하고 바로 확인”으로 바뀌었습니다. -
Cloudflare 배포가 간단해졌습니다.
호환성 레이어가 더 이상 필요 없습니다. 엣지‑런타임 우회도 없습니다. Workers가 본래 해야 할 일을 그대로 수행합니다. -
코드베이스가 이해하기 쉬워졌습니다.
신입 팀원이 더 빠르게 온보딩됩니다. 코드 리뷰는 “이 코드는 어디서 실행되나요?” 같은 질문보다 로직에 집중합니다. 실행 컨텍스트가 항상 명확하므로 디버깅이 간단해집니다. -
보안 상태가 개선되었습니다.
추상화 레이어가 줄어들어 잠재적인 취약점도 감소합니다. 보안 패치를 적용해야 할 때는 더 작고 집중된 코드베이스에 적용됩니다.
Next.js가 적합한 경우는 언제인가?
우리는 명확히 하고 싶습니다: Next.js는 여전히 다양한 사용 사례에 훌륭한 프레임워크입니다. 우리의 마이그레이션이 당신이 그것을 포기해야 한다는 의미는 아닙니다.
Next.js가 적합한 경우:
- 팀이 주로 별도 API 서버를 관리하고 싶어 하지 않는 프론트엔드 개발자로 구성된 경우.
- 컨텍스트 전환 없이 풀스택 애플리케이션을 구축할 수 있는 통합 백엔드 기능을 원할 때.
- Vercel의 관리형 생태계(Analytics, Edge Functions, 이미지 최적화, 배포 프리뷰 등)에 의존할 때.
- 세밀한 캐시 제어가 가능한 복잡한 Incremental Static Regeneration(ISR) 패턴이 필요할 때.
- 스트리밍 및 점진적 렌더링을 위해 React Server Components를 많이 사용하는 경우.
우리가 스스로에게 물은 질문은 간단했습니다: 이러한 조건 중 어느 것이 Pluslide에 적용되는가?
답은 아니오였습니다. 우리는 Vercel이 아니라 Cloudflare에 집중하고 있었습니다. 우리의 페이지는 완전 정적(마케팅 사이트, 문서) 혹은 완전 동적(프레젠테이션 편집기) 중 하나였습니다. ISR가 필요하지 않았고, React Server Components도 사용하지 않았습니다.
우리에게 Next.js는 해당 가치를 제공하지 못하고 복잡성만 늘리는 것이었습니다.
결론
Next.js는 다양한 유효한 사용 사례를 가진 강력한 프레임워크입니다. Vercel이 여러분의 플랫폼이고 풀스택 React가 아키텍처라면, 여전히 훌륭한 선택입니다.
하지만 프레임워크는 여러분의 필요에 맞춰야지, 그 반대가 되어서는 안 됩니다. 마찰이 지속적으로 발생하고, 호환성을 위해 끝없는 우회가 필요하며, 보안 사고 때문에 밤잠을 설친다면 재평가할 시점일 수 있습니다.
Pluslide의 경우, Vite와 Hono가 우리가 필요로 했던 바로 그 것—속도, 단순함, 그리고 Cloudflare와의 원활한 통합—을 제공했습니다. 마이그레이션에는 노력이 들었지만, 결과적으로 우리는 실제로 작업하기 즐거운 코드베이스를 얻게 되었습니다.
여러분의 상황은 다를 수 있습니다. 프레임워크와 싸우는 시간이 더 많아지고 있다면, 대안이 존재한다는 점을 기억하세요. 때로는 최고의 기술적 선택이 인프라와 맞는 도구를 선택하는 것이며, 그것과 맞서 싸우는 도구를 선택하는 것이 아닙니다.
이 글은 원래 Pluslide Blog에 게시되었습니다.
Pluslide는 위에서 설명한 스택을 기반으로 한 프레젠테이션 생성 API입니다. 프로그래밍 방식으로 슬라이드를 생성해야 하는 앱을 만들고 있다면, 확인해 보세요.
마이그레이션에 대해 궁금한 점이 있나요? 아래에 댓글을 남겨 주세요.