Understand any MongoDB aggregation pipeline, without connecting a database.
Paste your pipeline and get a plain-English, stage-by-stage walkthrough of what it does to your data, plus warnings for common performance mistakes. Read it, don't run it.
How PipelineExplain works
- 1
Paste your pipeline array
Paste the same array you'd pass to .aggregate(), whether it's valid JSON or Mongo shell syntax with unquoted keys and constructors like ObjectId(...).
- 2
PipelineExplain parses it locally
It tries strict JSON parsing first. If that fails, it falls back to a lenient parser that quotes bare keys, normalizes quotes, and unwraps shell constructors, all in your browser.
- 3
Each stage is identified by its operator
The single top-level key of each stage object ($match, $group, $lookup, and so on) is matched against a library of stage explanations.
- 4
Your actual arguments are read into the explanation
The field names, group keys, and join conditions you passed are pulled directly into the plain-English description, so it reflects your specific pipeline, not a generic template.
- 5
The pipeline is scanned for performance anti-patterns
A late $match, a $sort placed before a $group, and every $lookup are flagged with a note on why they're worth a second look.
- 6
A one-line shape summary sits at the top
Consecutive stages are grouped into categories like filter, group, join, and reshape, so you can see the overall transformation before reading the detail.
What each stage category means
Every stage is tagged with a category so you can scan the overall shape of the pipeline before reading each explanation in full.
Drops documents that don't match a condition ($match, $geoNear). Matters because filtering early reduces how many documents every later stage has to process, and can use an index if placed first.
{ $match: { status: "active" } }Collapses many documents into fewer, one per distinct key ($group, $bucket). Matters because the individual input documents are gone afterwards, only the aggregated result remains, so any stage after a group works on the grouped shape, not the original one.
{ $group: { _id: "$region", total: { $sum: "$amt" } } }Pulls in documents from another collection ($lookup, $graphLookup). Matters because joins are usually the most expensive stage in a pipeline, and an unindexed foreign field turns a fast pipeline into a slow one.
{ $lookup: { from: "customers", localField: "customerId", foreignField: "_id", as: "customer" } }Changes the shape of each document without changing which documents exist ($project, $addFields, $set, $unset, $unwind, $replaceRoot). Matters for knowing which fields are available to stages further down the pipeline.
{ $project: { name: 1, email: 1, password: 0 } }Reorders documents ($sort) or truncates the result set ($limit, $skip). Matters because a $sort over a large, ungrouped, unfiltered set of documents can be an expensive full sort with no index to lean on.
{ $sort: { createdAt: -1 } }Supported pipeline syntax
PipelineExplain accepts strict JSON as well as the looser syntax MongoDB shells and drivers commonly produce.
// Strict JSON works as-is
[{ "$match": { "status": "active" } }]
// Unquoted keys (Mongo shell style) are quoted automatically
[{ $match: { status: "active" } }]
// Single-quoted strings are normalized to double-quoted
[{ $match: { status: 'active' } }]
// Shell constructors are unwrapped to their inner value
[{ $match: { _id: ObjectId('64f1a2b3c4d5e6f7a8b9c0d1') } }]
[{ $match: { createdAt: { $gte: ISODate('2026-01-01') } } }]
// Trailing commas are tolerated
[
{ $sort: { createdAt: -1 } },
]Not supported: JavaScript function expressions inside a stage (e.g. a custom `$function` body), and multi-line template literals used as field values.
When to use PipelineExplain
| Situation |
|---|
| Reviewing a PR that touches an aggregation pipeline |
| Reading a pipeline from a Stack Overflow answer |
| Learning how $group and $unwind compose |
| Inheriting an unfamiliar codebase with no local DB access yet |
| Sanity-checking stage order before running it for real |
Frequently Asked Questions
What does PipelineExplain do?
PipelineExplain takes a MongoDB aggregation pipeline array, the same array you'd pass to .aggregate(), and walks through it stage by stage, explaining in plain English what each stage does to your documents.
It also flags common performance mistakes, like a $match that isn't placed early enough, or a $sort running before a $group that could be pushed later.
Does PipelineExplain actually run my pipeline against real data?
No. It never connects to a database and never executes your pipeline. It statically reads the shape of the pipeline (the operators and their arguments) and explains what each stage would do, based on how that operator behaves.
How is this different from MongoDB Compass's aggregation builder?
| MongoDB Compass | PipelineExplain | |
|---|---|---|
| Requires a live database connection | Yes | No |
| Shows your real documents at each stage | Yes | No, illustrative only |
| Works on a pipeline pasted from a PR or Stack Overflow | Only after connecting a matching DB | Yes, immediately |
| Flags performance anti-patterns | Via Explain Plan (needs a run) | Yes, statically |
Compass (and similar tools like Studio 3T or Mongon) are the better choice when you have a database in front of you and want to see real output at each stage. PipelineExplain is for the moment you're reading a pipeline, in a PR, a doc, or someone else's codebase, and don't have that database handy.
Does PipelineExplain send my pipeline to a server?
No. Parsing and explanation generation all run in JavaScript inside your browser. There's no backend, no API call, and no logging of what you paste. If your pipeline references sensitive field or collection names, they never leave your machine.
My pipeline uses unquoted keys from the Mongo shell, will it still parse?
Yes. If strict JSON parsing fails, PipelineExplain falls back to a lenient parser that quotes bare keys, normalizes single-quoted strings, strips trailing commas, and unwraps common shell constructors like ObjectId(...) and ISODate(...).
[
{ $match: { _id: ObjectId('64f1a2b3c4d5e6f7a8b9c0d1') } },
{ $sort: { createdAt: -1 } },
]This pastes and parses fine even though the keys aren't quoted and ObjectId(...) isn't valid JSON. If parsing still fails, the error message will point at which stage broke.
What happens if I use a stage operator PipelineExplain doesn't have a template for?
It still shows the stage in the list with its position and category, but instead of a tailored explanation, it shows the raw stage arguments. The MVP covers $match, $group, $project, $addFields, $set, $unset, $sort, $limit, $skip, $unwind, $lookup, $facet, $count, $replaceRoot, $sample, $out, $merge, and $geoNear. Rarer stages like $bucket or $graphLookup fall back to the generic explanation.