The Ultimate Guide to Managing Cookies in Next.js 14

Updated: December 18, 2023 By: Frienzied Flame Post a comment

Cookies are small pieces of data that are stored by the browser and sent to the server with every request. They are often used to store user preferences, authentication tokens, session data, and other information. In Next.js 14, you can use the cookies() function from the next/headers module to access and manipulate cookies in your server components, route handlers, middleware, and server actions.

Managing Cookies with the cookies() function

To set a cookie, you need to use the cookies().set() method, which takes a cookie name, value, and options as arguments. The options can include properties such as maxAge, httpOnly, secure, sameSite, etc. You can only set cookies in a Server Action or Route Handler, because HTTP does not allow setting cookies after streaming starts.

To read a cookie, you need to use the cookies().get() method, which takes a cookie name as an argument and returns an object with the name and value of the cookie. If the cookie is not found, it returns undefined. If multiple cookies match the name, it returns only the first one.

To delete a cookie, you can use the cookies().delete() method, which takes a cookie name as an argument and removes the cookie from the response. Alternatively, you can set a new cookie with the same name and an empty value, or set the maxAge or expires option to a value in the past.

Example: Managing Cookies in a Route Handler

Here is a complete example (with explanations in the comments) of how to set, read, and delete a cookie named jwt in a Route Handler:

// app/api/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { cookies } from 'next/headers';

export async function POST(request: NextRequest) {
    // set a cookie named jwt with a value and some options
    cookies().set('jwt', 'some-token', {
        maxAge: 60 * 60 * 24, // one day in seconds
        httpOnly: true, // prevent client-side access
        sameSite: 'strict', // prevent cross-site requests
    });

    // read the cookie named jwt and log its value
    const jwt = cookies().get('jwt')?.value;
    console.log(jwt); // some-token

    // delete the cookie named jwt
    cookies().delete('jwt');

    // return a JSON response
    return Response.json({ message: 'Cookie demo' });
}

To test the code above, you can use a tool like Postman or curl to send a POST request to the /api route. For example, using curl, you can run the following command in a terminal:

curl -X POST http://localhost:3000/api

You should see the following output in the terminal:

{"message":"Cookie demo"}

You should also see the following output in the console where you run the Next.js app:

some-token

Using Cookies in Middleware

Using cookies in middleware in Next.js 14 is similar to using cookies in Route Handlers or Server Actions. You can use the cookies object from the next/headers module to access and manipulate cookies in your middleware. You can use the cookies().set(), cookies().get(), and cookies().delete() methods to set, read, and delete cookies respectively. You can also pass options such as maxAge, httpOnly, secure, sameSite, etc. to customize your cookies.

Below is an example that demonstrates how to use cookies in middleware:

// middleware.ts
import { NextRequest, NextResponse } from 'next/server';

export async function middleware(request: NextRequest) {
  // get the cookie named name
  const name = cookies().get('name')?.value;
  // if the cookie is not set, set it to a default value
  if (!name) {
    cookies().set('name', 'Guest', {
      maxAge: 60 * 60 * 24, // one day in seconds
      httpOnly: true, // prevent client-side access
      sameSite: 'strict', // prevent cross-site requests
    });
  }
  // return the next response
  return NextResponse.next();
}

Server Actions and Cookies

Recent versions of Next.js introduced the concept of Server Actions. These are functions that you can export from your components and are triggered by an action, such as submitting a form.

import { cookies } from "next/headers";

export default function Message() {
  async function markAsSeen() {
    "use server";
    cookies().set("viewedWelcomeMessage", "true");
  }
  const viewedWelcomeMessage = cookies().has("viewedWelcomeMessage");
  if (viewedWelcomeMessage) {
    return <div>Welcome back!</div>;
  }
  return (
    <form action={markAsSeen}>
      Welcome! <button type="submit">Mark as seen</button>
    </form>
  );
}

Managing Cookies with Pages Router (Legacy)

This section is for developers who prefer to use the old-fashioned /pages directory. Here you have the getServerSideProps function, which is executed server-side before rendering the page. It allows you to both get and set HttpOnly cookies. Here’s a sample code snippet to illustrate this:

import { GetServerSideProps } from "next";

export const getServerSideProps: GetServerSideProps = async (context) => {
  const viewedWelcomeMessage = context.req.cookies.viewedWelcomeMessage;
  if (viewedWelcomeMessage === "true") {
    return { props: { message: "Welcome back!" } };
  }
  context.res.setHeader("Set-Cookie", "viewedWelcomeMessage=true");
  return { props: { message: "Welcome!" } };
};

See also:

Working with Cookies in API Routes (Legacy)

Setting cookies within API Routes (in the /pages directory) in Next.js is simple and intuitive. Here’s how you can set a cookie within an API Route:

import { NextApiRequest, NextApiResponse } from "next";
import cookie from "cookie";

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse<{ message: string }>
) {
  const viewedWelcomeMessage = req.cookies.viewedWelcomeMessage;
  if (viewedWelcomeMessage === "true") {
    return res.status(200).json({ message: "Welcome back!" });
  }
  res.setHeader("Set-Cookie", cookie.serialize("viewedWelcomeMessage", "true"));
  return res.status(200).json({ message: "Welcome!" });
}

Client-Side Cookies in Next.js 14

While we’ve focused primarily on server-side cookies, Next.js also supports client-side cookies. Libraries such as react-cookie or universal-cookie can provide a user-friendly experience.

const [cookies, setCookie] = useCookies(["name"]);

Best Practices

While managing cookies in Next.js 14, adhere to the following best practices:

  • Always use HttpOnly cookies for sensitive data to mitigate the risk of XSS attacks.
  • Use localStorage for storing non-sensitive information.
  • Regularly delete cookies that have served their purpose.

Potential Pitfalls

Despite the ease of managing cookies in Next.js 14, there are potential pitfalls to be aware of:

  • Modifying the request in middleware doesn’t impact the request anywhere else.
  • Setting multiple cookies requires an array of cookie strings to prevent overwriting.

Conclusion

You’ve learned how to set, read, and delete cookies in Next.js 14 (either you use the new /app directory or the old /pages directory). I hope the instructions and code examples in the article can help you in some way. Happy coding & have a nice day. See you again in other tutorials on Sling Academy!