How to use Next.js as a backend for your frontend
Learn how to use Next.js as a backend framework
Next.js supports the "Backend for Frontend" pattern. This lets you create public endpoints to handle HTTP requests and return any content type—not just HTML. You can also access data sources and perform side effects like updating remote data.
If you are starting a new project, using create-next-app
with the --api
flag automatically includes an example route.ts
in your new project’s app/
folder, demonstrating how to create an API endpoint.
Good to know: Next.js backend capabilities are not a full backend replacement. They serve as an API layer that:
- is publicly reachable
- handles any HTTP request
- can return any content type
To implement this pattern, use:
- Route Handlers
middleware
- In Pages Router, API Routes
Public Endpoints
Route Handlers are public HTTP endpoints. Any client can access them.
Create a Route Handler using the route.ts
or route.js
file convention:
This handles GET
requests sent to /api
.
Use try/catch
blocks for operations that may throw an exception:
Avoid exposing sensitive information in error messages sent to the client.
To restrict access, implement authentication and authorization. See Authentication.
Content types
Route Handlers let you serve non-UI responses, including JSON, XML, images, files, and plain text.
Next.js uses file conventions for common endpoints:
sitemap.xml
opengraph-image.jpg
,twitter-image
- favicon, app icon, and apple-icon
manifest.json
robots.txt
You can also define custom ones, such as:
llms.txt
rss.xml
.well-known
For example, app/rss.xml/route.ts
creates a Route Handler for rss.xml
.
Sanitize any input used to generate markup.
Consuming request payloads
Use Request instance methods like .json()
, .formData()
, or .text()
to access the request body.
GET
and HEAD
requests don’t carry a body.
Good to know: Validate data before passing it to other systems
You can only read the request body once. Clone the request if you need to read it again:
Manipulating data
Route Handlers can transform, filter, and aggregate data from one or more sources. This keeps logic out of the frontend and avoids exposing internal systems.
You can also offload heavy computations to the server and reduce client battery and data usage.
Good to know: This example uses POST
to avoid putting geo-location data in the URL. GET
requests may be cached or logged, which could expose sensitive info.
Proxying to a backend
You can use a Route Handler as a proxy to another backend. Add validation logic before forwarding the request.
Or use:
NextRequest and NextResponse
Next.js extends the Request
and Response
Web APIs with methods that simplify common operations. These extensions are available in both Route Handlers and Middleware.
Both provide methods for reading and manipulating cookies.
NextRequest
includes the nextUrl
property, which exposes parsed values from the incoming request, for example, it makes it easier to access request pathname and search params.
NextResponse
provides helpers like next()
, json()
, redirect()
, and rewrite()
.
You can pass NextRequest
to any function expecting Request
. Likewise, you can return NextResponse
where a Response
is expected.
Learn more about NextRequest
and NextResponse
.
Webhooks and callback URLs
Use Route Handlers to receive event notifications from third-party applications.
For example, revalidate a route when content changes in a CMS. Configure the CMS to call a specific endpoint on changes.
Callback URLs are another use case. When a user completes a third-party flow, the third party sends them to a callback URL. Use a Route Handler to verify the response and decide where to redirect the user.
Redirects
Learn more about redirects in redirect
and permanentRedirect
Middleware
Only one middleware file is allowed per project. Use config.matcher
to target specific paths. Learn more about middleware.
Use middleware
to generate a response before the request reaches a route path.
You can also proxy requests using middleware
:
Another type of response middleware
can produce are redirects:
Security
Rate limiting
You can implement rate limiting in your Next.js backend. In addition to code-based checks, enable any rate limiting features provided by your host.
Verify payloads
Never trust incoming request data. Validate content type and size, and sanitize against XSS before use.
Use timeouts to prevent abuse and protect server resources.
Store user-generated static assets in dedicated services. When possible, upload them from the browser and store the returned URI in your database to reduce request size.
Access to protected resources
Always verify credentials before granting access. Do not rely on middleware alone for authentication and authorization.
Remove sensitive or unnecessary data from responses and backend logs.
Rotate credentials and API keys regularly.
Preflight Requests
Preflight requests use the OPTIONS
method to ask the server if a request is allowed based on origin, method, and headers.
If OPTIONS
is not defined, Next.js adds it automatically and sets the Allow
header based on the other defined methods.
Library patterns
Community libraries often use the factory pattern for Route Handlers.
This creates a shared handler for GET
and POST
requests. The library customizes behavior based on the method
and pathname
in the request.
Libraries can also provide a middleware
factory.
More examples
See more examples on using Router Handlers and the middleware
API references.
These examples include, working with Cookies, Headers, Streaming, Middleware negative matching, and other useful code snippets.
Caveats
Server Components
Fetch data in Server Components directly from its source, not via Route Handlers.
For Server Components pre-rendered at build time, using Route Handlers will fail the build step. This is because, while building there is no server listening for these requests.
For Server Components rendered on demand, fetching from Route Handlers is slower due to the extra HTTP round trip between the handler and the render process.
A server side fetch
request uses absolute URLs. This implies an HTTP round trip, to an external server. During development, your own development server acts as the external server. At build time there is no server, and at runtime, the server is available through your public facing domain.
Server Components cover most data-fetching needs. However, fetching data client side might be necessary for:
- Data that depends on client-only Web APIs:
- Geo-location API
- Storage API
- Audio API
- File API
- Frequently polled data
For these, use community libraries like swr
or react-query
.
Server Actions
Server Actions let you run server-side code from the client. Their primary purpose is to mutate data from your frontend client.
Server Actions are queued. Using them for data fetching introduces sequential execution.
export
mode
export
mode outputs a static site without a runtime server. Features that require the Next.js runtime are not supported, because this mode produces a static site, and no runtime server.
In export mode
, only GET
Route Handlers are supported, in combination with the dynamic
route segment config, set to 'force-static'
.
This can be used to generate static HTML, JSON, TXT, or other files.
Deployment environment
Some hosts deploy Route Handlers as lambda functions. This means:
- Route Handlers cannot share data between requests.
- The environment may not support writing to File System.
- Long-running handlers may be terminated due to timeouts.
- WebSockets won’t work because the connection closes on timeout, or after the response is generated.