Search code examples
next.jscookiesmiddlewarenext.js14

Next 14: how to set cookie in middleware and get it in root layout


react: 18.2.0 next": 14.0.3

my goal is to guarantee existence of a cookie with session id from very beginning. i use middleware for that.

export async function middleware(req: nextrequest) {
   const response = nextresponse.next();
    const ensuredsessionid = await fetchensuresession(
      req.nexturl.origin,
      currentsessionid,
    );
    console.log(`ensured sessionid for url ${req.url}`, ensuredsessionid);
    response.cookies.set("sessionid", ensuredsessionid, {
      path: "/",
      httponly: true,
      samesite: "strict",
      secure: true,
    });

    return response;
    }

I want to use the cookie in my root layout.tsx but it's undefined. However, I can see it in browser's dev tools despite it was undefined in layout. and if I refresh the page, next time i get the cookie in my layout.tsx instantly.

import { cartprovider } from "@storefront/shell/cart/cartcontext";
import { cookies } from "next/headers";

interface props {
 children: react.reactnode;
}

export default async function rootlayout({ children }: props) {
 const session = cookies().get("sessionid");

 console.log("session-Id", session);

 return (
   <cartprovider sessionid={session?.value}>{children}</cartprovider>
 );
}

i expect cookie to be there initially since middleware comes before the layout.tsx. but it's not there. Next.js logs:

✓ Ready in 1773ms
✓ Compiled /src/middleware in 178ms (163 modules)
✓ Compiled /api/ensure-session in 455ms (33 modules)
ensured sessionId for url https://localhost:3000/en f142d570-93a7-4503-a52e-7f9fe580b89f
 ○ Compiling /[lang] ...
 ✓ Compiled /[lang] in 2.9s (3517 modules)
Session-Id undefined
 ○ Compiling /api/trpc/[trpc] ...
 ✓ Compiled /api/trpc/[trpc] in 573ms (2083 modules)

could anyone tell me what i'm missing about understanding of how next.js cookies works?


Solution

  • finally i've got it! When you set cookie in middleware the layout.tsx do not has already set cookie header in it's request indeed, but instead middleware pass a header to set it. Absolutely logical. Hence, to catch it up initially in first render of any RSC like layout.tsx you must look not into cookies() since it hadn't been set yet, but in headers() set-cookies since it gonna be set on response.