Pages Router 유지보수 전환과 기술그룹의 검증 배경
토스뱅크 프론트엔드 팀은 운영 중인 핵심 서비스의 차세대 아키텍처를 검토하기 위해 2025년 가을 내부 기술그룹을 구성하고 Next.js App Router 도입 검증을 진행했습니다. 토스뱅크는 기존에 Pages Router를 주로 사용해왔으나, Vercel이 해당 방식을 버그 수정과 보안 패치 위주의 유지보수 모드로 전환하고 신규 기능을 App Router에 집중 배치하면서 기술적 전환 압박을 받았습니다.
토스뱅크 엔지니어들은 컴포넌트 단위 데이터 페칭과 점진적 렌더링, React Server Components(RSC)를 통한 번들 크기 절감 효과가 금융 서비스의 사용자 경험을 개선할 수 있는지 실증하고자 했습니다. 하지만 검증을 마친 기술그룹은 서비스 안정성을 지키면서 App Router로 전환하고 유지하는 비용이 전환으로 얻는 실익을 상회한다고 판단해 도입을 전면 철회하고 Pages Router를 유지하기로 최종 결정했습니다.
WebKit 렌더링 지연과 스켈레톤 유지보수 비용 실측
토스 앱 내부의 인앱 웹뷰 환경에서 App Router의 핵심 기능인 Suspense 기반 스트리밍 SSR을 실측한 결과, 브라우저 렌더링 엔진에 따라 극단적인 렌더링 시점 차이가 나타났습니다. 화면 내 세 영역에 각각 1초, 3초, 5초 지연을 인위적으로 부여한 테스트에서 안드로이드 기반 Chromium은 첫 콘텐츠 표시 시점(FCP) 64밀리초를 기록하며 준비된 영역부터 점진적으로 화면을 표시했습니다.
반면 iOS 환경의 WebKit은 마지막 5초 지연 섹션이 준비될 때까지 화면 표시를 전면 중단하며 5,065밀리초 동안 하얀 화면을 유지했습니다. 이는 Safari 및 WebKit 엔진이 최소 1,024바이트(1KB) 이상의 스트리밍 응답 데이터를 수신하기 전까지 브라우저단에서 렌더링을 지연시키는 버퍼링 정책 때문입니다. 상단에 보이지 않는 더미 SVG를 삽입해 103밀리초로 단축하는 우회책을 적용했으나, 스켈레톤이 실제 데이터로 바뀔 때 높이 차이로 레이아웃 이동(CLS)이 발생하는 2차 문제가 이어졌습니다. 스켈레톤 규격을 맞추어 이동값을 0.138에서 0.036으로 낮췄음에도, 세로 단일 컬럼 웹뷰에서 모든 섹션의 로딩 높이를 수동 동기화해야 하는 관리 부담이 가중되었습니다.
서버 컴포넌트의 이점과 금융 웹뷰 도메인의 격리 한계
App Router의 서버 컴포넌트(RSC) 환경은 서버 전용 코드를 클라이언트 번들에서 완전히 격리하여 초기 로딩 부하를 줄이고, next/headers의 headers() API를 통해 인증 토큰을 데이터 호출 로직 내부에서 직접 주입할 수 있는 구조적 장점을 제공합니다. 토스뱅크 역시 package.json의 조건부 export를 구성하여 동일한 호출 경로에서 서버 환경과 브라우저 환경이 자동으로 분기되도록 데이터 페칭 코드를 단순화하는 성과를 거두었습니다.
그러나 금융 웹뷰의 비즈니스 특성상 이 장점을 극대화하기는 어렵습니다. 토스뱅크 화면은 버튼, 입력 폼, 네이티브 앱과 통신하는 앱 브릿지 호출 등 클라이언트 상호작용 비중이 높아 실질적으로 RSC를 적용할 수 있는 영역이 데이터 선조회 구간으로 제한되었습니다. 특히 브라우저 밖에서도 예외를 던지지 않도록 설계된 앱 브릿지 라이브러리는 RSC 내에서 잘못 호출되어도 에러 없이 침묵 실패를 유발하여 장애 추적을 어렵게 만들었습니다. 또한 다중 사용자가 공유하는 서버 캐시를 활용할 때 캐시 키에 사용자 식별자를 누락하면 다른 고객의 금융 정보가 노출될 수 있어 엄격한 학습과 검증 비용이 수반되었습니다.
점진적 마이그레이션 과정에서 드러난 공식 라우터 결함
안전한 전환을 위해 Pages Router와 App Router를 공존시키며 화면을 점진적으로 전환하려던 계획은 프레임워크 자체의 경로 판별 버그로 인해 중단되었습니다. basePath 설정이 적용된 환경에서 Pages Router 페이지 간 클라이언트 이동을 수행할 때, 이동 대상 주소 앞에 basePath가 중복 삽입되며 사용자에게 404 에러가 반환되는 현상이 발견되었습니다.
원인을 분석한 결과 Next.js 클라이언트 라우터가 대상 경로의 라우터를 판별하기 위해 빌드 시점에 생성하는 블룸 필터(BloomFilter)의 구조적 한계가 확인되었습니다. App Router에 등록된 동적 라우트(/a/[id])가 블룸 필터 내에 부모 경로인 /a로 등록되었고, 이로 인해 Pages Router의 /a/a 경로가 App Router 경로로 잘못 분류되었습니다. 오판정이 발생하자 클라이언트 네비게이션이 중단되고 서버로 전체 페이지를 다시 요청하는 하드 네비게이션이 트리거되었으며, 이때 Pages Router가 이미 포함된 basePath를 확인 없이 한 번 더 덧붙여 요청을 전송한 것입니다. 이 결함은 Next.js 공식 저장소의 Issue #47486으로도 보고되어 있으며, 안정성을 위해 선택한 공존 방식이 역으로 기존 서비스의 가용성을 훼손하는 결과를 낳았습니다.
관측성 공백과 프레임워크 도입에 대한 실무적 시사점
엔지니어링 팀은 거대 생태계를 갖춘 프레임워크라도 도메인 특화 결함이 빠르게 해결되지 않는다는 점에 주목했습니다. Pages Router에서는 router.pathname을 통해 화면 패턴(/blog/[slug])을 추출하여 지표를 집계할 수 있었으나, App Router의 usePathname()은 실제 완성 주소(/blog/hello-world)만 반환하여 통합 로깅 체계를 구축하는 데 제약이 있었습니다. 라우트 패턴을 제공하려는 PR은 2025년 10월 개설된 이후에도 장기간 초안 상태에 머물렀고, router.events의 부재로 인해 페이지 전환 수명주기를 추적하기 위한 커스텀 패키지를 별도로 제작해야 했습니다.
이번 사례는 메이저 프레임워크가 제시하는 청사진이 특정 비즈니스 런타임과 완벽히 부합하지 않을 수 있음을 시사합니다. 최신 기술 표준을 맹목적으로 추종하기보다, 네이티브 웹뷰 엔진 제약, 공통 모듈 호환성, 관측 인프라 유지보수 비용을 면밀히 측정하고 기존 체제를 방어적으로 유지하는 결정 또한 실무적으로 타당한 엔지니어링 전략이 될 수 있습니다. 다만 실험 플래그를 통한 블룸 필터 비활성화 영향이나 향후 릴리스의 개선 여부는 장기적으로 지속 추적할 필요가 있습니다.
출처
토스테크의 원출처와 본문에 표시한 참고자료를 바탕으로 한국어로 재구성했습니다. ‘ARCH.B 분석’은 자료를 읽고 덧붙인 편집 해석입니다.
App Router의 장점은 우리에게도 장점일까요? (새 창)


