npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

rightsize

v0.7.0

Published

Testcontainers-style integration testing on microsandbox microVMs, with a Docker fallback and an await-using lifecycle. No Docker required.

Readme

rightsize

CI

Testcontainers-style integration testing on microVMs. No Docker required.

rightsize runs your integration-test containers as hardware-isolated microsandbox microVMs - one microVM per container - behind a strict-mode ESM TypeScript API whose flagship lifecycle is TC39 explicit resource management. The runtime self-provisions on first use (no install step), and a hand-rolled Docker backend covers the platforms microVMs can't reach.

import "rightsize/backend-msb";
import "rightsize/backend-docker";
import { RedisContainer } from "rightsize/modules";

async function main(): Promise<void> {
  await using redis = await RedisContainer.start(); // boots a real microVM
  console.log("redis is up at", redis.uri); // redis://127.0.0.1:<mapped port>
  // ... your test ...
}

await main();

await using is the whole story: redis is disposed automatically at the end of its scope - stopped, removed, its port freed - ordered and awaited, the same way a try/finally would, with none of the boilerplate.

Why microVMs

| | Docker + Testcontainers | rightsize | |---|---|---| | Isolation | shared kernel (containers) | hardware-level (microVM per container) | | Runtime install | Docker Desktop / daemon required | none — self-provisions on first use | | Licensing | Docker Desktop licensing in orgs | Apache-2.0 all the way down | | Lifecycle | manual try/finally | await using explicit resource management | | Docker client | a general-purpose SDK over a shared HTTP stack | hand-rolled, unix-socket-only — can't be misrouted onto TCP |

The lifecycle and Docker-client rows above aren't incidental implementation choices - see Lifecycle and Backends for why each one is the way it is. (If you've used Testcontainers, the builder shape - withEnv, withExposedPorts, waitingFor, getMappedPort

  • will feel familiar; the lifecycle is where this library departs from it most.)

Quickstart

npm install --save-dev rightsize

Importing a backend subpath registers it as a side effect - import whichever one(s) you want considered, and rightsize picks the best supported one automatically (or RIGHTSIZE_BACKEND forces a specific one):

import "rightsize/backend-msb";
import "rightsize/backend-docker";

Drive any image directly with GenericContainer, or use one of twenty-three preconfigured modules:

import { GenericContainer, Wait } from "rightsize";

await using arango = await new GenericContainer("arangodb:3.11")
  .withEnv("ARANGO_NO_AUTH", "1")
  .withExposedPorts(8529)
  .waitingFor(Wait.forHttp("/_api/version").forPort(8529))
  .start();

const port = arango.getMappedPort(8529); // published on 127.0.0.1

Full guide: Quickstart.

Modules

Preconfigured containers with sensible waits and connection helpers. Each is a GenericContainer subclass, so the fluent builders (withEnv, withExposedPorts, waitingFor, …) are available on every one.

| Module | Helpers | |---|---| | RedisContainer | uri | | ValkeyContainer | uri (redis:// scheme — Valkey speaks the Redis wire protocol) | | MemcachedContainer | address | | ArangoContainer | endpoint; withRootPassword(...) to enable auth (default: no-auth) | | MongoDBContainer | connectionString, replicaSetUrl (alias) — single-node replica set, auto-initiated | | PostgresContainer | connectionString, username, password, databaseName; withUsername/withPassword/withDatabase(...) | | MySQLContainer | connectionString, username, password, databaseName; withUsername/withPassword/withDatabase(...) | | MariaDBContainer | connectionString, username, password, databaseName; withUsername/withPassword/withDatabase(...) | | RedpandaContainer | bootstrapServers, schemaRegistryUrl | | KafkaContainer | bootstrapServers — KRaft single node | | RabbitMQContainer | amqpUrl, managementUrl, username, password; withUsername/withPassword(...) — management plugin enabled | | PinotContainer | controllerUrl, brokerUrl — single-container QuickStart cluster | | SpringCloudConfigContainer | uri | | WireMockContainer | baseUrl, adminUrl — stub via the /__admin API | | KeycloakContainer | authServerUrl, adminUsername, adminPassword; withAdminUsername/withAdminPassword(...) | | ClickHouseContainer | httpUrl, username, password, databaseName; withUsername/withPassword/withDatabase(...) | | Neo4jContainer | httpUrl, boltUrl, username, password; withPassword(...) — HTTP Cypher endpoint (username fixed at neo4j) | | FlociContainer | FlociContainer.aws()/.azure()/.gcp() factories, endpointUrlfloci.io cloud emulators (unsigned REST, no SDK needed) | | FlinkContainer | restUrl; withTaskManager() for a full session cluster — Docker only¹ | | MinIOContainer | endpointUrl, rootUser, rootPassword; withRootUser/withRootPassword(...) — S3-compatible object store | | CassandraContainer | contactPoint, cqlPort, localDatacenter | | ElasticsearchContainer | restUrl — no no-arg constructor, Elastic publishes no floating tag; an explicit image is required | | QdrantContainer | restUrl — vector search engine |

Some modules raise a memory floor for their image (withMemoryLimit): heavyweight JVM images - Spring Cloud Config, Keycloak, Neo4j, Flink (1024 MB), Cassandra and Elasticsearch (2560 MB each) - and Pinot's multi-JVM QuickStart cluster (4096 MB) - need more than the microVM default. That's baked into the module; you don't set it.

Every module here also accepts a DockerImageName in place of a plain string, and checks the supplied image's repository against the one it declares — a mismatch throws IncompatibleImageError before any backend call, with an asCompatibleSubstituteFor(...) escape hatch for a verified compatible fork or mirror. See Image compatibility.

Every module's page under docs/modules/ documents its exact image tag, wait strategy, and the measured reasoning behind these choices.

¹ withTaskManager() throws UnsupportedByBackendError on microsandbox (the Flink image carries no nc/busybox for network-link emulation - see Networking); a bare JobManager still runs on microsandbox. Run TaskManager topologies under RIGHTSIZE_BACKEND=docker.

Backends

rightsize picks a backend automatically; override with RIGHTSIZE_BACKEND=microsandbox|docker.

| Platform | Backend used | |---|---| | macOS (Apple Silicon) | microsandbox (microVMs) | | Linux x86_64 / arm64 with /dev/kvm | microsandbox (microVMs) | | Windows x86_64 / arm64 (WHP enabled) | microsandbox (microVMs)¹ | | Intel Mac | Docker (auto-fallback) | | Windows without WHP | Docker (auto-fallback) | | Linux without KVM | Docker (auto-fallback) |

¹ Verified in CI on windows-2025 hosted runners, where Windows Hypervisor Platform is enabled by default. If WHP isn't enabled on your machine, run msb doctor --fix in an elevated terminal (may require a reboot) or use RIGHTSIZE_BACKEND=docker.

Both backends satisfy one behavioral contract, verified by a shared test suite - the code you write runs unchanged on either. A few edges are backend-specific rather than behavioral divergences:

  • Network-alias tunnels on microsandbox have real limits versus Docker's native bridge networking - see Networking.
  • followOutput delivers the same ordered, no-duplicate log stream on both backends, but on microsandbox the final tail can arrive shortly after the sandbox reports stopped, rather than exactly at stream EOF (msb logs -f doesn't close on sandbox stop in 0.6.8, so the backend replays the not-yet-delivered tail once stop is confirmed).

How it works

  • Self-provisioning runtime. A pinned msb release (binary + libkrunfw) is downloaded once, SHA-256-verified against the release manifest, and installed atomically under ~/.cache/rightsize/ (%LOCALAPPDATA%\rightsize on Windows) - the binary lands last, so a crashed install is detected and repaired, never half-trusted. A cross-process file lock keeps parallel processes from racing.
  • Attached-mode supervision. Each container is a held child process supervising its microVM; the image's ENTRYPOINT runs exactly as it would under Docker.
  • Pre-allocated ports. Host ports are chosen before boot, so brokers like Redpanda/Kafka get their advertised listeners baked in - no restart dance. A backend binds the ports it's given; it never allocates its own.
  • Two-tier cleanup, no async Drop. The happy path is await using or an explicit, awaited stop(). The fallback - a process that exits before either runs - falls back to a synchronous, blocking teardown registered per container (Node's "exit" handler can't await), with a ledger-based orphan reaper (sweep + optional watchdog) as the backstop for a hard SIGKILL that bypasses even that. See Orphan reaping.
  • Container reuse. .withReuse() plus the double opt-in RIGHTSIZE_REUSE adopts an already-running sandbox from a prior process instead of booting a fresh one, keyed by a content hash of the reuse-relevant spec - a local-dev-loop speedup, not a CI default. See Container reuse.
  • Failure diagnostics. diagnostics() renders every currently-running container's image, mapped ports, and a bounded log tail into one human-readable report, wireable into a test framework's own failure hook. See Failure diagnostics.
  • Isolation on demand. .withRequireIsolation() fails a start() fast, before any boot work, if the active backend can't provide hardware-virtualized isolation - for workloads that shouldn't silently degrade to a shared-kernel fallback. See Isolation.
  • Resource and network controls, msb-only. .withDiskLimit(mb) caps the writable root disk, .withTmpfsRoot(mb) backs it with RAM instead, and .withNetworkDisabled() blocks public-internet egress while published ports keep serving - docker ignores all three. See Isolation and Networking.
  • Checkpoint / restore. checkpoint() captures a running container's filesystem (image commit on docker, disk snapshot on microsandbox); fromCheckpoint() boots fresh containers from it - skip repeated boot-and-seed work across a suite. Pass a name - checkpoint("name") - to make it durable and rediscoverable across runs via Checkpoints.find/ list/remove, registered under the rightsize cache dir. Checkpoints.exportTo/ importFrom bundle a checkpoint into a portable archive for moving it between machines and CI caches. See Checkpoint / restore.
  • Runtime file copy. copyFileToContainer / copyContentToContainer / copyFileFromContainer move files and directories into or out of an already-running container, on both backends, with destination parent directories created automatically. See Copying files.
  • One interface, two backends. SandboxBackend is a small interface; the shared contract suite is the referee, with the Docker backend doubling as the correctness oracle for the microVM backend - and the same interface behavior is a cross-language contract, verified against the Kotlin and Rust implementations too. See Cross-language parity.

Full detail: How It Works.

Configuration

| Env var | Effect | |---|---| | RIGHTSIZE_BACKEND | Force microsandbox or docker | | MSB_PATH | Use a pre-installed msb binary; skip downloads | | RIGHTSIZE_CACHE_DIR | Relocate the runtime cache (default ~/.cache/rightsize; %LOCALAPPDATA%\rightsize on Windows) | | RIGHTSIZE_MSB_SKIP_DOWNLOAD | true = fail instead of downloading (air-gapped CI) | | RIGHTSIZE_REAPER | on (default) / sweep / off — see Orphan reaping | | RIGHTSIZE_REUSE | true or 1 — second half of reuse's double opt-in — see Container reuse |

Runtime support

| Runtime | Minimum | |---|---| | Node.js | >=22.11 (the 22.x "Jod" LTS line) | | Bun | >=1.1 |

Authored in TypeScript using await using; tsc emits ES2022 plus the downlevelled explicit-resource-management helpers, so the shipped dist/**.js runs unmodified on both runtimes with no flags.

Examples

Three self-contained, runnable examples live under examples/. Each builds the library once, then runs directly against the compiled dist/ - no separate example-specific setup beyond npm install.

| Example | What it shows | Run | |---|---|---| | redis-quickstart.ts | The await using lifecycle — the library's signature | npm run example:redis | | network-alias.ts | Two containers on one Network, reachable by alias | npm run example:network | | redis.test.ts | A node:test suite using a module container, gated behind RIGHTSIZE_IT=1 the same way this repo's own integration tests are | npm run example:test |

Run all three back to back with npm run examples:run. Every example picks a backend automatically; force one explicitly the same way you'd for any rightsize program:

RIGHTSIZE_BACKEND=docker npm run example:redis
RIGHTSIZE_BACKEND=microsandbox npm run example:redis

redis.test.ts skips its container-backed assertions unless RIGHTSIZE_IT=1 is set, so npm run example:test is safe to run on a machine with no container runtime - pass the flag to actually exercise it: RIGHTSIZE_IT=1 npm run example:test.

Documentation

Full documentation (guide, backends, module reference) is at ngriaznov.github.io/rightsize-node, built from docs/ by VitePress.

Development

npm install                                                # installs dependencies
npm run build                                              # compiles src/ to dist/
npm run typecheck                                          # tsc --noEmit
npm test                                                    # unit suite, both runtimes
npm run coverage:core                                       # core coverage, 80% line floor
RIGHTSIZE_BACKEND=microsandbox npm run test:node:it         # needs Apple Silicon or Linux+KVM
RIGHTSIZE_BACKEND=docker npm run test:node:it               # needs a reachable Docker daemon
npm run docs:build                                          # static docs site
npm run docs:verify                                         # typechecks every doc/README sample

CI runs the matrix on Linux (KVM), macOS (Apple Silicon), and a Docker-only job, both Node and Bun.

See CONTRIBUTING.md for what each tsconfig*.json is for, the full npm script reference, and integration-test conventions.

License

Apache-2.0