How do I correctly submit a form using Next.js Server Actions — without API routes, client fetch, or weird hydration errors?
If you’re moving from pages router or React SPA, you might be used to:
-
Writing an API route
-
Calling it with fetch
-
Updating state manually
With Server Actions, you don’t need that anymore.
You can post directly to the server function — securely — without exposing secrets to the browser.
Let’s build it cleanly.
🏗 Step 1 — Create a Simple Form
Example in /app/page.tsx:
Looks normal right?
Now here’s the magic 👇
🔐 Step 2 — Add the Server Action
Above the component:
Yes — that’s the whole backend.
No API route.
No client fetch.
No useEffect.
No JSON parsing.
Just a function that runs securely on the server only.
🧪 Try It
When you submit the form:
✔ page does NOT refresh fully
✔ server logs the email
✔ function runs on backend
✔ values are type-safe
Feels like magic — but predictable.
⚠️ Common Error #1 — “Server Actions only work in Server Components”
If you see this:
That means you added:
Server Actions only run in Server Components.
If you need both:
👉 move UI logic to a client component
👉 keep action in the parent server component
👉 pass the action as a prop
Example:
Client component:
❌ Common Error #2 — “Actions must be async functions”
Always write:
Even if you don’t await anything yet.
🛡 Adding Validation (Real-World Style)
Errors will surface in dev mode — which is great.
💾 Saving to a Database (Example With Prisma)
Note:
Your DB credentials never touch the browser — because this function runs server-side only.
🔁 Redirect After Submit
🧠 Progressive Enhancement (The Hidden Superpower)
Even if JavaScript is disabled, the form still works — because submission falls back to plain HTML POST.
This is what old frameworks got right — and we’re finally back there 😊
🎯 When Should You Use Server Actions?
Use them for:
✔ Form submissions
✔ Data mutations
✔ Secure logic
✔ Auth handling
✔ DB writes
Avoid them for:
✖ Streaming UI state
✖ High-frequency realtime events
✖ Store-like client values
🔥 Bonus — Show Success/Errors in UI (Without Client State)
No Redux.
No useState.
No API routes.
Still fully interactive.
🏁 Final Thoughts
Server Actions quietly fix a decade of frontend complexity.
Once you understand the flow:
👉 form → server function → DB → UI feedback
…your codebase becomes smaller, safer, and easier to reason about.