Server Actions
A Server Function is an async function marked with 'use server' that runs on the server but can be called from the client. Used for form submissions and mutations it is called a Server Action.
ts
// app/actions.ts
'use server';
export async function createPost(formData: FormData) {
const session = await auth();
if (!session) throw new Error('Unauthorized');
const title = String(formData.get('title'));
await db.post.create({ data: { title, authorId: session.userId } });
updateTag('posts');
}tsx
<form action={createPost}>
<input name="title" />
<button>Publish</button>
</form>Why they are convenient
- No hand-written API route and
fetchcall. - Forms work before hydration (progressive enhancement).
- The response can contain the updated UI after revalidation in one round trip.
useActionStategives the pending state and the returned result.
Security
Every Server Action is a public POST endpoint. Anyone can call it with any arguments, not only through your UI.
- Check authentication and authorization inside every action, not only on the page that renders the form.
- Validate input (e.g. with Zod):
formDataand arguments come from the client. - Do not rely on hidden fields for user ids, take them from the session.
Actions are dispatched one at a time on the client, so they are meant for mutations, not for parallel data fetching.
updated
did you know it?