Express, inside Next.js
Server actions serve your own forms. But sometimes you need a real HTTP endpoint: a mobile app hitting your backend, a webhook from Stripe (a URL another service calls to notify you when something happens, like a payment), a public JSON API. That is a route handler, the special file route.js:
// app/api/posts/route.js export async function GET() { const posts = await db.posts.all(); return Response.json(posts); } export async function POST(request) { const body = await request.json(); const post = await db.posts.insert(body); return Response.json(post, { status: 201 }); }
This is the Backend with Node.js course condensed: GET/POST exports instead of app.get/app.post, the web-standard Request and Response objects instead of Express's req/res, and file-based paths (app/api/posts/route.js → /api/posts) instead of route strings. Even the status codes you learned (201 Created) carry straight over.
Quiz
A folder cannot contain both page.js and route.js. Based on what each file does, why?
Server action or route handler?
| Situation | Reach for |
|---|---|
| Your own app's form submits data | Server action |
| A mobile app or another service needs JSON | Route handler |
| A third party POSTs webhooks to you | Route handler |
| A button in your UI mutates data | Server action |
Rule of thumb: actions are internal wiring, handlers are public doors. Actions keep the type-safe function-call feel inside your app. Handlers speak plain HTTP that anything on the internet can call, exactly like the Express APIs you built before.
Problem
Stripe needs a URL it can POST payment events to, reachable at /api/webhooks. Which special file do you create? (relative path from the project root)