A lightweight, self-hosted web UI for browsing, querying, and editing MongoDB.
Point it at one MONGODB_URI, log in, and work with your data from the browser —
databases, collections, documents, queries, aggregations, and indexes.
Quick start · Features · Configuration · API · Security
| 🗂️ Navigate | Sidebar tree of databases and collections with document counts; create a database or collection inline. |
| 📋 Browse | Paginated, capped document table — a large collection is never loaded in full. |
| 🔎 Query | Filter, sort, and projection as Extended JSON, validated server-side before it reaches the driver. |
| ✍️ Edit | Full document CRUD in a CodeMirror 6 JSON editor with syntax highlighting and parse errors surfaced inline. |
| 🧮 Aggregate | Run pipelines against a collection; write stages ($out, $merge) are blocked in read-only mode. |
| ⚡ Indexes | List, create, and drop indexes per collection. |
| 🔐 Auth | Cookie session via iron-session + bcrypt. Every API route is guarded; unauthenticated calls get 401. |
| 🛡️ Read-only mode | READ_ONLY=true makes every write path return 403 before it touches the database. |
| 🧬 EJSON end to end | ObjectId, Date, Decimal128 round-trip safely — no silent JSON.stringify corruption. |
| ♻️ One pooled connection | A single cached MongoClient singleton, reused across requests and hot reloads. |
| 🐳 Ships as a container | Multi-stage Dockerfile, OCI labels, and a Compose file with a sample MongoDB. |
docker compose up --build
# open http://localhost:3000 (login: admin / change-me)Change
ADMIN_PASSWORDandSESSION_SECRETindocker-compose.ymlbefore any real use.
Published as a multi-arch manifest (linux/amd64 + linux/arm64) on every
v* tag, to ghcr.io/soumya7681/mongui and docker.io/soumyaranajan/mongui.
docker run -p 3000:3000 \
-e MONGODB_URI="mongodb://user:pass@host:27017/?authSource=admin" \
-e ADMIN_USER=admin \
-e ADMIN_PASSWORD="a-strong-password" \
-e SESSION_SECRET="$(node -e "console.log(require('crypto').randomBytes(32).toString('hex'))")" \
ghcr.io/soumya7681/mongui:latestBuild it yourself instead with docker build -t mongui ..
Requires Node.js 20.9+ and a reachable MongoDB.
npm install
cp .env.example .env.local # then edit the values
npm run dev # http://localhost:3000Everything is environment variables — see .env.example.
| Variable | Required | Default | Description |
|---|---|---|---|
MONGODB_URI |
✅ | — | Connection string for the single MongoDB instance. Include credentials + authSource when the server has auth enabled. |
ADMIN_USER |
✅ | — | Login username. |
ADMIN_PASSWORD |
✅ | — | Login password in plaintext — Mongui bcrypt-hashes it at runtime, so you never generate or escape a hash yourself. |
SESSION_SECRET |
✅ | — | 32+ character secret encrypting the session cookie. Generate with node -e "console.log(require('crypto').randomBytes(32).toString('hex'))". |
READ_ONLY |
— | false |
When true, every write (insert / update / delete / drop / $out / $merge) returns 403. |
Secrets live in .env.local (gitignored); .env.example documents every variable.
Warning
Mongui grants full read/write access to the configured database. Do not expose it
on the public internet. Keep it behind a network boundary (VPN or private network),
always set a strong ADMIN_PASSWORD and a random SESSION_SECRET, and use
READ_ONLY=true for a browse-only deployment.
Built-in guardrails:
- Session check on every route under
/apiexceptauth/login. - Login rate limiting to blunt brute-force attempts.
- Query limits capped server-side (max 200 documents per page) plus a
maxTimeMSon every operation. - Filters, sorts, and projections validated with zod; unparseable input is rejected with
400, never passed through. - Destructive UI actions require confirmation — drops require typing the name.
All routes return JSON. Errors use { "status": "error", "message": string }.
| Method | Route | Purpose |
|---|---|---|
GET |
/api/health |
Ping + MongoDB server version. |
POST |
/api/auth/login |
Create a session. |
POST |
/api/auth/logout |
Destroy the session. |
GET |
/api/databases |
List databases. |
GET POST DELETE |
/api/databases/[db]/collections |
List, create, or drop collections in a database. |
GET POST |
/api/databases/[db]/[collection]/docs |
Query (filter/sort/projection/pagination) or insert. |
GET PUT DELETE |
/api/databases/[db]/[collection]/docs/[id] |
Read, replace, or delete one document. |
POST |
/api/databases/[db]/[collection]/aggregate |
Run an aggregation pipeline (capped, read-only aware). |
GET POST DELETE |
/api/databases/[db]/[collection]/indexes |
List, create, or drop indexes. |
Example: query with a filter
curl -s 'http://localhost:3000/api/databases/mydb/users/docs?filter={"age":{"$gt":21}}&sort={"age":-1}&limit=20' \
-H 'Cookie: <session cookie>'Filter, sort, and projection are Extended JSON, so {"_id":{"$oid":"..."}} works as expected.
npm run dev # dev server (Turbopack) on :3000
npm run build # production build
npm run start # serve the production build
npm run lint # eslint
npm test # vitest unit testsNext.js 16 (App Router, Turbopack) · React 19 · TypeScript (strict) ·
official mongodb driver 7 · Tailwind CSS 4 · TanStack Query & Table ·
CodeMirror 6 · iron-session · bcryptjs · zod · Vitest.
Issues and pull requests are welcome. Run npm run lint, npm test, and
npm run build before opening a PR — CI runs the same on Node 22.
Project context for contributors (and coding agents) lives in
AGENTS.md, scope in PLAN.md, and detailed
requirements in REQUIREMENTS.md.
MIT © Soumyaranjan