Search code examples
javascriptnext.jscookies

Unable to setcookies in app router in Next.js


I am learning next.js and the would like to set a cookie as in the code below.

The code returns an error: "Unhandled Runtime Error. Error: Cookies can only be modified in a Server Action or Route Handler."

I thought nextjs components were server components by default. I am using the app router.

I have googled, and have not managed to solve the issue.

Thank you.

import {cookies} from "next/headers";

function doit() {

    return new Promise<string>((resolve, reject) =>
    {
      setTimeout(
        ()=>
        {
          resolve("doit");
        }, 2000);
    });
  }

  const Home: React.FC = async () => {
  
    let results:string = await doit();

    if(results=="doit")
    {
        cookies().set("done", "true")
    }

    return (
      <div>
        <h1>H1 text</h1>
       </div>
    );
  }
  
  export default Home;

Solution

  • As far as I am concerned the Next.js has some limitation. You are trying to set a cookie on the client side within a Next.js component. Next.js has certain restrictions on modifying cookies, and they can only be modified in a Server Action or Route Handler. You have to implement the Server Action/Route Handler then make a request to set the cookies.

    import { NextApiRequest, NextApiResponse } from 'next';
    
    export default async function handler(req: NextApiRequest, res: NextApiResponse) {
    // Rest of implementation goes here
      let results: string = await doit();
    
      if (results === 'doit') {
        res.setHeader('Set-Cookie', 'done=true');
      }
    
      res.status(200).json({ message: 'Success' });
    }
    
    function doit() {
      return new Promise<string>((resolve, reject) => {
        setTimeout(() => {
          resolve('doit');
        }, 2000);
      });
    }
    

    That would be the api handler for request for Cookies. You can use fetch/axios to fetch the data from the actual Home component which you sent. Make sure of course to place this on the server-side, f.e some server which provides the responses of your requests.

    import { useEffect } from 'react';
    import axios from 'axios';
    
    const Home: React.FC = () => {
      useEffect(() => {
        const fetchData = async () => {
          try {
            const response = await axios.get('/api/set-cookie');
            console.log(response.data);
          } catch (error) {
            console.error('Error setting cookie:', error);
          }
        };
    
        fetchData();
      }, []);
    
      return (
        <div>
          <h1>H1 text</h1>
        </div>
      );
    };
    
    export default Home;
    

    Inside the useEffect you can implement logic for handling the obtained data, remember also that you should replace /api/set-cookies with your actual path.

    This article should be helpful: https://maxschmitt.me/posts/next-js-cookies