This chapter follows A short history of MongoDB. The examples assume MongoDB Server 8.0.x, the Node.js driver 7.8.x, and Node.js 20+. Pin versions in your own projects and check the driver compatibility table when you upgrade the server.
Run MongoDB in Docker
For local development, the community server image is enough for CRUD, aggregation, and geospatial exercises in this series:
docker pull mongodb/mongodb-community-server:8.0-ubuntu2204docker run --name mongo-dev -p 27017:27017 \ -e MONGO_INITDB_ROOT_USERNAME=dev \ -e MONGO_INITDB_ROOT_PASSWORD=devpass \ -d mongodb/mongodb-community-server:8.0-ubuntu2204Verify with mongosh (install from MongoDB Download Center):
mongosh "mongodb://dev:devpass@localhost:27017/admin" --eval "db.runCommand({ ping: 1 })"Create a free Atlas cluster
- Sign up at MongoDB Atlas.
- Create an M0 free cluster in a region close to you.
- Add a database user and note the username and password.
- Under Network Access, allow your IP (or
0.0.0.0/0only for short-lived experiments). - Copy the connection string from Connect → Drivers.
Install the Atlas CLI if you prefer terminal workflows (Atlas CLI docs):
curl -sSf https://fastdl.mongodb.org/mongocli/mongodb-atlas-cli_latest_linux_x86_64.tar.gz | tar -xz# move atlas binary to your PATH, then:atlas auth loginatlas clusters listAtlas URIs look like mongodb+srv://USER:PASS@cluster0.example.mongodb.net/myApp?retryWrites=true&w=majority. The mongodb+srv form resolves replica set members from DNS; the driver handles TLS automatically.
Install the Node.js driver
In your TypeScript project:
pnpm add mongodbpnpm add -D typescript @types/nodeThe mongodb package ships its own TypeScript types; you do not need @types/mongodb.
Connection string anatomy
| Part | Meaning |
|---|---|
mongodb:// or mongodb+srv:// |
Protocol; SRV for Atlas-style DNS |
user:pass@ |
Credentials (URL-encode special characters) |
host:27017 |
Server or seed host |
/myDb |
Default database name |
?authSource=admin |
Database that holds the user (often admin for root) |
&replicaSet=rs0 |
Required for some replica set connections |
Store secrets in environment variables, not source control:
export MONGODB_URI="mongodb://dev:devpass@localhost:27017/myapp?authSource=admin"A typed client module
Reuse one MongoClient per process. The driver pools connections internally.
import { MongoClient, Db } from 'mongodb';
const uri = process.env.MONGODB_URI;if (!uri) { throw new Error('MONGODB_URI is not set');}
const client = new MongoClient(uri, { maxPoolSize: 20, serverSelectionTimeoutMS: 5_000, socketTimeoutMS: 45_000,});
let connectPromise: Promise<MongoClient> | undefined;
export async function getClient(): Promise<MongoClient> { if (!connectPromise) { connectPromise = client.connect().then(() => client); } return connectPromise;}
export async function getDb(name = process.env.MONGODB_DB ?? 'myapp'): Promise<Db> { const c = await getClient(); return c.db(name);}
export async function closeClient(): Promise<void> { if (connectPromise) { await client.close(); connectPromise = undefined; }}Ping after connect in health checks:
import { getClient } from './client.js';
export async function pingMongo(): Promise<boolean> { const client = await getClient(); await client.db('admin').command({ ping: 1 }); return true;}Graceful shutdown
Register shutdown hooks so in-flight operations finish before the process exits:
import { closeClient } from './db/client.js';
async function shutdown(signal: string) { console.log(`Received ${signal}, closing MongoDB client`); await closeClient(); process.exit(0);}
process.on('SIGINT', () => void shutdown('SIGINT'));process.on('SIGTERM', () => void shutdown('SIGTERM'));Next: Authentication in MongoDB.