DEV Community

Adam Pitera
Adam Pitera

Posted on • Edited on

Why I Ditched API Routes for Server Actions in Next.js

I just deleted 128 lines of code and my app works better. Here's how Server Actions transformed my secure form handling in Next.js.
My first attempt used a traditional API route with 173 lines of HTTP boilerplate. Server Actions promised to handle the HTTP layer automatically - and they delivered, eliminating 128 lines while keeping the same security features.

The Problem: So Much Boilerplate

My form needed CSRF protection, rate limiting, and complex validation. The traditional API route approach worked, but required extensive manual HTTP handling:

// app/api/submit-form/route.ts - 173 lines
export async function POST(request: NextRequest) {
  // Before: So much manual work!
  const formData = await request.formData();  // Manual parsing

  // Manual extraction
  const token = request.cookies.get("csrf_token")?.value; 

  if (!token) {
    return NextResponse.json(
      { error: "Missing token" }, 
      { status: 403 }
    ); // Manual responses
  }

  // ... 165 more lines of HTTP plumbing
}
Enter fullscreen mode Exit fullscreen mode

The Solution: Server Actions

Server Actions let me call server functions directly from React components:

// app/actions.ts - 45 lines
"use server";

export async function submitForm(formData: FormData) {   
  const store = await cookies();
  const token = store.get("csrf_token")?.value;

  if (!token) 
    return { error: "Missing token", success: false };

  const result = await database.insert(data);
  return { success: true };
}
Enter fullscreen mode Exit fullscreen mode

What I Eliminated

  • 128 lines of code (73% reduction!)
  • HTTP status code management
  • Manual request/response handling
  • Method checking (GET/POST/PUT/DELETE)
  • JSON parsing/serialisation

What Stayed the Same

  • Security (CSRF, rate limiting, validation)
  • Database operations
  • Anonymous data handling

My code now has the same security with less complexity.

The Result

The real win? Everything is just JavaScript now. No context switching between "client thinking" and "API thinking". My validation schema lives in one place and works on both client and server. When debugging, the error is right there in my component instead of buried in server logs.

Key Takeaways

  • Server Actions handle HTTP automatically
  • Security logic stays server-side
  • Less code complexity

When NOT to Use Server Actions

While Server Actions simplified my use case, they're not always the right choice:

  • Building a public API
  • Need custom HTTP headers or status codes
  • Most webhook endpoints
  • Response streaming

If you're building an API for mobile apps or need fine-grained HTTP control, stick with traditional API routes.

Conclusion

Server Actions excel at form handling - especially when security matters. All validation logic stays server-side, hidden from prying eyes. Your implementation details will vary, but the core benefit remains: less boilerplate, same security.

Have you migrated to Server Actions? What was your experience? Drop a comment below!

Top comments (0)