Ryan S. Chiang

How to Resolve "[Error] Dynamic server usage: Route used cookies" in NextJS 14

Updated

4 min read

If you are using Next 14 App Router, you may have encountered the build error:

bashGenerating static pages (13/19) [Error]: Dynamic server usage: 
Route /app couldn't be rendered statically because it used cookies. 
See more info here: https://nextjs.org/docs/messages/dynamic-server-error

The NextJS docs linked in the error explain how this arises from using a Next.js function that uses "Async Context" outside of the same call stack as the function that ran it.

The docs give two common explanations for the error:

  1. cookies() being called inside of setInterval

  2. Or cookies() being called inside of setTimeout

The Solution

But there's a third common case that causes this Dynamic server usage error:

  1. cookies() being called inside of a try/catch block

To use cookies() in NextJS server components, you must not wrap it in a try/catch, setInterval, or setTimeout.

Instead of doing this...

jsximport { cookies } from "next/headers";

const HomePage: NextPage<{}> = async () => {
    try {
        const sessionId = cookies().get("sid")?.value ?? "";
        const res = await fetch("...", {
            method: "GET",
            credentials: "include",
            headers: {
                Cookie: `sid=${sessionId}`,
            }
        });
    } catch (err) {
        // not authenticated
        console.log(err);
        redirect("/signin")
    }

    return (
        <div>
            You are signed in.
        </div>
    )
}

export default HomePage;

This looks fine, but it will throw the [Error] Dynamic server usage: Route /app couldn't be rendered statically because it used cookies error when building your app.

Instead, never wrap cookies in a try/catch.

The correct way to use cookies in Server Components:

jsximport { cookies } from "next/headers";

const HomePage: NextPage<{}> = async () => {
    // simply move `cookies` outside of try/catch block
    const sessionId = cookies().get("sid")?.value ?? "";

    try {
        const res = await fetch("...", {
            method: "GET",
            credentials: "include",
            headers: {
                Cookie: `sid=${sessionId}`,
            }
        });
    } catch (err) {
        // not authenticated
        console.log(err);
        redirect("/signin")
    }

    return (
        <div>
            You are signed in.
        </div>
    )
}

export default HomePage;

Now you will avoid the dynamic server usage error.

In short: cookies() cannot be called outside the same call stack as the function that ran it.

Some other things to note about NextJS cookies

Here's a few other important pointers about using cookies in NextJS 14 and above.

Cookies only in Server Action and Route Handler?

You may have read on the docs that you need to use cookies in a Server Action or Route Handler.

This is true, but only for outgoing request cookies.

Reading cookies (cookies().get()) is allowed in a Server Component, which makes it convenient since all pages are by default server-side rendered using the App Router.

How to sending cookies in SSR fetch?

In the code examples above, you may note that I manually set the cookie values in the headers object of the fetch call like so:

jsxconst res = await fetch("...", {
    method: "GET",
    credentials: "include",
    headers: {
        Cookie: `sid=${sessionId}`, // manually send the cookies in SSR fetch
    }
});

We set credentials: "include" not to include our cookies on this request, but to ensure we receive and automatically set cookies that are sent in the response.

For client-side fetch calls, simply using credentials: "include" will properly send cookies.

But when you make a fetch request from a Server Component, NextJS doesn't automatically include the cookies from the incoming request. This behavior is consistent with how cookies are typically handled in server-side environments, where cookies are not automatically passed along to subsequent requests unless explicitly specified.

Wrapping Up

It's a small fix, but never wrap cookies in a try/catch block, setInterval, or setTimeout in a Server Component.

To resolve the "Dynamic server usage" error regarding cookies or other server-side functions, you cannot break outside the same call stack as the function that runs the Next.js function (e.g. calling cookies()).

Hope this helps! As always, let me know if you have any questions or feedback.

Ryan Chiang

Meet the Author

Ryan Chiang

Hello, I'm Ryan. I build things and write about them. This is my blog of my learnings, tutorials, and whatever else I feel like writing about.
See what I'm building →.

If you want an alert when I write a new blog post (not often), you can subscribe below:

0

Comments

Leave a Comment

Your email will not be published. Required fields are marked *

2024

2023

© 2024 Ryan Chiang