Forms posted to Server Actions

When you pass a Server Action straight to a form action attribute, Next.js wires the form to post directly to the server. If JavaScript is still loading or disabled, the form still works because HTML forms have always been able to post to a URL. That is progressive enhancement, and you get it for free.

app/books/new/page.tsx
tsx
import { redirect } from 'next/navigation';
import { db } from '@/lib/db';
import { books } from '@/lib/schema';

async function createBook(formData: FormData) {
  'use server';
  const title = formData.get('title') as string;
  const author = formData.get('author') as string;

  await db.insert(books).values({ title, author });
  redirect('/books');
}

export default function NewBookPage() {
  return (
    <form action={createBook}>
      <input name="title" required />
      <input name="author" required />
      <button>Save</button>
    </form>
  );
}

A form that submits to a Server Action without any JavaScript glue.

The use server directive can live at the top of a function, not just a file. That lets you colocate the action with the page that uses it. For one-off actions, inline is great. For actions shared across pages, put them in a dedicated actions.ts file.

Quiz: Quiz

Loading practice…