Design Converter
Education
Last updated on Mar 26, 2025
•5 mins read
Last updated on Mar 26, 2025
•5 mins read
Next.js
isn't just for building powerful frontend apps—it’s also a full-stack framework. With its latest advancements like the App Router
and Route Handlers
, you can create backend APIs right within your Next.js app using web-standard Request
and Response
objects.
In this article, we explore how to build scalable, production-ready APIs using the modern Next.js
architecture. Whether you're serving web clients, mobile apps, or third-party services, you'll learn everything from dynamic routing to secure middleware patterns.
To create a new Next.js
app with API examples included:
1npx create-next-app@latest --api
This scaffolds a project using the App Router
with example route.ts
files under the app/api/
directory.
Use Next.js
for APIs when:
If you only need server-side data fetching for your frontend (without exposing endpoints), consider using Server Components.
In the App Router
, route handlers live inside the app/api/
directory.
Example folder structure:
1app/ 2└── api/ 3 └── users/ 4 └── route.ts
Basic API handler:
1export async function GET(request: Request) { 2 const users = [{ id: 1, name: 'Alice' }]; 3 return new Response(JSON.stringify(users), { 4 status: 200, 5 headers: { 'Content-Type': 'application/json' }, 6 }); 7}
You can export multiple methods (GET
, POST
, PUT
, etc.) in a single file.
1export async function POST(request: Request) { 2 const body = await request.json(); 3 const { name } = body; 4 5 const newUser = { id: Date.now(), name }; 6 return new Response(JSON.stringify(newUser), { 7 status: 201, 8 headers: { 'Content-Type': 'application/json' }, 9 }); 10}
This allows /api/users
to handle both read and write operations from the same file.
The App Router
uses Web Platform APIs. You receive Request
objects and return Response
objects.
1import { NextRequest } from 'next/server'; 2 3export function GET(request: NextRequest) { 4 const query = request.nextUrl.searchParams.get('q'); 5 return new Response(JSON.stringify({ query })); 6}
1import { cookies, headers } from 'next/headers'; 2 3export function GET() { 4 const token = cookies().get('token')?.value; 5 const referer = headers().get('referer'); 6 7 return new Response(JSON.stringify({ token, referer })); 8}
For routes like /api/users/123
:
1app/ 2└── api/ 3 └── users/ 4 └── [id]/ 5 └── route.ts
1export async function GET( 2 request: Request, 3 { params }: { params: { id: string } } 4) { 5 return new Response(JSON.stringify({ id: params.id })); 6}
1app/api/docs/[...slug]/route.ts
1export async function GET( 2 request: Request, 3 { params }: { params: { slug: string[] } } 4) { 5 return new Response(JSON.stringify({ slug: params.slug })); 6}
1export async function GET() { 2 const res = await fetch('https://api.example.com/data', { 3 headers: { Authorization: `Bearer ${process.env.API_KEY}` }, 4 }); 5 6 const data = await res.json(); 7 return new Response(JSON.stringify({ ...data, proxy: true })); 8}
Reusable auth wrapper:
1type Handler = (req: Request) => Promise<Response>; 2 3export function withAuth(handler: Handler): Handler { 4 return async (req) => { 5 const token = req.headers.get('authorization'); 6 if (!token || token !== 'Bearer valid-token') { 7 return new Response(JSON.stringify({ error: 'Unauthorized' }), { 8 status: 401, 9 }); 10 } 11 return handler(req); 12 }; 13}
Usage:
1import { withAuth } from '@/lib/with-auth'; 2 3async function secretHandler(request: Request) { 4 return new Response(JSON.stringify({ secret: '🍕' })); 5} 6 7export const GET = withAuth(secretHandler);
1import handler from '@/app/api/users/[id]/route'; 2 3test('GET user by ID', async () => { 4 const request = new Request('http://localhost/api/users/123', { 5 method: 'GET', 6 }); 7 const response = await handler(request, { params: { id: '123' } }); 8 const body = await response.json(); 9 10 expect(response.status).toBe(200); 11 expect(body).toEqual({ id: '123' }); 12});
Aspect | Recommendation |
---|---|
Platform | Use Vercel for full compatibility |
Secrets | Use .env or the Vercel dashboard |
Static Export | Avoid next export if using API routes |
CLI Deploy | vercel --prod for production deployments |
Rate Limiting | Use Vercel Firewall or edge middleware |
Use Server Components
for internal-only data fetching:
1// app/users/page.tsx 2export default async function UsersPage() { 3 const res = await fetch('https://api.example.com/users'); 4 const users = await res.json(); 5 6 return ( 7 <ul> 8 {users.map((u: any) => ( 9 <li key={u.id}>{u.name}</li> 10 ))} 11 </ul> 12 ); 13}
Building APIs with Next.js
using the App Router
and Route Handlers
provides a modern, scalable, and developer-friendly full-stack experience.
✅ Use web-standard Request
and Response
objects
✅ Handle multiple HTTP methods in a single file
✅ Create dynamic, nested, and catch-all routes
✅ Share middleware logic across endpoints
✅ Proxy other APIs or handle webhooks
✅ Test and deploy APIs with confidence
Embrace Next.js
not just as a frontend tool—but as your complete backend layer too.
Tired of manually designing screens, coding on weekends, and technical debt? Let DhiWise handle it for you!
You can build an e-commerce store, healthcare app, portfolio, blogging website, social media or admin panel right away. Use our library of 40+ pre-built free templates to create your first application using DhiWise.