Skip to main content

Command Palette

Search for a command to run...

API Routes

Updated
7 min read
API Routes
  1. Introduction | What Are API Routes? Why Use Them?

Next.js provides “API Routes” as a mechanism that allows you to implement backend-like processing beyond the scope of the frontend. Simply put, this is a feature that lets you define server-side processing (API endpoints) within Next.js.

For example, it is used in the following scenarios:

・Querying a database to retrieve and return data

・Receiving form submissions and sending emails or saving the data

・Acting as a server-side intermediary for communication with external APIs

・Processing and validating authentication tokens and cookies on the server

This is particularly beneficial for developers who:

・Are working as individuals or in small teams and prioritize speed

・Want to work efficiently without separating UI development from API implementation

・Want to handle the minimum implementation themselves, even with limited backend experience

Additionally, within the Next.js App Router configuration, you can define API routes in the same way by using the app/api/ directory

That said, many of you may have questions like the following:

・Is it safe to use API Routes in production?

・What types of tasks are they best suited for?

・How do they differ from fetch and axios?

What’s the difference between the Pages Router and the App Router?

In this article, we’ll address these questions while introducing common patterns and best practices used in real-world scenarios.

2. Basic Syntax and Directory Structure of API Routes

Next.js API Routes provide a mechanism for defining server-side logic using simple syntax. They support both App Router and Pages Router configurations, and the syntax and placement differ slightly between the two.

✅Basic Syntax for Pages Router Configuration

In Pages Router, files placed under the pages/api/ folder are automatically recognized as endpoints.

// pages/api/hello.ts
import type { NextApiRequest, NextApiResponse } from 'next';

export default function handler(req: NextApiRequest, res: NextApiResponse) {
  res.status(200).json({ message: 'Hello API!' });
}

In this case, accessing /api/hello will return { message: “Hello API!” }.

You can use req.method to handle POST, GET, PUT, and other requests.

You can also handle database connections and session management within this code.

✅Basic Syntax for App Router Configuration (Next.js 13 and later)

In App Router, you must create files within the app/api/ directory and export HTTP method functions (such as GET and POST) on a per-file basis.

// app/api/hello/route.ts
import { NextResponse } from 'next/server';

export async function GET() {
  return NextResponse.json({ message: 'Hello from App Router!'         });
}

In the App Router configuration, the key point is that the file name is route.ts. This allows Next.js to recognize this file as an API endpoint.

The supported methods are as follows:

GET()

POST(req: Request)

PUT()

DELETE()

PATCH()

If necessary, use the Request object to retrieve the request body as follows:

export async function POST(req: Request) {
  const body = await req.json();
  return NextResponse.json({ received: body });
}

📁 Example of folder structure (App Router)

app/
  api/
    hello/
      route.ts         ← /api/hello
    contact/
      route.ts         ← /api/contact

🧩 Using with Middleware

API Routes can be combined with Next.js middleware (middleware.ts) and functions like headers() to enable advanced control features such as token authentication and redirect management.

① Form Submission Processing (e.g., Contact Form)

For example, when creating a “contact form,” the basic process involves sending and processing the information entered by the user via an API route.

✅ Benefits

Validation and submission processing can be separated from the front end

Flexible implementation of anti-spam measures and authentication logic

🔒 ② Secure authentication and authorization (JWT and session management)

For authentication, we may integrate with external services such as Firebase Authentication or Auth0, while performing token verification and user data protection within the API routes.

// app/api/user/route.ts
import { verifyToken } from '@/lib/auth';

export async function GET(req: Request) {
  const token = req.headers.get('Authorization')?.replace('Bearer ', '');
  const user = await verifyToken(token);
  if (!user) return new Response('Unauthorized', { status: 401 });
  return new Response(JSON.stringify({ user }), { status: 200 });
}

📂 ③ Integration with external APIs (indirect proxy)

API Routes are often used as a proxy to integrate with external APIs (such as OpenAI, Stripe, and Google APIs).

// app/api/openai/route.ts
export async function POST(req: Request) {
  const { prompt } = await req.json();
  const response = await fetch('https://api.openai.com/v1/chat/completions', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({ model: 'gpt-4', messages: [{ role: 'user', content: prompt }] }),
  });

  const data = await response.json();
  return new Response(JSON.stringify({ result: data }), { status: 200 });
}

✅ Benefits

You can safely call the API without exposing the API key to the front end

Front-end code becomes simpler

💾 ④ Integration with Databases (Prisma / Supabase / Firestore)

It is common to perform database operations within Next.js API routes using ORMs (e.g., Prisma) or client SDKs (e.g., Supabase, Firebase).

// app/api/todos/route.ts
import { prisma } from '@/lib/prisma';

export async function GET() {
  const todos = await prisma.todo.findMany();
  return Response.json(todos);
}

✅ Benefits

Optimizes data retrieval processes in an SSR environment

Eliminates the need for client-side database knowledge

4. Precautions and Best Practices for Using API Routes

While API Routes are convenient and flexible, improper design or operation can lead to spaghetti code and create security risks. In this chapter, we will introduce key points to keep in mind and best practices for using API Routes in real-world scenarios.

🧱 Improve Readability with a Thoughtful Directory Structure

As the number of API routes increases, your files can become cluttered. By creating a subdirectory for each endpoint, you can achieve a scalable structure.

/app
 └── api
     ├── contact
     │    └── route.ts
     ├── auth
     │    └── login/route.ts
     │    └── logout/route.ts
     └── todos
          ├── route.ts
          └── [id]/route.ts

✅ Key point: Grouping by functional units or resources helps minimize confusion even in team-based development

🔐 Standardize authentication and authorization mechanisms as much as possible

If many API routes require user authentication, it’s helpful to centralize authorization checks in middleware.ts or handle them in lib/auth.ts.

// lib/auth.ts
export async function getUserFromRequest(req: Request) {
  const token = extractToken(req);
  return await verifyToken(token);
}

✅ Key point: Hard-coding authentication logic for each API can easily lead to bugs.

🚧 Handle errors carefully

To ensure that the client displays the correct information when an API call fails, proper error handling and clear HTTP status codes are essential.

try {
  const data = await fetchSomething();
  return Response.json(data);
} catch (error) {
  console.error(error);
  return new Response('Internal Server Error', { status: 500 });
}

✅ Key point: Receiving a specific error message rather than a “500 error” on the client side improves the user experience

🚨 Division of Responsibilities with Client Components

Using fetch(‘/api/~’) directly in a Client Component tends to complicate state management and error handling.

Retrieve lightweight data using useSWR or React Query

Separate responsibilities for heavy processing into Server Components or API Routes

✅ Key Point: Clearly define where data is stored and where it is processed

📉 Don’t forget security measures like rate limiting and CSRF protection

The following measures are especially important for publicly exposed APIs (e.g., forms):

Rate Limit: Protection against bots and DDoS attacks

CSRF Token: Prevention of unintended requests

CORS Control: Allow requests only from authorized domains

✅ Key Point: Since Next.js alone cannot fully secure all areas, consider implementing a WAF or Cloudflare

✅ Conclusion | The key to API Routes is “simple design” Next.js API Routes are a very powerful feature for developing small to medium-sized applications. They are particularly well-suited for Server Components in App Router configurations and are ideal when you just need a “quick API.”

However, as the scale expands, considerations such as separation of concerns, security measures, and performance optimization become necessary.

In your own development, make sure to understand the “appropriate use cases” and “precautions” so you can use API Routes effectively.