Guides
Modes
One property decides what your tests run against. Everything else, including the annotation, seeding, cleanup, await helpers, and assertions, is the same either way. That is the entire point.
Embedded: the default
In embedded mode the harness opens the in-process store, registers the shim MongoClient as the sharedMongoTestClient bean, rewires any MongoClient or MongoDatabaseFactory beans the application declares itself, and neutralises spring.mongodb.uri, spring.mongodb.host and spring.mongodb.port so nothing in the context can dial a real server by accident.
# The default. Setting it explicitly is only ever documentation.
bonsai.mode=embeddedThe published URI is always the deterministic neutral value mongodb://localhost:1/<database>. Nothing listens on it: it exists only so configuration that reads the property keeps working. The initializer also publishes bonsai.active=true, which is the reliable way for test configuration to ask whether the harness is in play.
This is the mode the rest of the documentation assumes. It needs no Docker, no downloaded binary and no external process, and it is what makes the suite start in milliseconds. See How it works for what happens underneath.
Passthrough: a real server
Passthrough points the same unchanged test suite at a real MongoDB server. Two properties, no code changes:
# CI profile "mongo-verify": same tests, real MongoDB, zero code changes
bonsai.mode=passthrough
bonsai.passthrough.uri=${MONGO_VERIFY_URI}bonsai.passthrough.uri is required in this mode, and the failure is raised while the settings are read, before any client is created:
java.lang.IllegalStateException: bonsai.mode=passthrough requires
bonsai.passthrough.uri to be set to a real MongoDB connection URIIn embedded mode a passthrough URI is ignored, with a WARN saying so, rather than quietly changing behaviour. Any value of mode other than embedded or passthrough fails fast naming both.
What still works against the real server: the annotation lifecycle, declared schema, @MongoSeed and every fixture format, per-method cleanup, the await helpers and the whole assertion surface. Those features only ever talk to com.mongodb.client interfaces, so they are backend-neutral by construction. What changes: no bean overrides and no shim registration. Spring Boot builds its own real MongoClient from the published URI. The full contract is on the Passthrough mode page.
Durability: a debug store
Embedded mode keeps everything in memory, which is usually what you want and occasionally exactly what you do not: when a test fails on data you would like to open and look at, an in-memory store has already evaporated. Setting a durability directory makes the embedded store file-backed instead.
# Keep the store on disk so you can open it after the run …
bonsai.durability.directory=target/mongo-debug
# … and stop the harness from dropping everything between methods
bonsai.cleanup=noneDurability affects storage only. Cleanup is unchanged, so the default drop-databases will still empty the file between test methods. Persisting state across a run, or across runs, additionally requires bonsai.cleanup=none. The directory is created if it does not exist, and the store file is written inside it.
The generic JUnit harness reads the same switch as a system property, since it has no Spring environment to read from:
mvn test -Dbonsai.durability.directory=target/mongo-debugProperties
All of these are read once, when the application context is initialised. See Configuration for the rest of the bonsai.* set.
| Property | Default | Description |
|---|---|---|
bonsai.modeString | embedded | embedded runs the in-process shim; passthrough runs the same suite against the server named by bonsai.passthrough.uri. Any other value fails fast naming both. |
bonsai.passthrough.uriString | — | The real MongoDB connection URI. Required when mode=passthrough: missing, it fails before a client is created. Ignored with a WARN when mode=embedded. |
bonsai.durability.directoryString | — | Directory for the optional file-backed debug store. Embedded mode only. Affects storage only. Persisting across runs additionally requires cleanup=none. |
bonsai.cleanupString | drop-databases | drop-databases, clear or none. Applies in both modes; in passthrough it drops databases on the real server. |
bonsai.durability.directorySystem property | — | The same durability switch for the generic JUnit harness, which has no Spring environment to read. The Spring property sets it for you. |
Footnote: reference backends
One more selector exists, and it is worth naming so it is not mistaken for a third mode: BONSAI_REFERENCE_BACKEND. It configures nothing in your suite. It chooses which real MongoDB this library's own differential and performance lanes compare themselves against.
# Auto-detected: Docker present selects Testcontainers, otherwise flapdoodle.
BONSAI_REFERENCE_BACKEND=testcontainers mvn -q -pl evaluation -am verify
BONSAI_REFERENCE_BACKEND=flapdoodle mvn -q -pl evaluation -am verifyTestcontainers is the primary reference backend wherever a Docker-compatible runtime exists; a flapdoodle-launched mongod is the fallback for Docker-less machines. Selection is auto-detected, an explicit value skips the Docker probe entirely so a Docker-less machine fails loudly instead of being silently downgraded, and an unrecognised value is a hard error listing the valid ones.
The distinction is the whole point of this page. Modes are a consumer concern: which backend your tests execute against. Reference backends are a maintainer concern: which real server the library proves itself against before you ever see a release. What that proving covers is listed on Supported operations; the way to reach the same confidence about your own codebase is the first.