CSR(Client-Side Rendering) bailout은 미리 렌더(Prerender)되는 라우트에서 서버가 알 수 없는 값을 읽는 클라이언트 컴포넌트를 만나, 가장 가까운 Suspense 경계까지의 클라이언트 컴포넌트 트리를 서버 렌더에서 포기하고 브라우저 렌더로 넘기는 일이다. 대표 원인이 useSearchParams()다. 빌드 때는 ?q=신발 같은 쿼리를 모르기 때문이다.
빌드: Suspense 안쪽은 렌더 포기 → fallback만 HTML에 넣음
응답: 나머지는 완성된 정적 HTML + fallback
브라우저: 하이드레이션 → 주소창에서 쿼리 읽음 → fallback을 실제 컴포넌트로 교체- 경계가 없으면 범위가 페이지 루트까지 커진다. 정적 페이지인데 초기 HTML(HyperText Markup Language)이 사실상 빈 껍데기가 되어 SEO(Search Engine Optimization)와 첫 화면의 이점이 사라진다
- 그래서 Next.js는 프로덕션 빌드에서 이를 감지하면 빌드를 실패시킨다(
Missing Suspense boundary with useSearchParams). 14.x에는 경고로 낮추는 설정(missingSuspenseWithCSRBailout: false)이 있었지만 15부터 없어졌다 - 개발 모드에서는 안 보인다. dev는 요청마다 렌더해서 suspend가 일어나지 않는다.
build에서만 터지는 함정이다 - 해결
useSearchParams를 쓰는 작은 클라이언트 컴포넌트만 Suspense로 감싼다. 나머지는 미리 렌더된다- 서버 컴포넌트 페이지라면
searchParamsprop으로 받아 클라이언트 컴포넌트에 넘긴다 - 라우트가 원래 동적이어야 하면 서버 컴포넌트에서
connection()을 먼저 호출해 그 아래를 미리 렌더에서 뺀다
useRouter나 이벤트 핸들러 자체는 bailout을 일으키지 않는다. 문제는 렌더 결과가 요청 시점 값에 달려 있을 때다- 경계는
useSearchParams를 부르는 컴포넌트의 부모에 둔다. 그 컴포넌트가 자기 JSX 안에<Suspense>를 두면 이미 늦다. 훅은 그 컴포넌트를 렌더하는 순간 실행되기 때문이다
"bailout"은 낙하산으로 탈출한다는 뜻이다. 기술 문서에서는 "원래 하려던 최적화 경로를 포기하고 대체 경로로 빠진다"는 의미로 쓰고, JS(JavaScript) 엔진의 deopt(Deoptimization)와 같은 맥락이다. 경계를 어떻게 둘지는 부분 사전 렌더링(PPR)·'use client'와 클라이언트 경계와 같은 문제다.
서버 렌더 중 에러도 클라이언트 렌더로 넘어간다
빌드 때가 아니라 요청마다 조용히 일어나는 비슷한 경로가 있다. 서버 렌더 중 컴포넌트가 에러를 던지면 React는 렌더를 멈추지 않고, 가장 가까운 Suspense의 fallback을 HTML에 넣은 뒤 클라이언트에서 그 부분을 다시 렌더한다. 클라이언트에서 성공하면 에러는 사용자에게 보이지 않는다.
서버: 데이터 조회 실패(예: 서버 쪽 요청에 사용자 쿠키를 안 넘겨 인증 실패) → throw
→ 가장 가까운 Suspense의 fallback만 HTML에
브라우저: JS 다운로드·실행 → API 다시 호출 → 렌더 → 그제야 본문 표시- 화면은 결국 정상이라 기능 테스트로는 안 잡힌다. 증상은 첫 페인트와 LCP(Largest Contentful Paint)가 같은 시각으로 늦어지는 것(Core Web Vitals)과 에러 모니터링에 쌓이는 서버 렌더 에러다
- 원인을 고친다. 서버에서도 렌더에 필요한 데이터를 확보한다(쿠키 전달, 미리 조회해 넘기기). 비로그인 사용자의 "인증 실패"처럼 정상인 경우는 예외가 아니라 빈 결과로 바꿔 서버 렌더가 끝까지 가게 한다
useSyncExternalStore에getServerSnapshot이 없을 때도 같은 경로로 클라이언트 렌더로 넘어간다(서버 렌더에서 훅이 하는 일)
출처: Next.js - useSearchParams: Prerendering · Missing Suspense boundary with useSearchParams · React - Suspense: Providing a fallback for server errors and client-only content