2026. 7. 12.

Next.js 개발은 되는데 빌드만 실패할 때, 검색 화면만 감싸서 통과하는 법

Next.js App Router에서 개발 화면은 정상인데 빌드가 useSearchParams 오류로 멈출 때, 작은 Client Component와 Suspense 경계로 수정 범위를 줄이고 빌드 출력으로 확인하는 순서다.

3 min read
Next.js 개발은 되는데 빌드만 실패할 때, 검색 화면만 감싸서 통과하는 법 대표 이미지

로컬 개발 화면은 정상인데 npm run build에서 useSearchParams() should be wrapped in a suspense boundary가 뜨면 CSS나 검색 로직부터 다시 쓸 문제가 아니다. Next.js 공식 문서는 개발 모드가 route를 요청할 때 렌더링하므로 이 문제가 드러나지 않을 수 있지만, 정적으로 렌더링되는 프로덕션 빌드에서는 useSearchParams를 쓰는 Client Component가 Suspense 경계 밖에 있으면 실패한다고 설명한다.

해결의 첫 선택은 페이지 전체를 동적으로 바꾸는 것이 아니다. 쿼리 값을 읽는 작은 Client Component를 분리하고, 그 컴포넌트 바로 위를 Suspense로 감싼다. 수정이 끝났다는 기준도 개발 화면이 아니라 npm run build 성공 출력이다.

로컬 개발 화면은 정상인데 프로덕션 빌드 터미널에서 useSearchParams 오류가 난 상황

useSearchParams를 쓰는 작은 컴포넌트만 감싼다

먼저 훅을 쓰는 부분을 Client Component로 떼어 낸다. 검색어를 읽는 기능만 맡기면 수정 범위와 로딩 범위가 함께 줄어든다.

// app/search/search-panel.tsx
'use client'

import { useSearchParams } from 'next/navigation'

export default function SearchPanel() {
  const searchParams = useSearchParams()
  const query = searchParams.get('q') ?? ''

  return <p>검색어: {query || '없음'}</p>
}

Page는 Server Component로 남겨 두고 SearchPanel만 감싼다. fallback은 쿼리 값이 준비되기 전에 보일 짧은 대체 UI다.

// app/search/page.tsx
import { Suspense } from 'react'
import SearchPanel from './search-panel'

export default function Page() {
  return (
    <main>
      <h1>검색</h1>
      <Suspense fallback={<p>검색어를 확인하는 중...</p>}>
        <SearchPanel />
      </Suspense>
    </main>
  )
}

Next.js의 정적 렌더링 예제도 같은 구조를 쓴다. 이 경계 위쪽은 정적 HTML로 남고, 훅을 쓰는 부분부터 가장 가까운 Suspense 경계까지만 클라이언트에서 렌더링된다. React 공식 문서도 자식이 준비되지 않았을 때 가장 가까운 경계가 fallback을 표시한다고 설명한다.

Page의 정적 영역과 Suspense로 감싼 SearchPanel의 경계를 보여주는 구조도

개발 화면이 정상이어도 프로덕션 빌드는 다른 검사를 한다

이 오류가 당황스러운 이유는 npm run dev에서 검색 화면이 실제로 작동하기 때문이다. Next.js의 useSearchParams 공식 문서는 개발 중에는 route가 온디맨드로 렌더링돼 useSearchParams가 중단되지 않을 수 있다고 밝힌다. 반면 정적 페이지의 프로덕션 빌드는 쿼리 값이 필요한 클라이언트 영역을 미리 구분해야 한다.

따라서 AI에게 "개발 화면이 된다"는 설명만 주면 검증 조건이 빠진다. 오류 문구, 훅이 있는 파일, 해당 컴포넌트를 부르는 Page, npm run build 결과를 함께 줘야 한다. use client를 어디까지 붙일지 헷갈리면 Next.js 버튼 오류에서 Client 경계를 고르는 순서를 먼저 적용할 수 있다.

다음 검색으로 호출 위치를 좁힌다.

rg "useSearchParams" app src

rg가 없다면 편집기의 전체 검색으로 useSearchParams를 찾는다. 호출 파일을 찾은 뒤에는 그 컴포넌트가 어느 Page나 Layout에서 렌더링되는지 위로 따라간다. 루트 Layout 전체를 감싸기보다 검색 패널처럼 쿼리가 필요한 영역 바로 위에 경계를 둔다.

Suspense 대신 다른 경로를 고를 때는 렌더링 의도를 먼저 정한다

모든 useSearchParams 사용을 같은 방식으로 고칠 필요는 없다. 필요한 값과 렌더링 시점에 따라 경로가 갈린다.

상황먼저 고를 경로이유
정적 Page 안의 검색·필터 UI가 쿼리를 읽는다작은 Client Component + Suspense정적 영역을 유지하면서 필요한 부분만 클라이언트 렌더링한다.
Server Component인 Page에서 쿼리 값으로 데이터를 고른다Page의 searchParams propClient 훅을 추가하지 않고 서버에서 값을 읽을 수 있다.
요청마다 달라지는 동적 렌더링이 페이지의 의도다Server Component에서 await connection() 검토아래 트리를 프리렌더링에서 제외한다.

현재 Next.js 문서는 동적 렌더링이 의도일 때 예전의 dynamic = 'force-dynamic'보다 connection()을 권장한다. 다만 빌드 오류를 없애려고 무조건 동적으로 바꾸면 정적 렌더링을 포기하는 결정까지 함께 생긴다. 검색 패널 하나 때문에 전체 route를 동적으로 바꾸지 말고, 먼저 작은 Suspense 경계가 제품 의도에 맞는지 확인한다.

npm run build가 끝까지 성공해야 수정이 끝난다

수정 뒤에는 개발 서버만 새로고침하지 않는다. 다음 명령으로 프로덕션 빌드를 다시 실행한다.

npm run build

한 route를 고치면 빌드가 다음 route의 같은 오류를 보여 줄 수 있다. 첫 오류가 사라졌다는 사실과 전체 빌드가 성공했다는 사실은 다르다. 아래 네 줄을 차례로 확인한다.

  1. 전체 검색으로 useSearchParams 호출 파일을 찾았다.
  2. 호출을 작은 Client Component에 두고 가장 가까운 부모에 Suspense를 추가했다.
  3. fallback이 빈 화면 대신 짧은 상태를 보여 준다.
  4. npm run build가 오류 없이 끝까지 완료됐다.
useSearchParams 호출 찾기, 작은 컴포넌트 분리, Suspense 추가, 빌드 재실행 순서

AI 코딩 도구에는 아래처럼 요청한다. 페이지 전체 재작성보다 수정 파일과 성공 조건을 제한하는 프롬프트다.

Next.js App Router 빌드에서
"useSearchParams() should be wrapped in a suspense boundary" 오류가 납니다.

1. useSearchParams를 호출하는 가장 작은 Client Component를 찾으세요.
2. 그 컴포넌트 바로 위에 Suspense와 짧은 fallback을 추가하세요.
3. Page 전체를 Client Component나 동적 렌더링으로 바꾸지 마세요.
4. 바꾼 파일과 이유를 보여 주고 npm run build로 검증하세요.

빌드가 계속 실패하면 오류가 가리키는 route와 파일을 다시 읽는다. 배포 로그 자체를 어디서부터 볼지 막혔다면 Vercel 배포 실패에서 먼저 볼 로그로 이어서 확인할 수 있다. 오늘의 완료 상태는 단순하다. npm run build가 끝까지 성공하고, 검색 쿼리가 있는 URL과 없는 URL에서 모두 fallback 뒤의 화면이 정상적으로 보이면 된다.

이 글은 AI 코딩과 개발 학습의 일반 정보 제공 목적입니다. 도구, 모델, 커리큘럼, 요금은 버전과 시점에 따라 달라질 수 있으므로 실습이나 도입 전 공식 문서와 최신 릴리스 노트를 확인하세요.

참고 출처

다음으로 읽을 기사

같은 흐름으로 이어 읽기 좋은 기사만 추려 보여줍니다.

댓글 0

이 글을 읽은 독자들의 생각을 나눠보세요.

비밀번호(선택)

첫 번째 댓글을 남겨보세요

여러분의 생각이 다른 독자에게 도움이 됩니다.