Node.js + MongoDB
MongoDB with Express and Next.js
Where the client lives in a server, and how a route handler should talk to a collection.
The database client is a server object. It never ships to the browser. Route handlers call a small module that already has a connected client. They return JSON the UI can serialise — ObjectId becomes a string at the edge, not in React.
// db.js
export const client = new MongoClient(process.env.MONGO_URI);
export const users = client.db("app").collection("users");
// server.js
await client.connect();
app.get("/users/:id", async (req, res) => {
const user = await users.findOne({ _id: new ObjectId(req.params.id) });
if (!user) return res.status(404).end();
res.json({ id: user._id.toString(), name: user.name, city: user.city });
});import { MongoClient } from "mongodb";
const uri = process.env.MONGO_URI;
const g = globalThis;
export const client = g._mongoClient ?? new MongoClient(uri);
if (process.env.NODE_ENV !== "production") g._mongoClient = client;
export const db = client.db("app");
// Use db only in Server Components, route handlers, server actions — never in client components.Connect at process start in Express. In Next, first operation can lazy-connect; still one client. Do not import mongodb from a 'use client' file. Do not put MONGO_URI in NEXT_PUBLIC_*. Map documents in the handler so you do not leak passwordHash or a 2MB events array. This is not a full app architecture — it is where the socket lives.
Interview question
Where does MongoClient live in an Express or Next.js app?
On the server, as a singleton: created once, reused in route handlers. In Next.js I cache it on globalThis so hot reload and serverless reuse the pool. I never import the driver in client components or expose MONGO_URI to the browser. Handlers map documents to JSON.