This content originally appeared on DEV Community and was authored by Tianya School
Next.js API Routes enable the creation of standalone server-side functionality within a Next.js application, capable of handling HTTP requests and returning JSON data or other responses. API routes reside in the pages/api
directory, with each file mapping to a specific API endpoint.
Basic Example
pages/api/users.js
import type { NextApiRequest, NextApiResponse } from 'next';
// Get user list
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === 'GET') {
const users = [
{ id: 1, name: 'User 1' },
{ id: 2, name: 'User 2' },
{ id: 3, name: 'User 3' },
];
res.status(200).json(users);
} else if (req.method === 'POST') {
const user = req.body;
// Simulate database connection
// await addUserToDatabase(user);
res.status(201).json({ message: 'User added successfully.' });
} else {
res.setHeader('Allow', ['GET', 'POST']);
res.status(405).end(`Method ${req.method} Not Allowed`);
}
}
- The
pages/api/users.js
file defines an API route accessible at/api/users
. - The
handler
function accepts two parameters:req
(aNextApiRequest
object representing the HTTP request) andres
(aNextApiResponse
object for the HTTP response). - For GET requests, it returns a user list (hardcoded here, but typically queried from a database in practice).
- For POST requests, it accepts user data from the request body, simulates adding it to a database, and returns a success message.
- For unsupported methods, it returns a 405 Method Not Allowed error with allowed methods specified.
Next.js API Routes handle JSON responses by default, but you can return other content types as needed. For example, use
res.send
to return HTML.
Middleware and Request Handling Chain
Next.js API Routes support a middleware pattern, allowing preprocessing of requests or post-processing of responses before reaching the final handler. This is useful for validating headers, authentication, logging, etc.
Middleware Example
To validate an API key for all API requests:
// pages/api/middleware/authenticate.ts
export function authenticate(req: NextApiRequest, res: NextApiResponse, next: () => void) {
const apiKey = req.headers['x-api-key'];
if (!apiKey || apiKey !== process.env.API_KEY) {
return res.status(401).json({ message: 'Unauthorized' });
}
next();
}
Apply the middleware in an API route:
// pages/api/users.js
import { authenticate } from './middleware/authenticate';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
authenticate(req, res, () => {
// Original logic
});
}
Error Handling
Robust error handling is critical for production-grade applications. Next.js API Routes allow custom error handling logic.
Error Handling Example
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
// Code that might throw an error
const result = await fetchDataFromDatabase();
res.status(200).json(result);
} catch (error) {
console.error('Error occurred:', error);
res.status(500).json({ error: 'An error occurred while processing your request.' });
}
}
Type Safety
Using TypeScript for type annotations enhances code robustness and maintainability.
Type Safety Example
// pages/api/users.ts
import type { NextApiRequest, NextApiResponse } from 'next';
type User = {
id: number;
name: string;
};
export default async function handler(req: NextApiRequest, res: NextApiResponse<User[] | { message: string }>) {
// ...
}
Interacting with External Services
Most API routes interact with external services like databases or third-party APIs. Here’s how to use axios
for HTTP requests.
Install axios
:
npm install axios
Use in an API route:
import axios from 'axios';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
const response = await axios.get('https://api.example.com/data');
res.status(200).json(response.data);
} catch (error) {
res.status(500).json({ error: 'Failed to fetch data from external service.' });
}
}
Custom and Dynamic Routes
Next.js API Routes support more than single paths, allowing complex routing structures, including dynamic routes.
Custom Routes
To organize related API endpoints, use subdirectories. For a blog API, you might structure it as:
pages/
api/
blog/
posts.ts # Handles /api/blog/posts requests
post/[id].ts # Dynamic route, handles /api/blog/post/:id requests
Dynamic Routes
Dynamic routes capture URL segments as parameters. In the above example, [id]
is a dynamic segment replaced by an actual ID. Access these parameters via req.query
.
Dynamic Route Example (pages/api/blog/post/[id].ts)
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { id } = req.query; // Get dynamic ID
if (!id) {
return res.status(400).json({ message: 'Missing post ID' });
}
try {
const post = await getPostById(id as string); // Assume this fetches a post from a database
if (!post) {
return res.status(404).json({ message: 'Post not found' });
}
return res.status(200).json(post);
} catch (error) {
console.error('Error fetching post:', error);
return res.status(500).json({ message: 'Internal server error' });
}
}
API Route Caching
To improve performance, you may want to cache API responses. Next.js doesn’t provide built-in API caching, but you can use client-side libraries like swr
or server-side caching with services like Redis.
Server-Side Caching Example (Using Redis)
Install redis
and ioredis
:
npm install redis ioredis
Use Redis to cache data in an API route:
import redis from 'ioredis';
const redisClient = new redis(process.env.REDIS_URL);
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { id } = req.query;
let post;
try {
// Try fetching from Redis cache
post = await redisClient.get(`post:${id}`);
if (post) {
post = JSON.parse(post);
return res.status(200).json(post);
}
} catch (err) {
console.error('Redis error:', err);
}
// Fetch from database if not cached
post = await getPostById(id as string);
if (post) {
// Store in Redis for future requests
redisClient.set(`post:${id}`, JSON.stringify(post));
res.status(200).json(post);
} else {
res.status(404).json({ message: 'Post not found' });
}
}
CORS Support
Cross-Origin Resource Sharing (CORS) is a key aspect of web security. Next.js API Routes support CORS by default, but you can further control CORS policies.
CORS Example
import Cors from 'cors'; // Install cors library
// Initialize CORS middleware
const cors = Cors({
methods: ['GET', 'HEAD'],
});
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
// Apply CORS middleware
await new Promise((resolve, reject) => {
cors(req, res, (result) => {
if (result instanceof Error) {
reject(result);
} else {
resolve(result);
}
});
});
// Subsequent handling logic
}
🎁 I have compiled a complete series of advanced programming collections on Patreon:
- Weekly updated technical tutorials and project practice
- High-quality programming course PDF downloads
- Front-end / Back-end / Full Stack / Architecture Learning Collection
- Subscriber Exclusive Communication Group
👉 Click to join and systematically improve development capabilities: Advanced Development Tutorial
This content originally appeared on DEV Community and was authored by Tianya School

Tianya School | Sciencx (2025-07-12T06:41:29+00:00) Next.js API Routes Building Server-Side Functionality. Retrieved from https://www.scien.cx/2025/07/12/next-js-api-routes-building-server-side-functionality/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.