Next.js encountered the unstable value Math.random() while prerendering
빠른 답변
- 이 오류는 무엇인가요?
- prerendering 중 Server Component가 <Suspense> 밖에서 Math.random()을 호출하면 발생하는 Next.js 오류입니다.
- 가장 흔한 원인은 무엇인가요?
- prerendering 중 <Suspense> 밖에서 Math.random()을 호출하지 말고, 값을 요청마다 생성하려면 connection() 또는 io() 뒤로 이동하고, 캐시 가능한 값이면 use cache 함수 안에서 생성하며, 클라이언트 값이면 Client Component에서 생성해야 합니다.
- 무엇을 먼저 확인해야 하나요?
- `next dev`의 오류 오버레이에서 실패한 컴포넌트의 파일 경로와 줄 번호를 확인합니다. 해당 위치가 prerendering 중 호출된 `Math.random()`의 코드 위치를 가리키면 이 오류의 확인 기준에 해당합니다.
현재 증상
- 애플리케이션 오류 메시지
먼저 확인할 항목
`next dev`의 오류 오버레이에서 실패한 컴포넌트의 파일 경로와 줄 번호를 확인합니다. 해당 위치가 prerendering 중 호출된 `Math.random()`의 코드 위치를 가리키면 이 오류의 확인 기준에 해당합니다.
빌드 결과에서 `next build --debug-prerender`를 실행하고 사용자 코드의 전체 스택 추적을 확인합니다. 스택 추적이 실패한 컴포넌트의 `Math.random()` 호출 위치를 가리키면 해당 오류와 일치합니다.
수정 후 같은 경로를 다시 로드합니다. 의미 있는 화면이 즉시 표시되고 `<Suspense>` fallback이 스트리밍되는 영역만 덮으면 원문이 제시한 검증 상태에 해당합니다.
환경별 원인과 조치
오류 원문
Next.js encountered the unstable value Math.random() while prerendering
의미
prerendering 중 Server Component가 <Suspense> 밖에서 Math.random()을 호출하면 발생합니다. Cache Components가 활성화된 경우 Next.js는 빌드 시점과 실행 시점에 달라지는 예측할 수 없는 값을 prerendered HTML에 포함할 수 없습니다.
확인
next dev에서 오류가 발생한 경로를 엽니다.- 오류 오버레이에서 실패한 컴포넌트의 파일 경로와 줄 번호를 확인합니다.
- 빌드 결과를 확인하는 경우
next build --debug-prerender를 실행해 사용자 코드의 전체 스택 추적을 확인합니다. - 특정 경로만 확인하려면
next build --debug-build-paths /dashboard /settings형식으로 빌드합니다. - 수정 후 경로를 다시 로드하고, 의미 있는 화면이 즉시 표시되는지와
<Suspense>fallback이 스트리밍되는 영역만 덮는지 확인합니다.
수정 방법
요청마다 값 생성
각 요청마다 다른 값이 필요하면 connection() 또는 io() 뒤에서 값을 생성합니다.
import { connection } from 'next/server'export async function RequestTrace() { await connection() const traceId = Math.random().toString(16).slice(2) return <small>trace: {traceId}</small>}호출 뒤의 컴포넌트를 가장 가까운 <Suspense> 경계로 감싸면 주변 화면은 prerender된 상태로 유지되고 해당 영역만 요청마다 스트리밍됩니다. io()는 next/cache에서 가져와 사용할 수 있으며 prefetch를 막지 않고 use cache 범위와 Client Component 안에서도 사용할 수 있습니다.
값을 캐시
빌드, 배포 또는 cacheLife 기간 동안 하나의 안정적인 값이면 충분한 경우 Math.random()을 use cache가 첫 문장인 함수 안으로 이동합니다.
async function getRandomSeed() { 'use cache' return Math.random()}캐시 기간을 설정하려면 캐시 함수에서 cacheLife()를 사용합니다. 캐시 기간 동안 모든 방문자가 같은 값을 보게 되므로 사용자별 고유 값이나 보안에 민감한 값에는 사용할 수 없습니다.
클라이언트에서 생성
값이 브라우저 화면에만 필요하면 Client Component로 이동하고, 초기 상태를 결정적인 값으로 설정한 뒤 useEffect에서 실제 무작위 값을 할당합니다.
'use client'import { useEffect, useState } from 'react'export function Avatar() { const [color, setColor] = useState('#888') useEffect(() => { setColor(`#${Math.random().toString(16).slice(2, 8)}`) }, []) return <div style={{ background: color }} />}Client Component의 렌더링 중에 값을 바로 생성하면 SSR 중에도 같은 오류가 발생할 수 있습니다. 서버 HTML에 값이 필요하면 부모의 <Suspense> 경계 안에서 처리해야 합니다.
주의 사항
- prerender shell에 포함되는 UI는 결정적이어야 합니다.
<Suspense>fallback,loading.js,error.js,not-found.js,global-error.js도 포함됩니다. - 짧은
cacheLife프로필의 재검증 시간이 prerender의 유효 기간보다 짧으면 값이 prerender에 포함되지 않고 동적 영역이 될 수 있습니다. - 페이지 전체를 하나의
<Suspense>경계로 감싸 빈 shell만 남기면 검증은 통과할 수 있지만 instant navigation의 목적을 훼손합니다. - 요청마다 다른 값이 필요하면 요청마다 생성하는 방법을 사용하고, 캐시 기간 동안 같은 값이면 캐시 방법을 사용하며, 브라우저 화면에만 필요한 값이면 클라이언트 방법을 사용합니다.
관련 오류
Date.now() 및 crypto API도 같은 유형의 prerender 오류를 일으킬 수 있으며, Client Component의 Math.random()은 별도 문서에서 다룹니다.
참고 자료
Next.js · 공식 자료 · 확인 범위: Next.js는 prerendering 중 <Suspense> 밖에서 호출된 Math.random() 값을 정적 HTML에 포함할 수 없습니다., 요청마다 다른 값이 필요하면 connection() 또는 io() 뒤에서 Math.random()을 호출할 수 있습니다., 캐시 가능한 값은 use cache 함수 안에서 생성할 수 있습니다., 브라우저에서만 필요한 값은 Client Component의 useEffect 등에서 생성할 수 있습니다., next dev 오류 오버레이는 실패한 컴포넌트의 파일 경로와 줄 번호를 가리킵니다., next build --debug-prerender는 더 자세한 사용자 코드 스택 추적을 제공합니다. · 확인일: 2026-07-28