Next.js 추종자에서 배신자까지 (feat. Tanstack Router 마이그레이션)

GwangSoo·2026년 2월 3일

개인공부

목록 보기
43/43
post-thumbnail

요즘 웹 개발을 이야기할 때 Next.js를 빼놓기는 어렵다.

별도의 서버를 띄우지 않아도 되는 자체 서버 기능, 그리고 Vercel과 같은 강력한 배포 플랫폼과의 조합은 분명 매력적이다. 실제로 나 역시 이러한 이유로 Next.js를 매우 긍정적으로 사용해 왔고, 한동안은 ‘무적의 프레임워크’처럼 느끼기도 했다. 하지만 이런 생각은 Tanstanck Router를 만나면서 무참히 깨지게 되었다.

이번 글에서는 Next.js에서 Tanstack Router로 마이그레이션하게 된 경험에 대해 공유해 보겠다.

어떤 프로젝트인가?

우선 내가 진행하고 있는 프로젝트는 사내 백오피스 2개가 있다. 2개 모두 전적자들이 세팅을 해두었는데, 하나는 Tanstack Rotuer로 구성되어 있었고, 나머지 하나는 Next.js로 구성되어 있었다.

기술 스택이 다른 2개 어드민을 쓰다 보니 개발 경험도 달랐고, 무엇보다 Tanstack Router가 체감상 훨씬 더 빠르게 느껴졌다. 그리고 고심 끝에 아래와 같은 이유들로 Tanstack Router로 마이그레이션을 진행하기로 결정했다.

어떤 점 때문에 마이그레이션을 결심했는가?

오버스펙

Next.js는 다음과 같은 강력한 기능들을 제공한다.

  • SSR / SSG
  • SEO 최적화
  • 이미지 최적화
  • 서버 액션
  • 다양한 써드파티 연동과 방대한 생태계

하지만 여기서 한 번 다시 생각해 보았다.

  • 어드민에서 SSG가 정말 필요할까?
  • 검색 엔진에 노출될 필요가 있을까?
  • 사내 인프라를 쓰는데, Vercel과 같은 써드파티와 궁합이 중요한가?

이 질문들에 대한 답은 모두 ‘아니다’였다. 그리고 자연스럽게 다음 질문이 따라왔다.

풀스택 프레임워크인 Next.js를 굳이 가져가야 할까?

이 역시 결론은 ‘아니다’였다.

하이드레이션으로 인한 TTI 지연

Next.js는 서버에서 페이지를 만들고, 클라이언트에 자바스크립트와 함께 페이지를 내려준다. 이때 페이지는 빨리 만들어졌을지 몰라도 하이드레이션이 되지 않았을 때 버튼은 그저 그림의 떡이 되는 셈이다. 이는 TTI, 즉 사용자가 첫 인터렉션을 하기까지 걸리는 시간에서 손해를 볼 수 있다. 때문에 버튼을 클릭하지만 버튼이 동작하지 않는 것과 같은 UX를 떨어트리는 원인이 되기 충분했다.

Next.js는 서버에서 HTML을 생성한 뒤, 클라이언트에서 하이드레이션 과정을 거쳐 인터랙션을 활성화한다.

이 과정에서 화면은 빠르게 보이지만 하이드레이션이 끝나기 전까지 버튼은 동작하지 않는 문제가 있다.

즉, TTI(Time To Interactive) 관점에서 손해를 볼 수 있다.

사용자는 버튼을 눌렀는데 반응이 없는 경험을 하게 되고, 이는 UX 저하로 이어질 수 있다.

반면 TanStack Router는 CSR 기반이기 때문에, 이런 종류의 하이드레이션 지연 문제에서 훨씬 자유롭다.

Search Params의 타입 안정성

마이그레이션한 이유 중 하나라고 할 수 있을만큼 정말 좋은 기능이다. 먼저 Next.js의 단점부터 짚어보겠다.

  1. useSearchParams를 사용하려면 상위 컴포넌트를 Suspense로 감싸서 클라이언트에서 사용한다고 항상 명시해야 한다.
  2. 반환되는 값에 대해 정적 타입 추론이 불가능하다.

이와 대비되는 TanStack Router의 장점은 매우 명확하다.

  1. 기본적으로 CSR이므로 불필요한 클라이언트 경계 설정이 필요 없다.
  2. validateSearch + zodValidator 조합을 통해 Search Params에 대한 완전한 타입 안정성을 확보할 수 있다.

이 중에서 2번이 좋은 기능이라고 생각이 된다.

잘못된 타입으로 navigate를 시도하면 페이지 이동이 되지 않는다. 또한 fallback을 통해 잘못된 값이 들어왔을 때, 혹은 기본으로 설정하고 싶은 값을 명확하고 쉽게 정의할 수 있다.

개인적으로 정말정말 강력한 기능이라고 생각하고, zod를 통한 더 자세한 예시는 공식 문서를 참고하기를 바란다.

가벼운 빌드 결과물과 배포 방법

아래는 마이그레이션 전후의 빌드 결과물 비교이다.

.next 폴더 크기

.next 폴더

Next.js 빌드 결과물

dist 폴더 크기

dist 폴더

Vite + Tanstack Router 빌드 결과물

빌드 결과물의 크기가 약 177배로 극단적으로 차이 나는 것을 확인할 수 있었다. 이유는 비교적 단순하다.

Next.js는 아래와 같은 결과물이 포함된다.

  • 빌드 캐시
  • 이미지 최적화 캐시
  • 서버 실행을 위한 각종 산출물

반면 Vite + TanStack Router는 순수 정적 파일 중심의 결과물만 생성한다. 내가 사용하는 어드민의 특성을 다시 보면 아래와 같다.

  • 배포 빈도가 높지 않음 → 빌드 캐시의 이점이 없음
  • 이미지 사용이 없음 → 이미지 최적화 캐싱의 이점이 없음
  • 자체 서버로 우회할 기능이 없음 → 자체 서버가 필요 없음

즉, Next.js의 이미지 최적화나 서버 기능은 전혀 필요하지 않았다.

배포 측면에서도 nginx를 통한 정적 파일 서빙 + CDN 캐싱 조합이 훨씬 단순하고 명확하다고 판단했다.

그렇다면 Next.js는 진짜 쓸모가 없는걸까?

전혀 그렇지 않다. 기술 스택에는 언제나 맥락이 중요하다. 내가 TanStack Router로 마이그레이션해도 괜찮다고 판단한 이유는 다음과 같다.

  • 내부 사용자라는 한정된 사용자 → 개발 환경과 서비스를 사용하는 환경(네트워크 속도, 사용 기기 스펙 등)이 같을거라는 판단
  • SEO, SSR, 서버 기능이 필요 없는 어드민 → Next.js의 강력한 기능들이 오히려 오버스펙

따라서 내 어드민은 서비스를 사용하기에 충분히 좋은 조건을 가진 사용자들이 사용한다는 가정과 다양한 기능을 지원하는 프레임워크를 사용해야할만큼 복잡한 서비스도 아니라고 판단했기에 마이그레이션을 진행했다.

그렇기 때문에 Next.js는 여전히 1인 개발이나 SEO가 중요시되는 서비스 등에는 특화되어 있다고 생각한다.

따라서 아래와 같은 조건이라면 여전히 좋은 선택지라고 생각이 된다.

  • SEO가 중요한 서비스
  • 1인 개발
  • 빠른 MVP 구성
  • 서버 로직과 UI를 강하게 결합해야 하는 경우

마무리하며

이번에 마이그레이션을 진행하면서 ‘은탄환은 없다’는 말에 너무나도 공감을 하게 된 계기가 되었다.

좋은 기술이라도 프로젝트의 성격과 맞지 않으면 오버스펙이 될 수 있다는 점을 몸소 경험했다.

이번 경험을 계기로 앞으로는 유행이나 인지도보다 문제에 맞는 기술 스택을 선택하는 것을 더 중요하게 고민하게 될 것 같다.

0개의 댓글