Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Server actions for forms

A server action is an asynchronous function that runs on the server, yet you can pass it straight to a form's action attribute. When the form is submitted, Next.js makes the request itself and calls the function with the form data. You do not need to write a separate API for it.

A function that adds a post

First add a function that saves a post to lib/posts.ts:

// lib/posts.ts (add at the end)
export async function addPost(post: Post): Promise<void> {
  posts.push(post);
}

For now posts live in an in-memory array and disappear when the server restarts. In the database lesson the body of this function changes, while the form stays the same.

The actions file

Create app/posts/actions.ts. The 'use server' directive on the first line turns every exported function of the file into a server action:

// app/posts/actions.ts
'use server';
 
import { revalidatePath } from 'next/cache';
import { redirect } from 'next/navigation';
import { addPost } from '@/lib/posts';
 
export async function createPost(formData: FormData) {
  const title = String(formData.get('title'));
  const slug = String(formData.get('slug'));
  const body = String(formData.get('body'));
 
  await addPost({ slug, title, body });
 
  revalidatePath('/posts');
  redirect(`/posts/${slug}`);
}

The action receives a FormData object — field values keyed by their name attribute. After saving, revalidatePath refreshes the posts list and redirect sends the visitor to the new post.

The form

The /posts/new page already exists. Connect the action to it:

// app/posts/new/page.tsx
import { createPost } from '../actions';
 
export default function NewPostPage() {
  return (
    <form action={createPost}>
      <h1>New post</h1>
      <input name="title" placeholder="Title" required />
      <input name="slug" placeholder="Address, e.g. my-first-post" required />
      <textarea name="body" placeholder="Post text" required />
      <button type="submit">Publish</button>
    </form>
  );
}

Open /posts/new, fill in the fields and click "Publish". The browser goes to the new post's page, and the post also appears in the /posts list.

What happens on submit

  1. The browser sends the form data to the server.
  2. Next.js calls createPost with that data.
  3. The function saves the post and clears the list cache.
  4. redirect takes the visitor to the post page.

The page is a server component; no 'use client' was needed. The form works even before JavaScript has loaded in the browser.

Security

A server action is essentially a public address on the server: anyone can call it, not just your form. That is why an action checks the data (next lesson) and the user's rights (the authentication lesson).

Common mistake

Calling redirect inside try...catch. Like notFound(), it works through a special exception, and catch swallows it — no navigation happens. Put redirect after the try block, at the very end of the action.

Thanks for reading!

Donate to the site — we work hard for you.