Faiz Khan | Portfolio | Fullstack Developer

Faiz Khan | Next.js | Freelancer | Web Developer | Fullstack Developer | Portfolio | Web Development | Portfolio Website | Blog | Software Development | Personal Website | Software Engineer | React | Typescript | Node.js | Python | MongoDB | TailwindCSS | Express.js

Faiz Khan | Portfolio

Explore the portfolio of Faiz Khan, showcasing my skills, projects, and experience as a fullstack developer

Next.js | React | Typescript | Node.js | TailwindCSS | Python | AWS | GCP | Docker | AI

Next.js

Building Scalable APIs with Next.js App Router and Bun

Building Scalable APIs with Next.js App Router and Bun
0 views
5 min read
#Next.js

Introduction

Building scalable APIs is crucial for any modern web application. With the release of Next.js 14, we get even more powerful routing capabilities through the App Router, allowing us to create server-side API routes with enhanced flexibility. Pairing this with Bun, a fast runtime, ensures that your APIs are not only efficient but also fast at runtime.

In this detailed guide, we'll walk through how to set up API routes using the Next.js App Router and how Bun boosts the performance of these APIs. Additionally, we'll integrate a database (MongoDB) to make your APIs more practical and scalable for real-world applications.

Step 1: Setting Up the Project with Bun

Before anything else, let’s set up a new Next.js project using Bun. We’ll use the Next.js App Router instead of the traditional pages directory.

bun x create-next-app@latest --experimental-app
cd scalable-api

This command creates a new Next.js 14 project with the App Router enabled. Bun will speed up installation, compiling, and running your project as well.

Step 2: Creating an API Route with the Next.js App Router

In Next.js 14, the App Router provides a more flexible way of handling routes and API endpoints. Instead of adding API routes inside the pages/api directory, you’ll now create them within the new app directory.

To create your first API route, navigate to the app/api/ directory and create a new route like so:

// app/api/hello/route.ts

import { NextResponse } from 'next/server';

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

By defining this route, Next.js will automatically expose an API endpoint at /api/hello. The GET method returns a simple JSON response.

Step 3: Adding POST and Dynamic API Routes

Now let’s add a dynamic API route to handle POST requests, which is essential when dealing with user inputs or form data.

// app/api/users/route.ts

import { NextResponse } from 'next/server';

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

  if (!body.name || !body.email) {
    return NextResponse.json({ error: "Missing fields" }, { status: 400 });
  }

  // Add user to database (we'll handle the DB in the next step)
  return NextResponse.json({ message: "User created successfully" });
}

This POST request handler processes user data and can interact with a database for persistence. The NextResponse object allows us to structure the response, including setting status codes easily.

Step 4: Connecting MongoDB for Scalability

For any scalable API, persistence is essential. In this example, we'll use MongoDB as our database. To get started, install MongoDB's official client:

bun add mongodb

Create a MongoDB connection utility in the lib folder:

// lib/mongodb.ts

import { MongoClient } from "mongodb";

const client = new MongoClient(process.env.MONGODB_URI!);
let db;

export async function getDb() {
  if (!db) {
    await client.connect();
    db = client.db("nextjs-app");
  }
  return db;
}

Now, update the POST request handler to store data in MongoDB:

// app/api/users/route.ts

import { NextResponse } from 'next/server';
import { getDb } from '@/lib/mongodb';

export async function POST(req: Request) {
  const { name, email } = await req.json();
  const db = await getDb();

  if (!name || !email) {
    return NextResponse.json({ error: "Missing fields" }, { status: 400 });
  }

  await db.collection("users").insertOne({ name, email });
  return NextResponse.json({ message: "User created successfully" });
}

This implementation ensures that each POST request adds a new user to the MongoDB database.

Step 5: Fetching Data with GET Requests

Now that we’ve stored data, let’s create a GET request to fetch the users from MongoDB:

// app/api/users/route.ts

import { NextResponse } from 'next/server';
import { getDb } from '@/lib/mongodb';

export async function GET() {
  const db = await getDb();
  const users = await db.collection("users").find().toArray();
  return NextResponse.json(users);
}

This API route retrieves all users from the MongoDB collection and returns them as a JSON response. You now have fully functioning API routes for both creating and fetching users.

Step 6: Optimizing API Performance with Bun

Bun comes in handy when it’s time to optimize your API performance. The runtime is significantly faster than Node.js, making API responses quicker, especially under heavy traffic.

To build your app for production and further optimize it with Bun, run:

bun build

This command will bundle your Next.js app, including all API routes, for production. With Bun, this process is faster and results in a highly optimized build.

Step 7: Deploying to Production

Once you have your app built and APIs tested, it's time to deploy. Platforms like Vercel support Bun, and the deployment process is seamless.

Make sure your .env file includes the MongoDB URI and other environment variables:

MONGODB_URI=mongodb+srv://username:password@cluster.mongodb.net/nextjs-app

Finally, push your project to a Git repository, and deploy it to Vercel or any other Bun-compatible hosting provider.

Step 8: Scaling Best Practices

To make sure your APIs scale effectively in production, consider the following tips:

  1. Caching: Implement caching for frequently accessed routes using edge caching or tools like Redis.
  2. Database Indexing: Ensure your MongoDB collections are properly indexed for faster lookups.
  3. Rate Limiting: Use rate-limiting libraries to prevent abuse from excessive API requests.
  4. Error Handling: Provide robust error handling, especially for unexpected situations like database downtime.
if (!user) {
  return NextResponse.json({ error: "User not found" }, { status: 404 });
}

Conclusion

By leveraging the Next.js 14 App Router and Bun, you've created a highly scalable and optimized API environment. Using MongoDB as your persistence layer ensures that your app can handle high traffic while Bun makes sure that your API routes run efficiently. The new App Router simplifies the process of creating both static and dynamic API routes, making Next.js even more powerful for full-stack development.

Happy coding, and enjoy the performance boost from Bun!