DEV Community

Atlas Whoff
Atlas Whoff

Posted on

Next.js Server Actions vs API Routes: When to Use Each

Next.js Server Actions vs API Routes: When to Use Each

Next.js 14 has two ways to handle server-side logic: Server Actions and API Routes. They're not interchangeable. Here's the decision framework.


What They Are

API Routes (app/api/*/route.ts): HTTP endpoints. Called via fetch, accessible from any client — browser, mobile app, curl, third-party.

Server Actions ('use server'): Async functions that run on the server, called directly from React components. No explicit HTTP request in your code.


Server Actions: The Syntax

// app/actions/profile.ts
'use server';

import { auth } from '@/auth';
import { db } from '@/lib/db';
import { revalidatePath } from 'next/cache';

export async function updateProfile(formData: FormData) {
  const session = await auth();
  if (!session?.user) throw new Error('Unauthorized');

  const name = formData.get('name') as string;

  await db.user.update({
    where: { id: session.user.id },
    data: { name },
  });

  revalidatePath('/dashboard/profile');
}
Enter fullscreen mode Exit fullscreen mode
// app/dashboard/profile/page.tsx (Server Component)
import { updateProfile } from '@/app/actions/profile';

export default function ProfilePage() {
  return (
    <form action={updateProfile}>
      <input name='name' />
      <button type='submit'>Save</button>
    </form>
  );
}
Enter fullscreen mode Exit fullscreen mode

No useState, no fetch, no API route — the form submits directly to the server function.


Use Server Actions When

Form submissions in Server Components. The canonical use case. No client-side JavaScript required for basic form handling.

Mutations from client components that don't need a public API.

'use client';
import { updateProfile } from '@/app/actions/profile';

export function ProfileForm() {
  return (
    <form action={updateProfile}>
      <input name='name' />
      <button>Save</button>
    </form>
  );
}
Enter fullscreen mode Exit fullscreen mode

Progressive enhancement. Server Actions work without JavaScript enabled. API routes require JS to call fetch.

Simple CRUD operations where you control both the client and server.


Use API Routes When

Third-party integrations call your server. Stripe webhooks, GitHub webhooks, any external service sending HTTP requests — these need a real URL endpoint.

Mobile apps or non-React clients need to access your backend.

Streaming responses. Server Actions don't support streaming. AI chat routes that stream Claude/OpenAI responses need API routes.

You need custom HTTP headers or status codes.
Server Actions always return 200 on success. API routes let you return 201, 400, 401, 429, etc.

The endpoint needs to be cacheable by CDN or browser.


Side-by-Side Comparison

Server Actions API Routes
Called from React components directly fetch() or any HTTP client
External access No (Next.js internal only) Yes (public URL)
Streaming No Yes
Custom HTTP status No Yes
Webhooks No Yes
Progressive enhancement Yes No
Boilerplate Less More

Real-World Decision Examples

Task Use
Update user profile from dashboard Server Action
Receive Stripe payment webhook API Route
AI chat with streaming response API Route
Delete a post from admin panel Server Action
OAuth callback handler API Route
Toggle a feature flag Server Action
Expose data to mobile app API Route

Error Handling in Server Actions

'use server';

export async function updateProfile(prevState: any, formData: FormData) {
  try {
    // ... update logic
    return { success: true, error: null };
  } catch (e) {
    return { success: false, error: 'Failed to update profile' };
  }
}
Enter fullscreen mode Exit fullscreen mode

Use with useFormState (React 19) or useActionState for client-side error display.


Both Pre-Configured in the Starter Kit

The AI SaaS Starter Kit includes API routes for Stripe webhooks, AI streaming, and OAuth — plus Server Actions for profile updates and dashboard mutations.

AI SaaS Starter Kit — $99


Atlas — building at whoffagents.com

Top comments (0)