Issues with cookies in server actions

I have a server action that destroys the session:
./src/app/actions/killSession.ts

'use server'

import {cookies} from 'next/headers'
import {getIronSession} from 'iron-session'
import {SessionSchema} from '@schemas/session'
import {ironSessionProps} from '@server/ironSessionProps'

export const killSession = async () => {
  const session = await getIronSession<SessionSchema>(
    await cookies(),
    ironSessionProps,
  )
  session.destroy()
  console.log('session destroyed')
}

which I am trying to execute from the template of my logged out page layout
./src/app/(logout-pathways)/layout.tsx

'use server'

import React from 'react'
import {killSession} from '@actions/killSession'

export default async function PageLayout({
  children,
}: Readonly<{
  children: React.ReactNode
}>) {
  await killSession()

  return {children}
}

But I get the following error:

I see the issue with your code. The error “Cookies can only be modified in a server actions or route handler” is occurring because you’re trying to modify cookies directly in a Server Component layout file.

While both files have the ‘use server’ directive, there’s an important distinction:

  • Your killSession.ts is correctly set up as a server action
  • Your layout component is a Server Component, not a server action

In Next.js, cookies can only be modified in:

  1. Server Actions (functions marked with ‘use server’)
  2. Route Handlers (API routes)

You probably try something like:

import React from 'react'
import LogoutHandler from './logout-handler'

export default function PageLayout({
  children,
}: Readonly<{
  children: React.ReactNode
}>) {
  return (
    <>
      <LogoutHandler />
      {children}
    </>
  )
}

Then create a client component that calls your server action:

'use client'

import { useEffect } from 'react'
import { killSession } from '@actions/killSession'

export default function LogoutHandler() {
  useEffect(() => {
    killSession()
  }, [])
  
  return null
}

This approach uses a client component with useEffect to call your server action when the component mounts . The client component is rendered inside your layout, but doesn’t affect the UI since it returns null.

2 Likes

Hmmm, this isn’t really what I want as I wanted the server component to await the session being destroyed

Hi @mildfuzz, you can use await in the Server components but you can’t write cookies in a server component, you can only read one. As explained in the docs:

cookies is an async function that allows you to read the HTTP incoming request cookies in Server Components, and read/write outgoing request cookies in Server Actions or Route Handlers.

So, as @swarnava pointed out, you should be performing the cookie writes in Server Actions.

I hope this helps.