The mongosh Shell
mongosh is MongoDB’s official command-line shell — an interactive JavaScript environment for connecting to a MongoDB server, running queries, and administering databases. It’s the tool you’ll reach for every day to explore data, test aggregation pipelines, and debug problems before writing application code, because it lets you talk to MongoDB using the same JavaScript syntax the Node.js driver uses. Since MongoDB 5.0 it has replaced the legacy mongo shell, which is no longer bundled with current MongoDB installations.
Overview / How mongosh Works
mongosh is built on Node.js and runs on the same V8 JavaScript engine that powers Node and Chrome. That matters more than it sounds: mongosh is a genuine JavaScript REPL (Read-Eval-Print-Loop), not a shell that merely looks like JavaScript. Modern JS features work as-is — arrow functions, destructuring, template literals, for...of loops, and top-level await for asynchronous operations. Anything you learn here transfers almost directly to application code written against the Node.js driver, because mongosh’s collection and database methods (find, insertOne, aggregate, and so on) mirror the driver’s API.
When mongosh connects to a server, it opens a TCP (or TLS) connection and speaks MongoDB’s wire protocol — a binary protocol built around OP_MSG messages that carry BSON (Binary JSON) documents. BSON is a superset of JSON: it adds types JSON can’t represent natively, such as ObjectId, Date, Decimal128, and binary data, and it’s what’s actually stored on disk and sent over the wire. When you type db.students.find({ age: { $gt: 21 } }), mongosh serializes that query document to BSON, sends it to the server, and the server streams back a cursor of BSON documents that mongosh deserializes and pretty-prints as JavaScript objects. Authentication (by default SCRAM-SHA-256) happens once during the initial handshake, before any commands run.
A subtlety worth internalizing early: mongosh auto-prints the return value of whatever expression you evaluate, and for a cursor specifically it doesn’t dump everything at once — it fetches and displays the first batch (20 documents) and stops. If more documents exist, typing it on its own line fetches and prints the next batch. This is a shell convenience so a huge find() doesn’t flood your terminal; it does not affect how many documents an application using the driver would receive, since there you explicitly iterate or call .toArray().
Finally, a handful of commands you’ll type constantly — use, show dbs, show collections, exit — are not real JavaScript. mongosh’s REPL specially recognizes this small set of shell-style shortcuts and translates them internally (for example, use school becomes something equivalent to db = db.getSiblingDB('school')). They only work when typed interactively (or via mongosh’s --eval, which also recognizes them); they are syntax errors in a plain .js file executed by Node or loaded as a module. Keep this distinction in mind — it’s the single most common source of confusion for people new to mongosh.
Syntax
Starting mongosh follows this general form:
mongosh [connection string] [options]
With no arguments, mongosh tries to connect to a MongoDB server on localhost:27017 with no authentication — convenient for local development. For anything else, you supply either a full connection string or individual flags:
# Connect to a local server on the default port
mongosh
# Connect to a specific host/port with authentication
mongosh --host 127.0.0.1 --port 27017 --username appUser --authenticationDatabase admin
# Connect using a full connection string (Atlas or self-hosted)
mongosh "mongodb+srv://<user>:<password>@<cluster-url>/mydb"
| Option | Purpose |
|---|---|
--host, --port |
Target server address, used instead of a connection string. |
--username, --password |
Credentials; omit --password to be prompted interactively instead of leaving it in shell history. |
--authenticationDatabase |
The database that holds the user’s credentials (often admin). |
--eval "<code>" |
Runs one command (or shortcut) non-interactively, then exits — useful in scripts. |
--file <path> |
Executes a .js file non-interactively, then exits. |
--quiet |
Suppresses the startup banner and connection log noise. |
--nodb |
Starts mongosh without connecting to any server (useful for testing plain JS). |
Examples
Example 1: Connecting and exploring what’s on the server
Once connected, use the shell-only shortcuts to see what databases and collections already exist:
show dbs
use school
show collections
db
Output:
admin 40.00 KiB
config 60.00 KiB
local 40.00 KiB
school 72.00 KiB
switched to db school
students
courses
school
show dbs lists every database that actually contains data (empty databases are invisible here — more on that in Common Mistakes). use school switches the shell’s context so the global db variable now points at the school database. show collections lists the collections inside it, and evaluating the bare db variable prints the name of the currently selected database.
Example 2: Inserting and querying with real JavaScript
Everything past this point is ordinary JavaScript method calls — no shell magic:
db.students.insertOne({
name: "Ava Thompson",
age: 21,
major: "Computer Science",
gpa: 3.8,
enrolled: true
});
db.students.find({ major: "Computer Science" });
Output:
{
acknowledged: true,
insertedId: ObjectId('66b1f2a1c8e4a1234567890a')
}
[
{
_id: ObjectId('66b1f2a1c8e4a1234567890a'),
name: 'Ava Thompson',
age: 21,
major: 'Computer Science',
gpa: 3.8,
enrolled: true
}
]
insertOne returns an acknowledgment object containing the generated ObjectId. find() returns a cursor; because we evaluated it directly at the top level, mongosh iterated it for us and pretty-printed the resulting array of matching documents. Note the modern method name — older tutorials may show the removed insert(), which no longer exists in current MongoDB versions.
Example 3: Running mongosh non-interactively
For scripting and automation you don’t want an interactive prompt at all. --eval runs one line and exits; --file runs a whole script:
# Run a single command non-interactively and exit
mongosh "mongodb://localhost:27017/school" --quiet --eval "db.students.countDocuments()"
# Run a whole script file non-interactively
mongosh "mongodb://localhost:27017/school" --file ./seed.js
Output:
4
Inside an interactive session, mongosh also supports top-level await, which is invaluable once you start chaining asynchronous calls or writing multi-step scripts directly at the prompt:
const activeStudents = await db.students.find({ enrolled: true }).toArray();
activeStudents.length;
Output:
3
.toArray() fully drains the cursor into a real JavaScript array (rather than the shell’s 20-document auto-print limit), and await works without wrapping anything in an async function, because mongosh’s REPL evaluates each entry inside an implicit async context.
How it works step by step
- mongosh parses the connection string or flags and resolves the target host(s), reading any
mongodb+srv://DNS seed list if used. - It opens a TCP connection (upgraded to TLS if requested) and performs an initial
hellohandshake to learn the server’s wire protocol version and topology (standalone, replica set, or sharded cluster). - If credentials were supplied, mongosh completes a SCRAM-SHA-256 authentication exchange before any data commands are allowed to run.
- The REPL reads a line (or a multi-line block) of input, and before evaluating it, checks whether it matches one of the handful of shell-only shortcuts (
use,show ...,exit); if so, it runs the equivalent internal logic instead of treating the input as JavaScript. - Otherwise, the input is evaluated as real JavaScript in a context where
dbis bound to the currently selected database. Calling a method likedb.students.find(...)builds a command document, serializes it to BSON, and wraps it in anOP_MSGwire-protocol message. - The server executes the command — for a query, this means the query planner decides whether to use an index (
IXSCAN) or scan the whole collection (COLLSCAN) — and streams back a batch of BSON result documents. - mongosh deserializes the response and either returns a lazy
Cursorobject (for queries) or prints the result document directly (for writes, admin commands, and anything already resolved, like an array from.toArray()).
Common Mistakes
Mistake 1: Assuming use newdb creates the database
MongoDB creates databases (and collections) lazily, on first write — use only switches the shell’s context, it performs no server-side action by itself.
use newdb
show dbs
Output (newdb is missing):
admin 40.00 KiB
config 60.00 KiB
local 40.00 KiB
The database only appears once you actually write a document to it:
use newdb
db.placeholder.insertOne({ createdAt: new Date() });
show dbs
Output:
admin 40.00 KiB
config 60.00 KiB
local 40.00 KiB
newdb 8.00 KiB
Mistake 2: Putting shell shortcuts inside a script file
use and show are REPL-only shortcuts — they are not valid JavaScript, so a script run with mongosh --file throws a syntax error if it contains them.
// seed.js — FAILS when run as: mongosh --file seed.js
use school
db.students.insertMany([{ name: "Priya" }, { name: "Marcus" }]);
Output:
Uncaught SyntaxError: Unexpected identifier 'school'
Replace use with the real JavaScript equivalent, getSiblingDB(), which works identically inside scripts and the interactive shell:
// seed.js — works with: mongosh --file seed.js
db = db.getSiblingDB("school");
db.students.insertMany([{ name: "Priya" }, { name: "Marcus" }]);
Output:
{
acknowledged: true,
insertedIds: { '0': ObjectId('66b1f3c2c8e4a1234567890b'), '1': ObjectId('66b1f3c2c8e4a1234567890c') }
}
Mistake 3: Reaching for the deprecated count()
Older tutorials and habits from the legacy shell often lead people to call count() on a collection. It still runs in current MongoDB versions but is deprecated and slower than the purpose-built replacements.
db.students.count({ major: "Computer Science" });
Output:
DeprecationWarning: Collection.count() is deprecated. Use countDocuments or estimatedDocumentCount.
2
Use countDocuments() for an accurate count matching a filter, or the much cheaper estimatedDocumentCount() when you just want the size of the whole collection and can tolerate an estimate based on collection metadata:
db.students.countDocuments({ major: "Computer Science" });
db.students.estimatedDocumentCount();
Output:
2
4
Best Practices
- Prefer a full connection string with
--quietover separate--host/--port/--usernameflags in scripts — it’s easier to swap between environments. - Never type your password directly after
--passwordon the command line in a shared or logged environment; omit it so mongosh prompts you, or use an environment variable your shell doesn’t echo. - Remember that
use,show dbs, andshow collectionsonly work interactively or via--eval— usegetSiblingDB()in any file passed to--fileorload(). - Use
.toArray()(or explicit iteration) instead of relying on the 20-document auto-print limit whenever you need the full result set, especially inside scripts. - Keep a
.mongoshrc.jsfile in your home directory for personal setup (custom prompt, helper functions) that should load every session. - Use
explain()on slow-looking queries directly in mongosh before touching application code — it’s the fastest way to confirm whether an index is actually being used. - Install mongosh as a standalone package rather than relying on an old
mongobinary from a legacy MongoDB install — the legacy shell no longer receives updates.
Practice Exercises
- Start mongosh with no arguments against a local server, run
show dbs, then create alibrarydatabase containing abookscollection by inserting one document into it. Confirm the database now appears inshow dbs. - Write a script file
load_books.jsthat switches to thelibrarydatabase using the correct JavaScript-safe method (notuse) and inserts three book documents withinsertMany. Run it withmongosh --file load_books.js. - From inside mongosh, use
--evalfrom your terminal to non-interactively print the result ofdb.books.countDocuments()against thelibrarydatabase, without opening an interactive session.
Summary
- mongosh is a real JavaScript REPL built on Node.js/V8 — modern JS syntax, including top-level
await, works directly at the prompt. - A small set of commands (
use,show dbs,show collections,exit) are shell-only shortcuts, not JavaScript, and fail inside scripts run with--file. - Under the hood, commands are serialized to BSON and sent over MongoDB’s wire protocol as
OP_MSGmessages; results come back the same way. - A printed cursor auto-shows only its first batch (20 documents) — use
itto continue, or.toArray()to get everything at once. - Databases and collections are created lazily on first write, not by
usealone. --evaland--filemake mongosh usable non-interactively for automation and seeding scripts.- Always use current method names (
countDocuments,insertOne/insertMany,updateOne/updateMany) rather than deprecated legacy equivalents.
