Bird
Raised Fist0
NextJSframework~5 mins

Route handlers (route.ts) in NextJS

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Introduction

Route handlers let you create server-side code that responds to web requests in Next.js. They help you build APIs or handle form submissions easily.

You want to create an API endpoint to fetch or send data.
You need to handle form submissions on the server.
You want to respond differently to GET, POST, or other HTTP methods.
You want to keep server logic close to your Next.js app without a separate backend.
You want to build server-side logic that runs only when a specific URL is requested.
Syntax
NextJS
import { NextRequest, NextResponse } from 'next/server';

export async function GET(request: NextRequest) {
  // handle GET request
  return NextResponse.json({ message: 'Hello from GET' });
}

export async function POST(request: NextRequest) {
  // handle POST request
  const data = await request.json();
  return NextResponse.json({ received: data });
}

Each HTTP method (GET, POST, etc.) is a separate exported async function.

Use NextRequest to access request details and NextResponse to send responses.

Examples
Simple GET handler that returns a JSON message.
NextJS
import { NextRequest, NextResponse } from 'next/server';

export async function GET(request: NextRequest) {
  return NextResponse.json({ message: 'Hello GET' });
}
POST handler that reads JSON from the request and sends it back.
NextJS
import { NextRequest, NextResponse } from 'next/server';

export async function POST(request: NextRequest) {
  const data = await request.json();
  return NextResponse.json({ received: data });
}
DELETE handler example to respond to delete requests.
NextJS
import { NextRequest, NextResponse } from 'next/server';

export async function DELETE(request: NextRequest) {
  return NextResponse.json({ message: 'Deleted' });
}
Sample Program

This route handler file responds to GET requests with a greeting message. For POST requests, it reads JSON data sent by the client and returns it in the response.

NextJS
import { NextRequest, NextResponse } from 'next/server';

export async function GET(request: NextRequest) {
  return NextResponse.json({ greeting: 'Hello from GET route' });
}

export async function POST(request: NextRequest) {
  const data = await request.json();
  return NextResponse.json({ receivedData: data });
}
OutputSuccess
Important Notes

Route handler files must be named route.ts and placed inside the folder for the route.

Only export functions for HTTP methods you want to support.

Use await request.json() carefully; it only works if the request has JSON body.

Summary

Route handlers let you write server code for specific URLs in Next.js.

Each HTTP method is a separate exported async function.

Use NextRequest and NextResponse to work with requests and responses.

Practice

(1/5)
1. What is the main purpose of a route.ts file in Next.js?
easy
A. To configure database connections
B. To style components using CSS modules
C. To create client-side React components
D. To define server-side code that handles HTTP requests for a specific URL

Solution

  1. Step 1: Understand the role of route.ts

    The route.ts file is used in Next.js to write server-side code that responds to HTTP requests for a specific route.
  2. Step 2: Compare with other options

    Styling, client components, and database configs are handled elsewhere, not in route.ts.
  3. Final Answer:

    To define server-side code that handles HTTP requests for a specific URL -> Option D
  4. Quick Check:

    Route handlers = server code for URLs [OK]
Hint: Route handlers handle server requests per URL [OK]
Common Mistakes:
  • Confusing route.ts with client component files
  • Thinking route.ts is for styling
  • Assuming route.ts manages database directly
2. Which of the following is the correct way to export a GET handler in route.ts?
easy
A. export async function GET(request: NextRequest) { return NextResponse.json({ message: 'Hi' }) }
B. export function Get() { return 'Hello' }
C. export async function get() { return new Response('Hello') }
D. export async function fetch() { return 'Hello' }

Solution

  1. Step 1: Recall Next.js route handler syntax

    Next.js expects exported async functions named exactly by HTTP method in uppercase, e.g., GET, with NextRequest parameter and returning NextResponse.
  2. Step 2: Check each option

    export async function GET(request: NextRequest) { return NextResponse.json({ message: 'Hi' }) } matches correct syntax: async, uppercase GET, parameter, and returns NextResponse. Others have wrong function names, casing, or return types.
  3. Final Answer:

    export async function GET(request: NextRequest) { return NextResponse.json({ message: 'Hi' }) } -> Option A
  4. Quick Check:

    Uppercase method + NextRequest + NextResponse = correct [OK]
Hint: Use uppercase HTTP method and NextRequest param [OK]
Common Mistakes:
  • Using lowercase method names like get instead of GET
  • Missing NextRequest parameter
  • Returning plain string instead of NextResponse
3. Given this route.ts code, what will be the JSON response body when a GET request is made?
import { NextResponse } from 'next/server';

export async function GET() {
  return NextResponse.json({ success: true, data: [1, 2, 3] });
}
medium
A. undefined
B. {"success":true,"data":[1,2,3]}
C. {"error":"Method not allowed"}
D. [1, 2, 3]

Solution

  1. Step 1: Analyze the GET handler return

    The GET function returns NextResponse.json with an object containing success: true and data: [1, 2, 3].
  2. Step 2: Understand JSON response format

    This creates a JSON response with the exact object serialized as a JSON string.
  3. Final Answer:

    {"success":true,"data":[1,2,3]} -> Option B
  4. Quick Check:

    NextResponse.json outputs JSON string [OK]
Hint: NextResponse.json sends exact JSON object [OK]
Common Mistakes:
  • Expecting just the array without wrapping object
  • Confusing error responses with success
  • Thinking response is undefined
4. Identify the error in this route.ts code snippet:
export async function POST(request: NextRequest) {
  const data = await request.json();
  return new Response(JSON.stringify(data));
}

export async function GET() {
  return new Response('Hello');
}
medium
A. Missing import of NextRequest
B. GET function must accept a request parameter
C. POST handler should return NextResponse, not Response
D. No error, code is correct

Solution

  1. Step 1: Check imports

    The code uses NextRequest but does not import it from 'next/server'. This causes a runtime error.
  2. Step 2: Validate other parts

    GET handler can omit request parameter if unused. Returning Response is allowed but NextResponse is preferred; not an error. So main error is missing import.
  3. Final Answer:

    Missing import of NextRequest -> Option A
  4. Quick Check:

    Using NextRequest requires import [OK]
Hint: Always import NextRequest when used [OK]
Common Mistakes:
  • Forgetting to import NextRequest
  • Thinking GET must have request param
  • Confusing Response and NextResponse as errors
5. You want to create a route handler in route.ts that responds to both GET and POST requests. The GET returns a JSON list of users, and the POST adds a user from the request body and returns the updated list. Which code snippet correctly implements this behavior?
hard
A. export async function GET(request) { return new Response(JSON.stringify(['Alice', 'Bob'])); } export async function POST(request) { const data = await request.json(); return new Response(JSON.stringify(['Alice', 'Bob'])); }
B. import { NextRequest } from 'next/server'; const users = []; export function get() { return users; } export function post(request) { users.push(request.body.name); return users; }
C. import { NextRequest, NextResponse } from 'next/server'; let users = ['Alice', 'Bob']; export async function GET() { return NextResponse.json(users); } export async function POST(request: NextRequest) { const newUser = await request.json(); users.push(newUser.name); return NextResponse.json(users); }
D. import { NextResponse } from 'next/server'; export async function GET() { return NextResponse.json(['Alice', 'Bob']); } export async function POST() { return NextResponse.json(['Alice', 'Bob', 'Charlie']); }

Solution

  1. Step 1: Check imports and state management

    import { NextRequest, NextResponse } from 'next/server'; let users = ['Alice', 'Bob']; export async function GET() { return NextResponse.json(users); } export async function POST(request: NextRequest) { const newUser = await request.json(); users.push(newUser.name); return NextResponse.json(users); } correctly imports NextRequest and NextResponse, and uses a mutable users array to store state between calls.
  2. Step 2: Verify GET and POST handlers

    GET returns current users as JSON. POST reads JSON body, adds new user, then returns updated list. This matches requirements.
  3. Step 3: Review other options

    import { NextRequest } from 'next/server'; const users = []; export function get() { return users; } export function post(request) { users.push(request.body.name); return users; } uses lowercase method names and no NextResponse, invalid in Next.js route handlers. export async function GET(request) { return new Response(JSON.stringify(['Alice', 'Bob'])); } export async function POST(request) { const data = await request.json(); return new Response(JSON.stringify(['Alice', 'Bob'])); } returns new Response but does not maintain state. import { NextResponse } from 'next/server'; export async function GET() { return NextResponse.json(['Alice', 'Bob']); } export async function POST() { return NextResponse.json(['Alice', 'Bob', 'Charlie']); } POST does not accept request or update users dynamically.
  4. Final Answer:

    import { NextRequest, NextResponse } from 'next/server'; let users = ['Alice', 'Bob']; export async function GET() { return NextResponse.json(users); } export async function POST(request: NextRequest) { const newUser = await request.json(); users.push(newUser.name); return NextResponse.json(users); } -> Option C
  5. Quick Check:

    Correct imports + state + async handlers = import { NextRequest, NextResponse } from 'next/server'; let users = ['Alice', 'Bob']; export async function GET() { return NextResponse.json(users); } export async function POST(request: NextRequest) { const newUser = await request.json(); users.push(newUser.name); return NextResponse.json(users); } [OK]
Hint: Use async GET/POST with NextRequest, NextResponse, and shared state [OK]
Common Mistakes:
  • Using lowercase method names instead of uppercase
  • Not importing NextRequest or NextResponse
  • Not maintaining state between requests
  • Ignoring async/await for request.json()