2025-05-20•Abyan Dimas
Deep Dive: Next.js Server Actions & Mutations
Server Actions changed the game. We used to write:
- Component -> 2.
fetch('/api/user')-> 3. API Route -> 4. Controller -> 5. Database.
Now, we just call the function.
The Syntax
// src/components/Form.tsx
import { createUser } from '@/actions/users'
export default function RegisterForm() {
return (
<form action={createUser}>
<input name="email" />
<button type="submit">Sign Up</button>
</form>
)
}
// src/actions/users.ts
'use server'
export async function createUser(formData: FormData) {
const email = formData.get('email');
await db.user.create({ data: { email } });
revalidatePath('/dashboard');
}
Security Concerns
"Is this SQL Injection waiting to happen?" No, because Server Actions are POST requests behind the scenes. However, you MUST validate inputs.
import { z } from 'zod';
const schema = z.object({ email: z.string().email() });
export async function createUser(formData: FormData) {
const parse = schema.safeParse(Object.fromEntries(formData));
if (!parse.success) return { error: 'Invalid email' };
// Proceed safely
}
Optimistic Updates
Use useOptimistic to show the new state immediately, even before the server responds.
Server Actions bring the simplicity of PHP with the power of React.