A MongoDB change stream monitor watches inserts, updates, replacements, and deletes as they happen. It is useful for debugging an event-driven feature, confirming that a write reached the expected collection, and seeing the exact update delta without tailing application logs. It is not automatically a durable consumer. A live table with a green dot can still forget everything the moment you close it. The dot remains emotionally unaffected.

Change streams require replication
MongoDB change streams read from replication history, so they work on replica sets and sharded clusters. A standalone server has no oplog-backed stream to follow.
For local development, a single-node replica set is enough. Connect to it, then open a collection stream through the driver's watch() method:
const stream = db.collection("orders").watch([
{
$match: {
operationType: { $in: ["insert", "update", "replace", "delete"] }
}
}
]);
for await (const event of stream) {
console.log(event);
}
MongoDB's change stream documentation covers collection, database, and deployment scope plus topology requirements. Filter as early as possible so the server does not deliver event types your consumer will immediately discard.
The event type determines what you receive
An insert event can include the inserted document. A replacement event identifies the replacement and can include its full value. A delete event carries the document key, not the deleted document. Unless pre-images are separately configured, the old document is gone from the stream by the time you ask where it went.
An update event normally carries an updateDescription:
{
"operationType": "update",
"documentKey": { "_id": "..." },
"updateDescription": {
"updatedFields": { "status": "shipped" },
"removedFields": [],
"truncatedArrays": []
}
}
That delta is usually enough to answer "what field changed." It is smaller and cheaper than fetching the full document for every update.
The MongoDB update-event reference defines the fields and version-specific additions. Keep consumers tolerant of fields they do not understand. Server upgrades are a poor time to discover that an exhaustive switch statement considered new metadata a personal attack.
updateLookup is explicit because it costs a read
Set fullDocument: "updateLookup" when you need the current document after an update:
const stream = db.collection("orders").watch([], {
fullDocument: "updateLookup"
});
This performs an additional lookup. The document is the latest majority-committed version available when MongoDB processes the event. If another update happened in between, the full document may already include that later state.
That distinction matters. The delta belongs to one event. The looked-up document is a current snapshot.
Leave lookup off for event routing, field-change debugging, and high-volume streams where the delta is enough. Enable it deliberately when the current state is the thing you need to inspect.
Resume tokens separate a monitor from a consumer
Every change event has an _id value that acts as its resume token. A durable consumer persists progress after processing and uses a supported resume option after restart. It also owns retry policy, idempotency, token retention, invalidation, and the case where the required history has fallen out of the oplog.
The $changeStream stage reference documents resumeAfter, startAfter, and startAtOperationTime. It also notes that streams opened through driver watch() have resumability behavior that a raw aggregation cursor does not provide in the same way.
A debugging monitor does not need that contract. In fact, pretending it has one is worse than being explicit that it does not. If you close the window and miss ten events, the correct result is "the monitor was closed," not a cheerful gap in a table.
Bound the UI before traffic bounds it for you
Change streams can be quiet for hours and then burst. A GUI should cap retained events, omit oversized value payloads, and expose a dropped-event count. Rendering every event forever is a memory leak with charts.
The same applies to lifecycle:
- Stop should close the driver cursor, not only stop painting rows.
- Navigation and disconnect should close the stream.
- Window destruction should close it even if React cleanup never finishes.
- An invalidate event should end the monitor and require a fresh stream.
- Unexpected completion should report ended, not listening.
Do not persist full events by default. They can contain production values, and a local debugger should not quietly become a second event archive.
mongoui keeps the monitor ephemeral
Open Tools, then Change stream monitor. Select a collection and the insert, update, replace, or delete event types you need. Current-document lookup for updates is explicit and off by default.
mongoui keeps the newest 200 events in renderer memory. Older visible events are dropped with a counter. Oversized value-bearing payloads are omitted. Events and resume tokens are never persisted. Stop, navigation, disconnect, and window closure close the underlying stream.
The Change Stream Monitor guide covers the exact controls and topology behavior. The features page places it alongside profiler history, guarded writes, and environment comparison. For query-side diagnosis after an event reveals an expensive operation, use the slow-query profiler workflow.
Use the smallest tool that matches the guarantee
Use an ephemeral monitor when you are debugging live behavior and can tolerate events that occur while it is closed. Use an application-owned durable consumer when every event must be processed, retried, audited, or replayed.
That line is the whole design decision. A change stream makes live database activity available. Your retention and recovery contract decides whether you built a debugger or infrastructure.
The monitor should be easy to start and equally easy to stop. The production consumer should be considerably more boring, which is how you know somebody thought about it.
