NextJS "Dynamic Server Error"

Yechan Jung·2024년 12월 26일
post-thumbnail

문제: Dynamic Server Error

Dev Mode 에서는 예상한대로 라우팅이 되었으나, 빌드를 하면 static page가 다른 페이지로 라우팅 되는 이슈가 있었다. (try-catch 사용 시)

Next.js 15(App Router)를 사용할 때, cookies(), headers(), 또는 useSearchParams()와 같은 서버 전용 함수를 조건문이나 동적 로직(예: try-catch 블록이나 if 문) 안에서 호출하면 “Dynamic Server Error” 오류가 발생할 수 있습니다.

Next.js는 서버 함수가 서버 컴포넌트의 최상위에서 무조건적으로 호출되어야 한다고 요구합니다. 조건부 호출은 Next.js가 서버 컴포넌트를 빌드 시간에 정적 분석하고 최적화하는 것을 방해하기 때문입니다.


왜 이런 문제가 발생할까?

  1. 정적 분석: Next.js는 빌드 시 서버 컴포넌트를 최적화(예: 스트리밍, 캐싱 등)하기 위해 정적 분석을 수행합니다.
  2. 결정성(Determinism): 조건부 또는 동적 호출은 함수가 항상 실행되지 않을 수 있다는 의미이며, 이는 Next.js가 예측 가능한 서버 동작을 보장하기 어렵게 만듭니다.
  3. 오류 트리거: cookies()try-catch나 조건문 안에 두면 불확실성이 생기고, 이로 인해 Next.js가 빌드 시간에 “Dynamic Server Error”를 발생시킵니다.

문제의 예시

// ❌ 이 코드는 "Dynamic Server Error"를 발생시킵니다
export default async function Page() {
  try {
    const cookieStore = await cookies(); // 동적 서버 사용
    const accessToken = cookieStore.get("accessToken")?.value;

    if (!accessToken) {
      redirect("/?error=NO_TOKEN");
    }

    return <SomePage />;
  } catch (error) {
    console.log(error);
    redirect("/");
  }
}

문제점

  • cookies() 함수가 try 블록 안에서 호출됩니다. Next.js는 이를 조건부 호출로 인식하며, 항상 실행된다고 보장할 수 없습니다.

해결 방법

서버 전용 API 호출을 서버 컴포넌트의 최상위로 이동시키고, 조건문 바깥에서 호출해야 합니다.

// ✅ 해결: cookies()를 최상위에서 무조건적으로 호출
export default async function Page() {
  const cookieStore = await cookies(); // 최상위에서 무조건적으로 호출

  try {
    const accessToken = cookieStore.get("accessToken")?.value;

    if (!accessToken) {
      redirect("/?error=NO_TOKEN");
    }

    return <SomePage />;
  } catch (error) {
    console.log(error);
    redirect("/");
  }
}

왜 이 방법이 동작할까?

  • cookies()를 최상위에서 호출함으로써, Next.js는 이를 정적으로 분석하고 빌드 프로세스 중에 최적화할 수 있습니다.

Understanding and Resolving the “Dynamic Server Error” in Next.js

핵심 정리

  1. 서버 API를 최상위에서 호출: cookies(), headers()와 같은 호출은 항상 서버 컴포넌트의 최상위에 위치시킵니다.
  2. 조건문 또는 동적 래핑 방지: 이러한 호출을 try-catch 블록이나 if 문 안에서 사용하지 마세요.
  3. 정적 로직 유지: Next.js의 결정성 요구사항에 맞춰, 정적 로직을 사용해 빌드 시간 오류를 방지하세요.

이 패턴을 따르면 “Dynamic Server Error”를 방지하고, Next.js에서 서버 컴포넌트를 매끄럽게 사용할 수 있습니다. 🚀

The Issue: Dynamic Server Usage

When working with Next.js 15 (App Router), you might encounter a “Dynamic Server Error” if you use server-only functions like cookies(), headers(), or useSearchParams() inside conditional or dynamic logic (e.g., try-catch blocks or if statements).

This happens because Next.js requires server functions to be called unconditionally at the top level of server components. Conditional or dynamic usage prevents Next.js from statically analyzing and optimizing your server component during build time.

Why This Happens

  1. Static Analysis: Next.js performs static analysis during the build to optimize server components (e.g., for streaming and caching).
  2. Determinism: Conditional or dynamic calls mean the function might not always execute, which makes it harder for Next.js to guarantee predictable server-side behavior.
  3. Error Trigger: Wrapping cookies() inside try-catch or conditionals introduces uncertainty, causing Next.js to throw a build-time “Dynamic Server Error”.

Example of the Problem

// ❌ This code throws a "Dynamic Server Error"
export default async function Page() {
  try {
    const cookieStore = await cookies(); // Dynamic server usage
    const accessToken = cookieStore.get("accessToken")?.value;

    if (!accessToken) {
      redirect("/?error=NO_TOKEN");
    }

    return <SomePage />;
  } catch (error) {
    console.log(error);
    redirect("/");
  }
}

What’s wrong?

  • The cookies() function is called inside a try block. Next.js sees this as a conditional call and cannot guarantee it always runs.

How to Fix It

Move your server-side API calls to the top level of your server component, outside of any conditional logic.

// ✅ Fixed: Unconditional top-level call to cookies()
export default async function Page() {
  const cookieStore = await cookies(); // Called unconditionally at the top level

  try {
    const accessToken = cookieStore.get("accessToken")?.value;

    if (!accessToken) {
      redirect("/?error=NO_TOKEN");
    }

    return <SomePage />;
  } catch (error) {
    console.log(error);
    redirect("/");
  }
}

Why this works:

  • cookies() is now called unconditionally at the top level, allowing Next.js to statically analyze the component and optimize it during the build process.

Key Takeaways

  1. Call Server APIs at the Top Level: Always place calls like cookies() or headers() at the top of your server components.
  2. Avoid Conditional or Dynamic Wrapping: Don’t wrap these calls inside try-catch blocks or if statements.
  3. Use Static Logic for Framework Optimization: Ensure your server-side code adheres to Next.js’s deterministic execution requirements to avoid build-time errors.

By following this pattern, you’ll avoid the “Dynamic Server Error” and ensure your server components work seamlessly in Next.js. 🚀

위 글은 원글을 바탕으로 AI에 의해 작성되었습니다.

참고: https://nextjs.org/docs/messages/dynamic-server-error

profile
꿈꾸는 개발자

0개의 댓글