Next.js Connect Router
next-connect is a promise-based routing and middleware layer designed specifically for Next.js applications, supporting various environments including API Routes, Edge API Routes, Middleware, App Router Route Handlers, and `getServerSideProps`. Currently at stable version 1.0.0, the library has historically followed an active release cadence, with pre-releases leading up to major versions. Its key differentiators include asynchronous middleware support, a lightweight footprint suitable for serverless environments, and significantly faster performance compared to traditional Express.js setups. It also offers robust TypeScript support and handles asynchronous handlers with integrated error catching, providing a flexible and efficient alternative for managing server-side logic in Next.js projects.
Common errors
-
TypeError: (0 , next_connect__WEBPACK_IMPORTED_MODULE_0__.default) is not a function
cause Attempting to use `next-connect` with a default import (`import nextConnect from 'next-connect';`) after upgrading to v1, which switched to named exports.fixUpdate your import statements to use named exports: `import { createRouter } from 'next-connect';` or `import { createEdgeRouter } from 'next-connect';` -
Error: You can't use next(err) here. Please throw an error instead.
cause Calling `next(err)` in middleware after upgrading to `next-connect` v1.0.0, which removed this pattern.fixReplace calls to `next(err)` with `throw err;` or `throw new Error('...')`. Errors will be caught by the `onError` handler configured in `.handler()`. -
TypeError: handlers[(i++)] is not a function
cause This error can occur if a middleware function is not properly defined or if an `async` middleware does not correctly call `await next()`, leading to issues in the promise chain resolution.fixEnsure all middleware functions are correctly structured `(req, res, next) => { ... }` and that `async` middleware explicitly `await next();`. Double-check any `expressWrapper` usage for correct integration. -
TypeError: Cannot read properties of undefined (reading 'end') at nextConnect/lib/index.js
cause This error often indicates issues with the `res` object not being properly handled or passed through the middleware chain, or an unhandled promise rejection in an async handler where `res` might become undefined.fixEnsure that `res` is always available and that all asynchronous operations either return a value or explicitly call `next()` or `res.end()`/`res.json()`. Await all `next()` calls in async middleware. Implement a robust `onError` handler in `router.handler()` to catch and gracefully respond to errors.
Warnings
- breaking Version 1.0.0-next.0 (and thus v1.0.0 stable) introduced significant breaking changes. Built-in support for Express.js middleware was removed, requiring the use of `expressWrapper` for compatibility. Additionally, the `next(err)` pattern for error propagation within middleware chains was deprecated in favor of throwing errors directly.
- breaking In version 0.12.1, the `handle()` method (now `.handler()` in v1) no longer directly used the `onError` option. This change affected how error handling was configured for those upgrading from older `v0` versions.
- gotcha When using `next-connect` with async middleware or handlers, it is crucial to `await next()` to ensure that errors thrown later in the chain are properly caught by the `onError` handler and to allow for proper control flow. Failing to await `next()` can lead to `UnhandledPromiseRejection` errors.
- gotcha The library offers `createRouter` for standard Node.js-based Next.js API Routes (`pages/api`) and `createEdgeRouter` for Next.js Edge API Routes and App Router Route Handlers. Using the wrong router for the intended runtime can lead to type mismatches or runtime errors, as their request/response objects differ.
Install
-
npm install next-connect -
yarn add next-connect -
pnpm add next-connect
Imports
- createRouter
import nextConnect from 'next-connect'; const router = nextConnect();
import { createRouter } from 'next-connect'; - createEdgeRouter
import { createRouter } from 'next-connect'; // Incorrect for Edge Runtimeimport { createEdgeRouter } from 'next-connect'; - expressWrapper
import { expressWrapper } from 'next-connect'; - NextConnect
import type { NextConnect } from 'next-connect';
Quickstart
import type { NextApiRequest, NextApiResponse } from "next";
import { createRouter } from "next-connect";
// Mock dependencies for a runnable example
const getUser = (id: string) => ({ id, name: `User ${id}`, email: `${id}@example.com` });
const updateUser = async (data: any) => ({ ...data, updatedAt: new Date().toISOString() });
class ForbiddenError extends Error {
statusCode: number;
constructor(message: string) {
super(message);
this.name = 'ForbiddenError';
this.statusCode = 403;
}
}
const router = createRouter<NextApiRequest, NextApiResponse>();
router
.use(async (req, res, next) => {
const start = Date.now();
// Simulate authentication or logging
console.log(`Incoming request to ${req.url}`);
await next(); // call next in chain
const end = Date.now();
console.log(`Request to ${req.url} took ${end - start}ms`);
})
.get((req, res) => {
const { id } = req.query;
if (typeof id !== 'string') {
res.status(400).json({ message: 'Invalid user ID' });
return;
}
const user = getUser(id);
res.json({ user });
})
.put(async (req, res) => {
// Simulate user context (e.g., from session/token)
const currentUser = { id: 'currentUserId123' }; // Mock current user
const { id } = req.query;
if (typeof id !== 'string') {
throw new Error('Invalid user ID for update');
}
// Example authorization check
if (currentUser.id !== id) {
throw new ForbiddenError("You can't update other user's profile");
}
const updatedUser = await updateUser({ id, ...req.body });
res.json({ user: updatedUser });
});
export default router.handler({
onError: (err, req, res) => {
console.error(err.stack); // Log the error for debugging
const statusCode = (err as ForbiddenError).statusCode || 500;
res.status(statusCode).end(err.message || "Something broke!");
},
onNoMatch: (req, res) => {
res.status(404).end(`Route ${req.method} ${req.url} not found`);
},
});