惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Spread Privacy
Spread Privacy
Engineering at Meta
Engineering at Meta
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
D
DataBreaches.Net
N
Netflix TechBlog - Medium
T
The Blog of Author Tim Ferriss
L
LangChain Blog
Jina AI
Jina AI
MongoDB | Blog
MongoDB | Blog
B
Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
月光博客
月光博客
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
T
Tailwind CSS Blog
Google DeepMind News
Google DeepMind News
WordPress大学
WordPress大学
T
Threatpost
V
V2EX
Security Archives - TechRepublic
Security Archives - TechRepublic
GbyAI
GbyAI
Scott Helme
Scott Helme
Cyberwarzone
Cyberwarzone
H
Help Net Security
大猫的无限游戏
大猫的无限游戏
Security Latest
Security Latest
T
The Exploit Database - CXSecurity.com
T
Tenable Blog
S
Schneier on Security
博客园 - 叶小钗
Apple Machine Learning Research
Apple Machine Learning Research
F
Full Disclosure
腾讯CDC
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
S
Security @ Cisco Blogs
A
Arctic Wolf
S
Securelist
Recent Commits to openclaw:main
Recent Commits to openclaw:main
T
Tor Project blog
The Register - Security
The Register - Security
L
LINUX DO - 最新话题
Blog — PlanetScale
Blog — PlanetScale
U
Unit 42
V
Vulnerabilities – Threatpost
Google Online Security Blog
Google Online Security Blog
L
LINUX DO - 热门话题
TaoSecurity Blog
TaoSecurity Blog
Y
Y Combinator Blog
博客园 - 三生石上(FineUI控件)
C
CERT Recently Published Vulnerability Notes

Clerk Blog

Going to production with Clerk Deploy Clerk Init: The fastest way to start a new project Introducing Clerk CLI Middleware-based route protection bypass Postmortem: Clerk System Outage (March 10, 2026) Clerk for the AI era Add API Key support to your SaaS in minutes Postmortem: Clerk System Outage (February 19, 2026) Using Clerk in a React Native app Postmortem: DNS Provider Outage (February 10, 2026) How do I implement passkeys in Next.js? Clerk ranked #4 fastest-growing software vendor on Ramp’s December 2025 list How do I handle JWT verification in Next.js? Committing to Agent Identity: Clerk raises $50m Series C from Menlo and Anthropic’s Anthology Fund What is the best way to handle authentication in Next.js App Router? Postmortem: Database Incident (September 14–18, 2025) How do I add authentication to a Next.js app? Introducing Free Trials in Clerk Billing Postmortem: August 28, 2025 - elevated API latency and errors Introducing Mosaic: Bring Your Brand to Every Authentication Flow Multi-tenant authentication: What you need to know (and how Clerk helps) What are the risks and challenges of multi-tenancy? Resilience in Practice: Regional Failover at Clerk Build a Cross-Platform B2B App with Clerk, Expo, and Supabase Highlights from the MiduDev/Clerk Hackathon Add multi-tenancy to an app built with Clerk, Lovable, and Supabase How to build an AI coding rules app with Clerk, Lovable, and Supabase How to Build Multi-Tenant Authentication with Clerk Choosing the right SaaS architecture: Multi-Tenant vs. Single-Tenant Postmortem: June 26, 2025 service outage How to Design a Multi-Tenant SaaS Architecture What is multi-tenancy and why it matters for B2B SaaS How OAuth Works Synchronize user data from Clerk to Supabase Add subscriptions to your SaaS with Clerk Billing Getting started with Clerk Billing Multi-tenant analytics with Tinybird and Clerk How Huntr Migrated 250K Users to Clerk: A Scalable Auth Solution for Startups How to take Clerk to Production How to take your Clerk application to production A practical guide to testing Clerk Next.js applications Implementing multi-tenancy into a Supabase app with Clerk How Clerk integrates with a Next.js application using Supabase How Clerk integrates with Supabase Build a blog with tRPC, Prisma, Next.js and Clerk How to enrich PostHog events with Clerk user data How to build a secure project management platform with Next.js, Clerk, and Neon Validate your SaaS idea while building an audience Postmortem: February 6, 2025 service outage Implement Role-Based Access Control in Next.js 15 Build a Next.js sign-up form with React Hook Form Build a Next.js login page template How to implement Google authentication in Next.js 15 What is middleware in Next.js? How to customize Next.js metadata How to set environment variables in Node.js Building a React Login Page Template How to implement per-user OAuth scopes with Clerk Using Clerk SSO to access Google Calendar and other service data Streamline enterprise customer onboarding with SAML and Clerk Clerk launches EASIE SSO and eliminates SSO fees How to secure Liveblocks Rooms with Clerk in Next.js Securing Node.js Express APIs with Clerk and React Combining the benefits of session tokens and JWTs Build a task manager with Next.js, Supabase, and Clerk Comparing Clerk Webhooks vs Backend API Automate Neon schema changes with Drizzle and GitHub Actions A guide to reading authenticated user data from Clerk Role based access control with Clerk Organizations Mitigating OAuth’s recently discovered Open Response Type vulnerability Per-user B2B monetization with Stripe and Clerk Organizations Build a team-based task manager with Next.js, Neon, and Clerk Building a Hybrid Sign-Up/Subscribe Form with Stripe Elements Welcoming Colin from Zod as our inaugural Open Source Fellow Build a modern authenticated chat application with Next.js, Ably, and Clerk Build a waitlist with Clerk user metadata How to use Clerk with PostHog Identify in Next.js How to secure API Gateway using JWT and Lambda Authorizers with Clerk What are passkeys and how do they work? Comparing Authentication in React.js vs. Next.js How to Add an Onboarding Flow for your Application with Clerk Create Your Own Custom User Menu with Radix - Part 2 Introducing Webhook Workflows with Inngest & Svix Clerk raises $30M Series B from CRV and Stripe Clerk in 2023: A Year in Review Build a Movie Emoji Quiz App with Remix, Fauna, and Clerk Ultimate Guide to Magic Link Authentication Create Your Own Custom User Menu with Radix Introducing has(), protect(), and <Protect> Updated Pricing: 10,000 MAUs Free, and a new “Pro Plan” Next.js Authentication with Clerk: Streamlined SSR Handling Clerk Webhooks: Data Sync with Convex Exploring Clerk Metadata with Stripe Webhooks The Ultimate Guide to Next.js Authentication Empower Your Support Team With User Impersonation Clerk Webhooks: Getting Started A Complete Guide to Session Management in Next.js The Advanced Guide to Passwordless Authentication in Next.js How We Roll – Chapter 10: Roundup How We Roll – Chapter 9: Infrastructure
Next.js 13 Routes Part 1: Getting Started with Next.js API Routes
Aniket Bhattacharyea · 2023-01-26 · via Clerk Blog

An API route creates a server-side bundle separate from the client-side bundle. As is usual for Next.js pages, file-based routing is used to create API routes, where files inside pages/api are mapped to /api/* routes.

Apart from building the backend logic, you can use API routes to run logic that depends on a secret you don't want to expose to the client—for example, connecting to a database through a database URL string. Since API routes are server-side only, you don't have to worry about exposing the database credentials to the client.

You can also use API routes to mask external service URLs. For example, if you call https://some-service/foo, you can route it through an API route such as /api/foo to hide the actual URL used.

In this article, you'll get hands-on experience in building API routes while learning about different types of API routes in Next.js.

Implementing API Routes in Next.js

To follow this tutorial, make sure you have Node.js 14.6.0 or newer. This article uses Yarn as the package manager, but you can also use npm. If you'd like to see the code of the finished application, you can find it in this GitHub repo.

First, create a Next.js app:

Once you're prompted, choose a name for your app—for example, api-routes-demo. Select No when asked if you want to use TypeScript. You can keep the default answers to all the other questions. After the app is created, move into the app directory. You can delete the pages/api/hello.js file that was created by default.

To work with the app, you'll need some sample data. To keep things simple, you'll use a static data set, but in a real-world app, you'll likely use a database.

Create the file data.js in the project root:

Basics of API Routes

The heart of the API routes is the pages/api directory. Any file in this directory is mapped to a route of the form /api/*. So, the file pages/api/foo.js will get mapped to /api/foo. To make the API route work, you'll need to export a default function from the file, as shown below:

The function receives two arguments:

Before proceeding, keep these two things in mind:

  1. Next.js 13 introduced a new app directory that offers an improved routing system over the traditional pages directory. However, API routes should still be defined in the pages/api directory. As this article is being written, the Next.js team hasn't decided yet how API routes will look like in the app directory. So this article will use the usual pages/api directory structure, but keep in mind it may change in the future.
  2. Next.js offers a beta version of Edge API routes, which use the Edge Runtime. These API routes are often faster than their Node.js runtime counterparts but come with limitations such as not having access to native Node.js APIs. This article will not discuss Edge API routes and will only deal with standard API routes.

Static Routes

A static route is a fixed, predefined route that matches a single path verbatim. Next.js offers two equivalent ways of creating static routes. If you want a static route /api/foo, you can do one of the following:

  1. Create the file foo.js in pages/api, or
  2. Create the file index.js in a directory named foo in pages/api

Even though both approaches are equivalent, the second approach is much easier to work with if you have nested or dynamic routes under that particular route, as you'll see later.

Let's create two static routes—/api/users and /api/posts—and see both approaches in action. First, create a users directory in pages/api and create an index.js file in this directory with the following code:

As you can see, the handler function returns the list of users with a 200 status. You can test this route by sending a GET request to localhost:3000/api/users:

You'll take the second approach for the /api/posts route. Create the file posts.js in pages/api:

Similar to the previous route, this one returns the list of all posts. A similar GET request can be used to test this route:

It's possible to pass query parameters to routes such as /api/foo?bar=baz. These query parameters can be accessed in the handler function through the req.query object. Let's see this by passing a limit query parameter to the /api/posts route. Modify posts.js with the following code:

Now you can pass the limit parameter to limit the number of results:

Dynamic Routes

Fixed static routes may not be always enough for complex routing needs. For example, if you have multiple users, it's not convenient to set up individual static routes for each user, such as /api/users/1, /api/users/2, and so on. To solve this, you need to use dynamic routes, where one or more segments work as parameters that the user can pass.

For example, a route like /api/users/[id] can match /api/users/xxx, where xxx can be any valid URL component. The actual parameter passed through the URL can be accessed by the name assigned in the route (id in this example), and the appropriate record can be fetched from the database.

To create a dynamic segment, you need to add square brackets ([ ]) around the name of the file. For example, pages/api/users/[id].js will be mapped to the route /api/users/[id]. Just like in the case of static routes, you can also create a directory named [id] and create index.js inside it. Both approaches are precisely equivalent. The parameter id can be accessed in the handler function through the req.query object:

It's possible to have multiple dynamic segments by using a nested directory structure. For example, pages/api/users/[id]/[postId].js will be mapped to /api/users/[id]/[postId], and both id and postId can be accessed via req.query:

Remember that a route parameter will override a query parameter with the same name. So in the route /api/users/1?id=foo, req.query.id will be 1 and not foo.

Create a directory [id] in pages/api/users and create index.js inside it, which will map to the /api/users/[id] route. Write the following code in index.js:

This function finds the appropriate user from the array and returns it. If no user with the specified ID is found, a "Not found" error is returned instead. Test the route with the following request:

Nested Routes

It's possible to create nested routes in Next.js by simply nesting directories. A directory structure like pages/api/foo/bar.js or pages/api/foo/bar/index.js will be mapped to /api/foo/bar. Let's create a posts route under /api/users/[id], which will return all posts by the specified user.

Create the file posts.js in pages/api/users/[id] with the following code:

This function first finds the appropriate user and then filters the posts array to find posts with the particular userId. Test that it works correctly:

Catch-All Routes

Catch-all routes are similar to dynamic routes, but whereas in a dynamic route, the dynamic segment matches only that particular part of the route, in a catch-all route, it matches all paths under that route. This can be created by adding three dots (...) inside the square brackets. So, a route like /api/foo/[...bar] will match /api/foo/a, /api/foo/a/b, /api/foo/a/b/c, and so on. However, it won't match /api/foo—i. e. , the path parameter cannot be omitted.

If you'd like the path parameter to be optional, you can convert it to an optional catch-all route by using two square brackets ([[ ]]). So, /api/foo/[[...bar]] matches /api/foo/a, /api/foo/a/b, /api/foo/a/b/c, and so on, as well as /api/foo. The path parameters can be accessed through req.query as before, but in this case, it will be an array of one or more elements if parameters are passed or an empty object if the parameter is omitted.

Let's create an optional catch-all route /api/comments/[[...ids]], which will do the following:

  • Return all comments if no parameter is passed
  • Return all comments under post xx for a route like /api/comments/xx
  • Return all comments by user yy under post xx for a route like /api/comments/xx/yy

Create the directory comments in pages/api and create the file [[...ids]].js inside:

You can test this route with zero or more parameters:

Adding JWT Authentication

If you're working on a project where your API routes should be kept private, you'll need to protect them from unauthorized access. JWT authentication is one of the most commonly used authentication mechanisms for securing APIs. You'll now add JWT authentication to the /api/users route so that the users need to log in before accessing that route.

First, stop the server if it's running. Install the required dependencies with yarn add bcryptjs jsonwebtoken. The bcrypt library is used to hash and compare the passwords, and the jsonwebtoken library is used to create and verify the JWT. Create an ENV file with the following content:

This key will be used to sign the JWT, so in an actual application, this should be a random string and kept secret.

Next, open data.js and add a password key to all the users. For simplicity, add the same password to all the users:

The value in quotes is the hashed version of the string "password".

Next, create auth.js inside pages/api. This file will log the user in and generate the token. Start with the necessary imports:

Ensure that only the POST method is allowed:

The next step is to extract the username and password from the body and ensure that a user with the username exists:

Then, use bcrypt to compare the password in the request with the actual password:

If the passwords are a match, sign and send the JWT:

The entire file should look like this:

Let's test this route. Start the server with yarn dev and send a request to localhost:3000/api/auth:

Note that you'll likely get a different token.

You can now use this token to check the authenticity of the user. Let's protect the /api/users route with JWT. Replace the content in pages/api/users/index.js with the following:

The above code checks the Authorization header for the JWT. If a token is passed, the jwt.verify function is invoked to check the token's authenticity. Once authenticated, the data is returned (with the password field stripped from the users—you wouldn't want to expose the passwords, would you?).

Test this route by passing the Authorization header to the request:

An invalid token will raise the following error:

As you can see, adding JWT authentication to API routes is an involved process that can be complicated. Using something like Clerk’s Next.js authentication solution makes the process much easier since it does the heavy lifting of authentication, taking the task off your plate.

With Clerk, authentication is as simple as importing the getAuth function:

Calling it inside the handler function is also easy, which will automatically authenticate the user and return the user ID:

You'll learn more about authentication with Clerk in part two of this series.

Conclusion

Next.js API routes offer extreme flexibility in keeping your server-side logic close to the frontend and creating an API application. With the many different types of API routes available, it's critical to implement proper authentication to protect the routes from bad actors. However, adding authentication can be a complex and daunting task. This is why solutions like Clerk exist to make it as easy and seamless as possible.