본문으로 건너뛰기
Caesiumy's BLOG
뒤로 가기

[번역] Railway는 왜 프론트엔드를 Next.js에서 걷어냈나

방문자 수
[번역] Railway는 왜 프론트엔드를 Next.js에서 걷어냈나 썸네일

이 문서는 Moving Railway’s Frontend Off Next.js의 한글 번역입니다.

목차

목차 보기

핵심 요약

📌 TL;DR (클릭하여 펼치기)

주요 내용

  • Railway는 프로덕션 프론트엔드 전체(대시보드, 캔버스, railway.com)를 Next.js에서 Vite + TanStack Router로 전환했습니다.
  • 10분을 넘기던 빌드가 2분 이내로 줄었고, PR 2개만으로 무중단 마이그레이션을 완료했습니다.
  • Pages Router의 레이아웃 한계, 서버 우선 패러다임과 실제 제품의 불일치, 느린 개발 루프가 전환의 주요 이유였습니다.
  • Nitro를 서버 레이어로 도입해 리다이렉트 500건 이상, 보안 헤더, 캐싱 규칙을 한 곳에 통합했습니다.
  • Fastly 엣지 캐싱과 Vite의 콘텐츠 해시 청크 모델 덕분에 재방문 사용자는 메가바이트가 아니라 킬로바이트만 내려받습니다.

주의사항

  • TanStack Start는 신생 프레임워크라 거친 부분이 있을 수 있습니다. Railway는 그 방향성을 믿고 Vite와 TanStack 모두를 후원하고 있습니다.
  • next/image의 내장 이미지 최적화는 Fastly 엣지 최적화로 대체했고, next-seo·next-sitemap 같은 에코시스템 도구는 자체 제작했습니다.

원문 작성일: 2026년 4월 3일 (금)

작성자: Victor Ramirez


Railway의 프로덕션 프론트엔드는 더 이상 Next.js 위에서 동작하지 않습니다. 대시보드, 캔버스, railway.com 모두 이제 Vite + TanStack Router로 실행되며, PR 2개로 무중단 마이그레이션을 해냈습니다.

Next.js는 제 역할을 다했다. 그러다 아니게 됐다

Next.js는 railway.com을 제로에서 출발해 매달 수백만 명이 쓰는 프로덕션 앱으로 키워줬습니다. 훌륭한 프레임워크임은 분명합니다. 하지만 우리 제품에 맞는 프레임워크는 더 이상 아니었습니다.

프론트엔드 빌드가 어느새 10분을 넘겼습니다. 그 중 6분은 오롯이 Next.js 몫이었고, 그마저 절반은 “페이지 최적화 마무리” 단계에 발이 묶여 있었습니다. 하루에도 여러 번 배포하는 팀에게 이 정도 빌드 시간은 사소한 불편이 아닙니다. 매 반복마다 물리는 아주 비싼 세금과 다름없습니다.

Railway 앱의 압도적인 비중은 클라이언트 사이드입니다. 대시보드는 풍부한 상태를 다루는 인터페이스이고, 캔버스는 실시간으로 동작하며, Websockets이 곳곳에 깔려 있습니다. Next.js의 서버 우선 기본 요소들은 쓸 일이 없었습니다. 결국 Pages Router 위에 자체 추상화 레이어를 덧쌓을 수밖에 없었고, 프레임워크가 기본 지원하지 않는 레이아웃·라우팅 방식을 직접 구현했습니다.

Pages Router를 쓰는 동안에는 레이아웃 공유가 어색했습니다. 모든 레이아웃 패턴이 프레임워크가 기본 제공하는 요소가 아니라 억지로 덧댄 우회책이었습니다. App Router로 넘어가면 일부 문제는 해결되겠지만, App Router는 서버 우선 패턴에 깊게 기대는 구조입니다. 우리 제품은 의도적으로 클라이언트 중심이라 그 방향과는 맞지 않았습니다. 도입한다면 우리에게 필요 없는 패러다임을 중심으로 전부 다시 짜야 했을 것입니다.

TanStack Start + Vite를 선택한 이유

우리가 실제로 개발하는 방식과 맞는 스택을 원했습니다. 명시적이고, 클라이언트 우선이며, 빠르게 반복할 수 있는 것. 게다가 우리가 쓰면서 진심으로 즐겁다는 점도 한몫했습니다.

제품 팀 입장에서 프론트엔드 구현 방식을 일일이 고민하지 않아도 되는 요소들을 원했고, 아래 다섯 가지가 결정적이었습니다.

팀원 여럿이 연휴 동안 TanStack Start를 써봤고, 반응은 만장일치였습니다. 개발 자체가 즐거웠고, Railway 대시보드 같은 제품에서는 벤치마크 수치만큼이나 중요한 부분입니다.

PR 2개, 무중단

결정을 내린 뒤 바로 작업에 들어갔습니다. squash 머지 전까지 수백 개 커밋을 쌓았을 겁니다.

200개 이상의 라우트에 매달 수백만 명이 접속하는 프로덕션 프론트엔드를 마이그레이션하는 일은 보통 몇 달에 걸친 병행 운영과 단계적 전환이 필요합니다. 마감 기한이 있었기에, PR 2개로 해냈습니다.

PR 1은 Next.js 전용 요소를 모두 걷어냈습니다. next/image, next/head, next/router를 각각 네이티브 브라우저 API나 프레임워크 독립적인 대안으로 교체했습니다. 이 PR은 프레임워크 자체는 전혀 건드리지 않았습니다. 그저 Next.js 의존성을 모두 제거해, PR 2가 깔끔한 교체 작업이 되도록 준비했을 뿐입니다.

PR 2는 프레임워크를 교체했습니다. 200개 이상의 라우트를 마이그레이션했습니다. 먼저 페이지 파일에서 라우팅과 무관한 코드를 모두 개별 React 컴포넌트로 추출한 다음, 기존 페이지 트리에서 모든 라우트를 자동 생성했습니다.

이어서 Nitro를 서버 레이어로 추가하고, next.config.js를 Nitro 설정으로 대체해 리다이렉트 500건 이상, 보안 헤더, 캐싱 규칙을 한 곳으로 통합했습니다. Next.js가 폴리필로 감싸던 Node.js API(Buffer, url.parse 등)도 브라우저 네이티브 대안으로 교체했고, 덤으로 코드도 한결 깔끔해졌습니다.

일요일 이른 아침에 머지했습니다. 팀은 곧바로 Discord에 실시간 워룸(war room)을 열고 내부에서 직접 사용해보며 같은 날 수정 사항들을 속속 반영했습니다. 다운타임은 없었습니다.

포기한 것들

더 빠르고 명시적인 스택을 얻었지만, 트레이드오프도 있었습니다.

Railway의 프론트엔드는 Railway 위에서 동작한다

우리 프로덕션 프론트엔드를 실행하는 방식은 사용자들이 자신의 프론트엔드를 실행하는 방식과 동일합니다. PR마다 프리뷰 배포, 헬스 체크, 무중단 롤아웃. 빌드 시스템과 프레임워크 전체를 교체하면서도 인프라는 손대지 않았습니다. 코드를 바꿔 푸시했고, Railway가 나머지를 처리했습니다.

이제 Fastly가 대부분의 트래픽을 엣지에서 직접 처리합니다. 마케팅 페이지는 캐시되고, 동적 페이지는 필요한 곳에만 ISR을 씁니다. 프론트엔드 서버는 대부분 유휴 상태입니다. Vite의 에셋 모델이 이 구조와 특히 잘 맞습니다. 각 모듈이 콘텐츠 해시 청크를 가지므로, 결제 관련 코드를 수정해도 해당 청크만 무효화됩니다. 재방문 사용자는 메가바이트가 아니라 킬로바이트만 내려받습니다.

프론트엔드는 이렇게 배포되어야 한다고 생각합니다. 빌드는 빠르고, 에셋은 변하지 않으며 캐시 친화적이고, 기반 인프라가 롤아웃·프리뷰·라우팅을 알아서 처리해줘서 신경 쓸 필요가 없는 구조. 프론트엔드 프레임워크는 반복 속도에 최적화되어야 하고, 인프라는 그 반복을 배포할 때 투명하게 만들어줘야 합니다. Railway에서 개발하면서, 그리고 Railway를 쓰는 모든 사람을 위해 만들어가는 경험이 바로 이것입니다.

지금이어야 했던 이유

프론트엔드 반복 속도는 지금만큼 중요했던 적이 없습니다.

10분을 넘기던 빌드가 이제 2분 이내에 끝납니다. 개발 서버는 즉시 시작됩니다. 라우트 변경은 라우트 경계에서 타입 검사를 거칩니다. 레이아웃은 우회책 없이 자연스럽게 조합됩니다.

코드를 작성하고 사용자 앞에 내보내기까지의 간격이 곧 병목입니다. 지금까지 해온 모든 작업 — 프레임워크 교체, 엣지 캐싱, 에셋 모델 — 은 그 간격을 좁히기 위한 것입니다. Vite + TanStack은 프론트엔드 변경 사항을 거의 즉시 배포할 수 있는 세계로 가는 발판이며, 우리는 바로 그런 세계를 만들어가고 있습니다.

참고 자료


공유하기
복사됨!

이전 글
[번역] LLM도 벗어날 수 없는 디자인 시스템 만들기
다음 글
이력서 한 줄을 포트폴리오 섹션으로 풀어내는 4-Phase 하네스 설계하기