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:
cookies()
being called inside of setInterval
Or cookies()
being called inside of setTimeout
But there's a third common case that causes this Dynamic server usage
error:
cookies()
being called inside of a try/catch
blockTo 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.
Here's a few other important pointers about using cookies in NextJS 14 and above.
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.
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.
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.
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 →.
Thanks for reading! If you want a heads up when I write a new blog post, you can subscribe below: