Next.js Directives

Use the use client, use server, and use cache directives to control where code runs.

TL;DR

  1. Add 'use client' to files that need state, effects, or events.
  2. Add 'use server' to functions the browser may call on the server.
  3. Add 'use cache' to async functions whose results can be reused.

use client

    'use client'

    Mark a file so its components run in the browser and can use hooks.

    'use client';
    import { useState } from 'react';
    
    export function Toggle() {
      const [on, setOn] = useState(false);
      return (
        <button onClick={() => setOn(!on)}>
          {on ? 'On' : 'Off'}
        </button>
      );
    }
    Top of File

    Place the directive above every import, or Next.js ignores it.

    'use client'; // first line
    
    import { useEffect } from 'react';
    One Boundary

    Add it once at the entry point; components it imports are already client code.

    // Form.tsx
    'use client';
    import { Input } from './Input'; // no directive needed

use server

    File-Level

    Mark every export in a file as a Server Function the client can call.

    // app/actions.ts
    'use server';
    
    export async function createPost(form: FormData) {
      const title = form.get('title');
      await savePost(String(title));
    }
    Inline

    Define a Server Function inside a Server Component with an inline directive.

    export default function Page() {
      async function subscribe(form: FormData) {
        'use server';
        await addEmail(String(form.get('email')));
      }
      return <form action={subscribe}>...</form>;
    }
    Form Action

    Pass a Server Function to a form's action prop to run it on submit.

    import { createPost } from './actions';
    
    export default function NewPost() {
      return (
        <form action={createPost}>
          <input name="title" />
          <button type="submit">Save</button>
        </form>
      );
    }

use cache

    cacheComponents

    Turn on Cache Components in your config before using the directive.

    // next.config.ts
    const nextConfig = {
      cacheComponents: true,
    };
    
    export default nextConfig;
    'use cache'

    Cache the result of an async function so repeat calls skip the work.

    export async function getProducts() {
      'use cache';
      return sql`SELECT * FROM products`;
    }
    cacheLife()

    Set how long the cached result stays fresh with a preset profile.

    import { cacheLife } from 'next/cache';
    
    export async function getProducts() {
      'use cache';
      cacheLife('hours');
      return sql`SELECT * FROM products`;
    }

Using Directives Safely

    Validate Input

    Treat every Server Function as a public endpoint and check its arguments.

    'use server';
    
    export async function rename(form: FormData) {
      const name = String(form.get('name') ?? '');
      if (name.length < 2) {
        return { error: 'Name is too short' };
      }
      await saveName(name);
    }
    Check Auth

    Verify the user inside the function, not only on the page that calls it.

    'use server';
    
    export async function deletePost(id: string) {
      const user = await getUser();
      if (!user) throw new Error('Not signed in');
      await removePost(id, user.id);
    }
    Pass Request Data

    Read cookies outside a cached function, then pass the value in as an argument.

    const theme = (await cookies()).get('theme')?.value;
    const data = await getHome(theme ?? 'light');
    
    async function getHome(theme: string) {
      'use cache';
      return loadHome(theme);
    }

Tips

  1. Keep Server Functions in a separate actions.ts file marked 'use server', so both Server and Client Components can import them.
  2. Call cacheLife() inside every 'use cache' function, so the lifetime of the cached data is clear to the next reader.

Warnings

  1. A 'use server' function is a public endpoint, so always validate its input and check the user's permissions inside it.
  2. The 'use cache' directive only works after you set cacheComponents: true in next.config.ts, so enable that option first.

In Practice

FAQ