Docs Menu
Docs Home
/ /

Integrate Next.js with MongoDB

In this guide, you can learn how to create a Next.js web application that integrates with MongoDB. Next.js is a React framework that provides server-side rendering, static site generation, and API routes in a single application. The application in this tutorial consists of the following layers:

  • Database layer: MongoDB provides data storage and retrieval.

  • API layer: Next.js API routes handle server-side logic and database operations.

  • Presentation layer: React components implement the user interface and front-end interactions.

Next.js is a full-stack React framework that enables you to build both the front end and back end of your application in a single codebase. By integrating MongoDB with Next.js, you can leverage the following benefits:

  • Unified development: Write both client and server code in JavaScript/TypeScript

  • Server-side rendering: Fetch data from MongoDB during server-side rendering for improved SEO and performance

  • API routes: Create serverless API endpoints that connect directly to MongoDB

  • Flexible data model: MongoDB's document model aligns naturally with JavaScript objects and React component state

Next.js with MongoDB is well-suited for applications that require dynamic content, user authentication, real-time updates, and complex data relationships.

This tutorial shows you how to build a web application by using Next.js and MongoDB. The application accesses sample restaurant data, queries the data, and displays the results on a locally hosted site. The tutorial also includes instructions for connecting to a MongoDB cluster hosted on MongoDB Atlas and accessing and displaying data from your database.

Tip

If you prefer to connect to MongoDB by using the Node.js driver without Next.js, see the Get Started with the Node.js Driver guide.

Follow the steps in this section to install the project dependencies, create an Atlas cluster, and set up the application directories.

1

To create the application, you need the following installed in your development environment:

Prerequisite
Notes

Download either the Latest LTS or Latest Release version.

Code editor

This tutorial uses Visual Studio Code, but you can use the editor of your choice.

Terminal app or shell

For MacOS users, use Terminal or a similar app. For Windows users, use PowerShell.

2

MongoDB Atlas is a fully managed cloud database service that hosts your MongoDB deployments. If you do not have a MongoDB deployment, you can create a MongoDB cluster for free (no credit card required) by completing the MongoDB Get Started tutorial. The MongoDB Get Started tutorial also demonstrates how to load sample datasets into your cluster, including the sample_restaurants database that is used in this tutorial.

To connect to your MongoDB cluster, you must use a connection URI. To learn how to retrieve your connection URI, see the Add your connection string section of the MongoDB Get Started tutorial.

Important

Save your connection string in a secure location.

3

Run the following command in your terminal to create a new Next.js application.

npx create-next-app@latest next-quickstart

The command prompts you to select some configuration options for your project. When prompted, select the option to use the recommended defaults.

After running the command, navigate to the project directory:

cd next-quickstart
4

Run the following command to install the MongoDB Node.js Driver:

npm install mongodb

This command installs the Node.js Driver, which allows your Next.js application to connect to and interact with MongoDB.

After you set up the project structure and dependencies, follow the steps in this section to configure your database connection.

1

In the next-quickstart directory, create a .env.local file that stores your MongoDB connection URI:

MONGODB_URI=<connection URI>

Replace the <connection URI> placeholder with the connection URI that you saved in a previous step.

Note

Next.js automatically loads environment variables from .env.local files. Variables prefixed with NEXT_PUBLIC_ are exposed to the browser, while other variables are only available on the server.

2

In the root directory, create a new directory called lib. Add a new file named mongodb.ts to this directory and paste the following code:

next-quickstart/lib/mongodb.ts
import { MongoClient } from "mongodb";
declare global {
var _mongoClientPromise: Promise<MongoClient> | undefined;
}
const uri = process.env.MONGODB_URI;
const options = {};
let client: MongoClient;
let clientPromise: Promise<MongoClient>;
if (!uri) {
throw new Error("Please add your Mongo URI to .env.local");
}
client = new MongoClient(uri, options);
clientPromise = client.connect();
// Export a module-scoped MongoClient promise. By doing this in a
// separate module, the client can be shared across functions.
export default clientPromise;

This file creates a reusable MongoDB client connection that is shared across your application. The connection is cached to prevent creating multiple connections during development when Next.js hot-reloads your code.

After you set up the database connection, follow the steps in this section to create API routes that query MongoDB and return restaurant data.

1

In the app directory, create a new api/restaurants directory. Add a new file named route.ts to this directory and paste the following code:

next-quickstart/app/api/restaurants/route.ts
import { NextResponse } from "next/server";
import clientPromise from "@/lib/mongodb";
export async function GET() {
try {
const client = await clientPromise;
const db = client.db("sample_restaurants");
const restaurants = await db
.collection("restaurants")
.find({})
.toArray();
return NextResponse.json(restaurants);
} catch {
return NextResponse.json(
{ error: "Failed to fetch restaurants" },
{ status: 500 }
);
}
}

This file defines a GET endpoint at /api/restaurants that retrieves all restaurants from the sample_restaurants database.

2

In the app/api directory, create a new directory called browse. Create a new file named route.ts in this directory and paste the following code:

next-quickstart/app/api/browse/route.ts
import { NextResponse } from "next/server";
import clientPromise from "@/lib/mongodb";
export async function GET() {
try {
const client = await clientPromise;
const db = client.db("sample_restaurants");
const query = {
borough: "Queens",
name: { $regex: "Moon", $options: "i" },
};
const restaurants = await db
.collection("restaurants")
.find(query)
.toArray();
return NextResponse.json(restaurants);
} catch {
return NextResponse.json(
{ error: "Failed to fetch restaurants" },
{ status: 500 }
);
}
}

This file defines a GET endpoint at /api/browse that retrieves restaurants matching specific query criteria. The query filters for restaurants in Queens that contain the word "Moon" in the name.

After you set up the API routes, follow the steps in this section to create the React components that display the restaurant data.

1

In the root directory, create a new directory called components. Add a new file named Navbar.tsx to this directory and paste the following code:

next-quickstart/components/Navbar.tsx
import Link from "next/link";
export default function Navbar() {
return (
<nav className="bg-gray-800 p-4">
<div className="container mx-auto flex justify-between items-center">
<Link href="/" className="text-white text-xl font-bold">
MongoDB Restaurants
</Link>
<div className="space-x-4">
<Link
href="/"
className="text-gray-300 hover:text-white transition-colors"
>
All Restaurants
</Link>
<Link
href="/browse"
className="text-gray-300 hover:text-white transition-colors"
>
Filtered Restaurants
</Link>
</div>
</div>
</nav>
);
}

This component creates a navigation bar with links to view all restaurants and filtered restaurants.

2

In the components directory, create a new file named RestaurantList.tsx and paste the following code:

next-quickstart/components/RestaurantList.tsx
"use client";
/* The above directive tells Next.js to render this component
on the client side instead of the server side.
Client components can use React hooks like useState
and useEffect, while server components cannot.
*/
import { useEffect, useState } from "react";
import { ObjectId } from "mongodb";
interface Restaurant {
_id: ObjectId;
name: string;
borough: string;
cuisine: string;
}
interface RestaurantProps {
restaurant: Restaurant;
}
const Restaurant = (props: RestaurantProps) => (
<tr className="border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted">
<td className="p-4 align-middle [&:has([role=checkbox])]:pr-0">
{props.restaurant.name}
</td>
<td className="p-4 align-middle [&:has([role=checkbox])]:pr-0">
{props.restaurant.borough}
</td>
<td className="p-4 align-middle [&:has([role=checkbox])]:pr-0">
{props.restaurant.cuisine}
</td>
</tr>
);
interface RestaurantListProps {
endpoint: string;
title: string;
}
export default function RestaurantList({ endpoint, title }: RestaurantListProps) {
const [restaurants, setRestaurants] = useState<Restaurant[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function getRestaurants() {
try {
const response = await fetch(endpoint);
if (!response.ok) {
const message = `An error occurred: ${response.statusText}`;
console.error(message);
return;
}
const restaurants = await response.json();
setRestaurants(restaurants);
} catch (error) {
console.error("Error fetching restaurants:", error);
} finally {
setLoading(false);
}
}
getRestaurants();
}, [endpoint]);
function restaurantList() {
return restaurants.map((restaurant) => {
return <Restaurant restaurant={restaurant} key={restaurant._id.toString()} />;
});
}
if (loading) {
return <div className="p-4">Loading...</div>;
}
return (
<>
<h3 className="text-lg font-semibold p-4">{title}</h3>
<div className="border rounded-lg overflow-hidden">
<div className="relative w-full overflow-auto">
<table className="w-full caption-bottom text-sm">
<thead className="[&_tr]:border-b">
<tr className="border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted">
<th className="h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0">
Name
</th>
<th className="h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0">
Borough
</th>
<th className="h-12 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0">
Cuisine
</th>
</tr>
</thead>
<tbody className="[&_tr:last-child]:border-0">
{restaurantList()}
</tbody>
</table>
</div>
</div>
</>
);
}

This component fetches and displays restaurant data from the API routes. It uses React hooks to manage state and fetch data when the component mounts.

3

Navigate to the app/page.tsx file and replace the contents with the following code:

next-quickstart/app/page.tsx
import RestaurantList from "@/components/RestaurantList";
export default function Home() {
return (
<main className="container mx-auto p-4">
<RestaurantList
endpoint="/api/restaurants"
title="All Restaurants"
/>
</main>
);
}

This file renders the home page, which displays all restaurants from the database.

4

In the app directory, create a new directory called browse. Add a new file named page.tsx to this directory and paste the following code:

next-quickstart/app/browse/page.tsx
import RestaurantList from "@/components/RestaurantList";
export default function Browse() {
return (
<main className="container mx-auto p-4">
<RestaurantList
endpoint="/api/browse"
title='Filtered Restaurants (Queens, containing "Moon")'
/>
</main>
);
}

This file renders the browse page, which displays filtered restaurants based on the query criteria.

5

Navigate to the app/layout.tsx file and replace the contents with the following code:

next-quickstart/app/layout.tsx
import "./globals.css";
import Navbar from "@/components/Navbar";
import { Metadata } from "next";
export const metadata: Metadata = {
title: "MongoDB Next.js App",
description: "A Next.js application with MongoDB integration",
};
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<Navbar />
{children}
</body>
</html>
);
}

This file defines the root layout for your application, which includes the navigation bar and wraps all pages.

Finally, follow the steps in this section to run your application and view the rendered restaurant data.

1

Navigate to the next-quickstart directory and run the following command to start the Next.js development server:

npm run dev

If successful, this command outputs the following information:

▲ Next.js 15.1.6
- Local: http://localhost:3000
✓ Starting...
✓ Ready in 2.3s
2

Open the http://localhost:3000/ URL. The initial landing page displays a list of all restaurants in the sample_restaurants.restaurants collection:

The landing page that displays all restaurants

Click the Filtered Restaurants link in the navigation bar to view the restaurants that match the name and borough field query:

The web page that displays the matching restaurants

Congratulations on completing the Quick Start tutorial!

After you complete these steps, you have a Next.js web application that connects to your MongoDB deployment, runs queries on sample restaurant data, and renders the results on a locally hosted website.

To learn more about Next.js and MongoDB, view the following resources:

Back

TanStack Integration

On this page