# Deploy an Express + MongoDB REST API to Production (Mongoose, 2026)

Build and deploy a production Express API with MongoDB and Mongoose: MONGODB_URI, validation, error handling, security middleware and graceful shutdown.

URL: https://blog.dockhosting.dev/deploy-express-mongodb-api
Published: 2026-10-20 · Updated: 2026-10-20 · Author: Doughmi ILYAS

## Summary

- Attach a managed MongoDB database and connect with process.env.MONGODB_URI: it's injected over a private network.
- Connect once at startup and reuse the connection; close it on SIGTERM so zero-downtime deploys stay clean.
- Add helmet, body-size limits and a central error handler before you go live.

ort const meta = {
  title: "Deploy an Express + MongoDB REST API to Production (Mongoose, 2026)",
  seoTitle: "Deploy an Express + MongoDB API to Production",
  description:
    "Build and deploy a production Express API with MongoDB and Mongoose: MONGODB_URI, validation, error handling, security middleware and graceful shutdown.",
  date: "2026-10-20",
  category: "Guides",
  tags: ["Express", "MongoDB", "Mongoose", "Node.js", "API"],
  stack: ["express", "mongodb", "mongoose"],
  tryLabel: "Express API",
  command: "dock deploy",
  takeaways: [
    "Attach a managed MongoDB database and connect with process.env.MONGODB_URI: it's injected over a private network.",
    "Connect once at startup and reuse the connection; close it on SIGTERM so zero-downtime deploys stay clean.",
    "Add helmet, body-size limits and a central error handler before you go live.",
  ],
  faq: [
    {
      q: "Is there a free MongoDB database?",
      a: "Yes. DockHosting's Free plan includes one managed database, which can be MongoDB, with 500 MB of storage that doesn't pause or expire. Daily backups start on Hobby.",
    },
    {
      q: "Can I connect to the database with MongoDB Compass from my laptop?",
      a: "Public database access is available on Hobby and up. On every plan, your app connects over the private network.",
    },
    {
      q: "Which Node.js versions are supported?",
      a: "Node.js 20 and 22 LTS, with npm, pnpm or yarn chosen from your lockfile.",
    },
  ],
};

Express and MongoDB are still one of the quickest ways to ship a JSON API. This guide builds a small production-ready API with Mongoose and deploys it with a managed MongoDB database.

## 1. Connect once, from the environment

```js
// db.js
import mongoose from "mongoose";

export async function connect() {
  await mongoose.connect(process.env.MONGODB_URI);
  console.log("MongoDB connected");
}
```

When you attach a managed MongoDB database to the project, `MONGODB_URI` is injected into the app's environment and reached over a **private network**, with no public port to secure. Standard drivers read it unchanged.

## 2. A model with validation

```js
// models/Todo.js
import mongoose from "mongoose";

const todoSchema = new mongoose.Schema(
  {
    title: { type: String, required: true, trim: true, maxlength: 200 },
    done: { type: Boolean, default: false },
  },
  { timestamps: true },
);

export const Todo = mongoose.model("Todo", todoSchema);
```

Schema validation is your first line of defense against bad input. It rejects missing or oversized fields before they reach the database.

## 3. The API

```js
// server.js
import express from "express";
import helmet from "helmet";
import mongoose from "mongoose";
import { connect } from "./db.js";
import { Todo } from "./models/Todo.js";

const app = express();
app.use(helmet());
app.use(express.json({ limit: "100kb" }));

app.get("/health", (_, res) => res.json({ ok: mongoose.connection.readyState === 1 }));

app.get("/todos", async (_, res) => res.json(await Todo.find().sort({ createdAt: -1 }).limit(100)));

app.post("/todos", async (req, res) => {
  const todo = await Todo.create({ title: req.body.title });
  res.status(201).json(todo);
});

// Central error handler: validation errors → 400, everything else → 500.
app.use((err, _req, res, _next) => {
  if (err instanceof mongoose.Error.ValidationError) return res.status(400).json({ error: err.message });
  console.error(err);
  res.status(500).json({ error: "Internal error" });
});

await connect();
const server = app.listen(process.env.PORT || 3000);

// Finish in-flight requests and close the DB connection when the platform stops the old release.
process.on("SIGTERM", () => server.close(() => mongoose.disconnect().then(() => process.exit(0))));
```

In Express 5, errors thrown inside `async` handlers reach the error handler automatically.

```json
{
  "type": "module",
  "scripts": { "start": "node server.js" },
  "dependencies": { "express": "^5", "helmet": "^8", "mongoose": "^8" }
}
```

> Only pick the fields you expect from `req.body` (as `title` is picked above) instead of passing the whole body to `create`. That blocks clients from setting fields you didn't intend, like `isAdmin`.

## 4. Deploy

```bash
curl -fsSL https://cli.dockhosting.dev/install.sh | sh   # Windows: irm https://cli.dockhosting.dev/install.ps1 | iex
dock login
dock deploy
```

Express is detected from `package.json`, dependencies are installed with the package manager that matches your lockfile, and the app starts with `npm start`. Attach a **MongoDB** database in the dashboard, run `dock restart`, and check `https://<project>.dockhosting.cloud/health`.

## 5. Before real users arrive

- **Indexes:** add indexes for the fields you query on, such as `todoSchema.index({ createdAt: -1 })`.
- **Rate limiting:** add a limiter (attach managed Redis and use `REDIS_URL` if you run several instances).
- **Backups:** paid plans back up databases daily (kept 3, 7 or 30 days).
- **Always on:** Free apps sleep after an hour idle. Hobby ($4/month) keeps the API awake.

Prefer SQL? The same flow works with PostgreSQL and `DATABASE_URL`: see [connecting to managed PostgreSQL](/connect-app-to-managed-postgresql). New to deploying Node.js? Start with [one-command deploys](/deploy-nodejs-app-one-command).

**Related:** [Free Node.js hosting that doesn't sleep](/free-nodejs-hosting-without-sleeping)

## FAQ

### Is there a free MongoDB database?

Yes. DockHosting's Free plan includes one managed database, which can be MongoDB, with 500 MB of storage that doesn't pause or expire. Daily backups start on Hobby.

### Can I connect to the database with MongoDB Compass from my laptop?

Public database access is available on Hobby and up. On every plan, your app connects over the private network.

### Which Node.js versions are supported?

Node.js 20 and 22 LTS, with npm, pnpm or yarn chosen from your lockfile.
