@jongodb/memory-server
v0.1.6
Published
Node.js test runtime adapter for jongodb standalone launcher (MongoDB-compatible integration tests).
Downloads
2,518
Maintainers
Readme
@jongodb/memory-server
Node test runtime adapter for jongodb.
It starts a local jongodb launcher process, provides a MongoDB URI, and manages lifecycle for test runners.
Why This Package Exists
mongodb-memory-server is useful, but it still depends on mongod bootstrap behavior.
@jongodb/memory-server focuses on a different tradeoff:
- faster integration-test startup loops
- deterministic local process lifecycle control
- simple test runner integration (Jest, Vitest, Nest Jest)
This package is for test runtime usage only. It is not a production MongoDB server.
Value for Integration Test Suites
Observed benchmark summary on one NestJS integration suite shape:
- historical suite-scoped lifecycle: about
55.9%faster thanmongodb-memory-server - current single-boot lifecycle: about
64.2%faster thanmongodb-memory-server
Actual deltas vary by test shape, dataset size, and CI machine characteristics.
Scope
- integration-test runtime helper
- launcher process start/stop/detach lifecycle
- framework-agnostic runtime API
- convenience hooks for Jest, Vitest, and Nest Jest
Requirements
- Node.js 20+
CI Coverage
Node adapter compatibility smoke runs in CI across:
- OS:
ubuntu-latest,macos-latest - Node:
20,22
Cold-start performance gate:
- workflow:
.github/workflows/node-cold-start-benchmark.yml - benchmark docs:
docs/NODE_COLD_START_BENCHMARK.md
Versioning Policy
SemVer/compatibility policy for Node adapter releases:
Install
npm i -D @jongodb/memory-serverCanary channel:
npm i -D @jongodb/memory-server@canaryModule Format
This package supports both:
- ESM (
import) - CommonJS (
require)
Dual-export contract coverage:
- test suite runs both
scripts/esm-smoke.mjsandscripts/cjs-smoke.cjsto guard import/require entrypoint parity.
Quick Start
Recommended pattern: one runtime per test process.
import { beforeAll, afterAll } from "@jest/globals";
import { createJongodbEnvRuntime } from "@jongodb/memory-server/runtime";
const runtime = createJongodbEnvRuntime({
databaseName: "test",
databaseNameStrategy: "worker",
envVarNames: ["MONGODB_URI", "DATABASE_URL"],
});
beforeAll(async () => {
await runtime.setup();
});
afterAll(async () => {
await runtime.teardown();
});Runtime behavior:
setup()starts launcher and writes URI to configured env key(s)teardown()stops launcher and restores previous env values- overlapping runtimes that share env keys now restore without clobbering each other
CommonJS example:
const { createJongodbEnvRuntime } = require("@jongodb/memory-server/runtime");
const runtime = createJongodbEnvRuntime({ databaseName: "test" });Migration from mongodb-memory-server
Full migration guide:
Basic Jest migration:
Before:
import { MongoMemoryServer } from "mongodb-memory-server";
let mongod: MongoMemoryServer;
beforeAll(async () => {
mongod = await MongoMemoryServer.create();
process.env.MONGODB_URI = mongod.getUri();
});
afterAll(async () => {
await mongod.stop();
});After:
import { beforeAll, afterAll } from "@jest/globals";
import { createJongodbEnvRuntime } from "@jongodb/memory-server/runtime";
const runtime = createJongodbEnvRuntime({ databaseName: "test" });
beforeAll(async () => {
await runtime.setup();
});
afterAll(async () => {
await runtime.teardown();
});Option mapping:
MongoMemoryServer.create({ instance: { port } })->createJongodbEnvRuntime({ port })MongoMemoryServer.create({ instance: { dbName } })->createJongodbEnvRuntime({ databaseName })mongod.getUri()->runtime.uri(aftersetup) or configured env varmongod.stop()->runtime.teardown()
Parallel test tip:
- set
databaseNameStrategy: "worker"to isolate worker data by database name
Runner Integrations
Jest (per-file hooks):
import { beforeAll, afterAll } from "@jest/globals";
import { registerJongodbForJest } from "@jongodb/memory-server/jest";
registerJongodbForJest({ beforeAll, afterAll });Jest (global setup/teardown):
jest.global-setup.ts
import { createJestGlobalSetup } from "@jongodb/memory-server/jest";
export default createJestGlobalSetup();jest.global-teardown.ts
import { createJestGlobalTeardown } from "@jongodb/memory-server/jest";
export default createJestGlobalTeardown();Global setup/teardown stabilization notes:
- repeated global setup calls with the same state file now reuse the existing detached launcher (idempotent)
- stale state files (PID no longer alive) are auto-healed by starting a fresh launcher
Vitest:
import { beforeAll, afterAll } from "vitest";
import { registerJongodbForVitest } from "@jongodb/memory-server/vitest";
registerJongodbForVitest({ beforeAll, afterAll });Vitest workspace (project isolation):
import { beforeAll, afterAll } from "vitest";
import { registerJongodbForVitestWorkspace } from "@jongodb/memory-server/vitest";
registerJongodbForVitestWorkspace({ beforeAll, afterAll }, {
projectName: "catalog-api",
isolationMode: "project",
databaseName: "test",
});Workspace helper behavior:
isolationMode: "project"(default): appends project token to database name and writes project-scoped URI env keyisolationMode: "shared": keeps provided database name without project suffix
NestJS (Jest E2E):
import { beforeAll, afterAll } from "@jest/globals";
import { registerJongodbForNestJest } from "@jongodb/memory-server/nestjs";
registerJongodbForNestJest({ beforeAll, afterAll });Nest adapter defaults:
- binds both
MONGODB_URIandDATABASE_URLunless env keys are explicitly overridden - defaults to
databaseNameStrategy: "worker"for Jest parallel isolation
Common patterns:
- NestJS + Mongoose: use
process.env.MONGODB_URIinforRootAsync - Mongoose transaction/session tests: run
startSession/withTransactionagainst runtime URI in integration suites - Prisma (Mongo): set runtime
envVarNamesto includeDATABASE_URLor inject URI viaPrismaClientdatasource override - TypeORM (Mongo): pass runtime URI into
urland validateMongoRepositoryCRUD in smoke suites - Express: inject
process.env.MONGODB_URIinto a shared MongoClient bootstrap and keep app routes DB-agnostic - Koa: inject
process.env.MONGODB_URIinto app context/bootstrap and keep middleware layers DB-agnostic
Runtime Resolution
launchMode values:
auto(default): binary first, Java fallbackbinary: binary onlyjava: Java only
Port collision retry (fixed port > 0):
- when launcher failures include port-in-use signatures, runtime retries on the next port number
- defaults:
portRetryAttempts=3,portRetryBackoffMs=100(linear backoff by retry index)
Binary resolution order:
options.binaryPathJONGODB_BINARY_PATH- bundled platform binary package
Binary integrity verification:
- bundled platform binary packages are verified against embedded
jongodb.sha256metadata before launch - explicit binary paths can opt into verification with
binaryChecksumorJONGODB_BINARY_CHECKSUM
Bundled targets:
@jongodb/memory-server-bin-darwin-arm64@jongodb/memory-server-bin-linux-x64-gnu@jongodb/memory-server-bin-win32-x64
Java fallback:
- set
classpathoption orJONGODB_CLASSPATH - if both are missing, classpath auto-discovery probes:
- command:
options.classpathDiscoveryCommand->JONGODB_CLASSPATH_DISCOVERY_CMD-> repo-local Gradle ->gradle - args:
--no-daemon -q printLauncherClasspath - working directory:
options.classpathDiscoveryWorkingDirectory->JONGODB_CLASSPATH_DISCOVERY_CWD->process.cwd() - disable probe:
classpathDiscovery: "off"orJONGODB_CLASSPATH_DISCOVERY=off - probe results are cached under
.jongodb/cachewith default pruning (maxEntries=32,maxBytes=5MiB,ttl=7d)
- command:
Launcher contract:
- stdout ready line:
JONGODB_URI=mongodb://... - optional stderr failure line:
JONGODB_START_FAILURE=... - process stays alive until termination signal
- runtime validates URI topology sync (requested
topologyProfilevs emittedreplicaSetquery)
Troubleshooting
Signature-based troubleshooting playbook:
API Surface
Main export (@jongodb/memory-server):
startJongodbMemoryServer(options?)
Runtime export (@jongodb/memory-server/runtime):
createJongodbEnvRuntime(options?)
Jest export (@jongodb/memory-server/jest):
registerJongodbForJest(hooks, options?)createJestGlobalSetup(options?)createJestGlobalTeardown(options?)readJestGlobalState(options?)readJestGlobalUri(options?)
Nest export (@jongodb/memory-server/nestjs):
registerJongodbForNestJest(hooks, options?)
Vitest export (@jongodb/memory-server/vitest):
registerJongodbForVitest(hooks, options?)registerJongodbForVitestWorkspace(hooks, workspaceOptions)
Options Reference
Core:
launchMode:auto|binary|java(default:auto)binaryPath: binary executable override pathbinaryChecksum: expected SHA-256 checksum for explicit binary verificationclasspath: Java classpath string or string arrayclasspathDiscovery:auto|off(default:auto)classpathDiscoveryCommand: override command used for classpath auto-discovery probeclasspathDiscoveryWorkingDirectory: cwd for classpath auto-discovery probeartifactCacheDir: artifact cache directory for classpath auto-discovery metadata (default:.jongodb/cache)artifactCacheMaxEntries: max cache entries retained after prune (default:32)artifactCacheMaxBytes: max cache size retained after prune (default:5_242_880bytes)artifactCacheTtlMs: cache TTL for entries before expiration prune (default:604_800_000)javaPath: Java executable path (default:java)launcherClass: Java launcher class (default:org.jongodb.server.TcpMongoServerLauncher)topologyProfile:standalone|singleNodeReplicaSet(default:standalone)replicaSetName: replica-set name forsingleNodeReplicaSetprofile (default:jongodb-rs0)databaseName: base DB name (default:test)databaseNameSuffix: suffix appended todatabaseName(example:_ci)databaseNameStrategy:static|worker(default:static)host: bind host (default:127.0.0.1)port: bind port (0means ephemeral)portRetryAttempts: retry count for port-collision failures whenport > 0(default:3)portRetryBackoffMs: base backoff per retry for port collisions (default:100)startupTimeoutMs: startup timeout (default:15000)stopTimeoutMs: stop timeout before forced kill (default:5000)cleanupOnProcessExit: sendSIGTERMto non-detached launcher on parent process exit (default:true)env: extra child process environment variableslogLevel:silent|error|warn|info|debug(default:silent)logFormat:plain|jsonconsole output format (default:plain)onLog: structured runtime log hook (timestamp,level,event,message,attempt,mode,source,port,stream)onStartupTelemetry: optional hook for startup attempt telemetry (attempt,mode,source,startupDurationMs,success,errorMessage)
Runtime helper options:
envVarName: single target env key (default:MONGODB_URI)envVarNames: multiple target env keys (example:["MONGODB_URI", "DATABASE_URL"])envTarget: optional scoped env object (default:process.env)
Replica-set profile example:
const runtime = createJongodbEnvRuntime({
topologyProfile: "singleNodeReplicaSet",
replicaSetName: "rs-test",
});Replica-set contract test coverage:
- URI must include
?replicaSet=<name>whentopologyProfile=singleNodeReplicaSet helloresponse must exposesetName,hosts,primary,isWritablePrimary,topologyVersion
Run Node adapter contract tests:
npm run --workspace @jongodb/memory-server testRun strict API type coverage report:
npm run node:type:reportReport output:
packages/memory-server/reports/type-api-coverage.md
Scoped env example:
const scopedEnv: Record<string, string | undefined> = {};
const runtime = createJongodbEnvRuntime({
envVarName: "MONGODB_URI",
envTarget: scopedEnv,
});Troubleshooting
- runtime startup logs and failure tails apply secret redaction (
<redacted>) for password/token-style values No launcher runtime configured: setbinaryPath/JONGODB_BINARY_PATH/classpath/JONGODB_CLASSPATHBinary launch mode requested but no binary was found: providebinaryPathorJONGODB_BINARY_PATHBinary checksum verification failed: validatebinaryChecksum/JONGODB_BINARY_CHECKSUMand binary file provenanceEADDRINUSE/address already in use: increase baseport, tuneportRetryAttempts, or useport: 0Java launch mode requested but Java classpath is not configured: provideclasspathorJONGODB_CLASSPATHClasspath auto-discovery probe failed: set explicitclasspath/JONGODB_CLASSPATH, or fix Gradle probe command/cwd- stale cache concerns: tune
artifactCache*options or remove.jongodb/cacheto force fresh probe spawn ... ENOENT: missing runtime executable path- startup timeout: launcher did not emit
JONGODB_URI=... Launcher URI topology options are out of sync: emitted URI query does not match requestedtopologyProfile/replicaSetName
Parallel test tip:
- use
databaseNameStrategy: "worker"or per-worker suffixes to prevent data collisions - if multiple runtimes share a Node process, prefer
envTargetfor per-runtime scoped bindings
Security policy reference:
Support/debug bundle:
- generate issue bundle:
npm run node:debug:bundle -- --outputDir build/reports/node-debug-bundle - collector guide:
docs/NODE_DEBUG_BUNDLE.md - preflight doctor:
npm run node:doctor -- --outputDir build/reports/node-doctor - doctor guide:
docs/NODE_DOCTOR.md
