Bun-first libraries for building servers: an Express-like HTTP layer for
Bun.serve, a NestJS adapter built on it, and background jobs and queues.
- What this repository is
- Packages
- Examples
- Requirements
- Installation
- Development
- Repository layout
- Contributing
- License
A monorepo of eight published packages, managed with Bun workspaces, lerna and
nx, released together at one version (lerna's fixed mode). Each package ships
its TypeScript source, which Bun runs as it is (main is lib/index.ts),
and declarations built into dts/ when it is packed. Each has its own tests
(bun:test), bun check typecheck, and bun lint and bun fmt from the
root bunfig.toml. The packages
prefer Bun and native APIs over third-party dependencies.
| Package | npm | Description |
|---|---|---|
| bun-common | @kingsleyweb/bun-common |
An Express-like HTTP layer for Bun.serve: BunRouter with Express 5 semantics, BunRequest, BunResponse, BunHttpAdapter, validation with any Standard Schema, CORS, static files, compression, multipart uploads, WebSockets and structured logging. |
| bun-contract | @kingsleyweb/bun-contract |
bun-common's transport-agnostic contract core on its own: transports, contracts over any Standard Schema, guards, contract descriptions and channel contracts, with no dependency and safe in a browser. bun-common re-exports it as @kingsleyweb/bun-common/contract. |
| bun-nest | @kingsleyweb/bun-nest |
Run NestJS 11 or 12 on Bun: BunHttpAdapter in place of @nestjs/platform-express, multer-style file upload interceptors, and BunWebSocketAdapter for gateways over Bun's native WebSockets. |
| bun-jobs | @kingsleyweb/bun-jobs |
Background work for Bun: BunRunner runs a JS/TS file on a schedule or on demand (child process, Worker or in-process), and BunQueue / BunQueueWorker process jobs across processes and services over memory, file, Redis, SQL and MongoDB drivers. |
| bun-client | @kingsleyweb/bun-client |
A typed HTTP client for these servers, with no dependency and safe in a browser: one call per verb keyed by the server's own path literal, named operations, results discriminated by status, retries with Retry-After, timeouts, middleware and single-flight auth refresh; ./query puts the routes on TanStack's query-core (an optional peer) with cache tags, ETag revalidation and optimistic updates. |
| bun-cache | @kingsleyweb/bun-cache |
Caching over pluggable drivers: one typed API (TTLs, tags, single-flight, stale-while-revalidate, counters, an L1 memory tier kept coherent by a bus) over memory, file, SQLite, Postgres, MySQL, MariaDB, Redis, MongoDB, S3, Azure Blob Storage and Cloudflare drivers, an HTTP response cache for bun-common and a Keyv store. |
| bun-ui | @kingsleyweb/bun-ui |
Every browser UI of the repo in one package, one subpath each: @kingsleyweb/bun-ui/jobs is the React management UI for bun-jobs' management API, served by a jobsUi() router that mounts beside createJobsApi (bun-jobs is an optional peer only that subpath needs); @kingsleyweb/bun-ui/docs is a self-hosted viewer for one OpenAPI 3.1 or AsyncAPI 3.0 document, served by a docsUi() handler under a strict self-only CSP. |
bun-nest, bun-jobs, bun-cache and bun-ui depend on bun-common, which depends on bun-contract; bun-client depends on bun-contract alone.
Runnable, commented examples live in examples/, one
project per package. Each example is a single script you run with bun.
| Project | Covers |
|---|---|
examples/bun-common |
Routing, the HTTP adapter, requests and responses, validation, CORS, static files, compression, multipart uploads, WebSockets, logging and utilities, plus option tours |
examples/bun-nest |
NestJS on Bun: the HTTP adapter, file upload interceptors and the WebSocket adapter, plus option tours |
examples/bun-jobs |
Queues, workers, the job registry, scheduling, flow control, failures, the runner, every driver and integrations, plus option tours |
examples/bun-ui |
bun-ui, a folder per UI; jobs/: the management UI beside the management API: mounting, the shell and bundle with their security headers, a cross-origin API, plus an option tour |
bun install # at the repo root
cd examples/bun-nest
bun run-all.ts # every example in the project; prints ok / skip / FAILexamples/README.md describes the conventions every
example follows.
- Bun ≥ 1.4.2 to use the packages. Every package declares it in
engines.bun. bun-jobs' Redis and SQL drivers use APIs that 1.4.2 is the firstbun-typesrelease to declare. @types/bun≥ 1.4.2, an optional peer of every package.- Bun ≥ 1.4.3 to develop the repository, the first stable release with
bun check, which runs every type check here. The rootpackage.jsondeclares it inengines.bunand pinsbun@1.4.3as its package manager. - NestJS 11.1.20 or later, or NestJS 12 (
@nestjs/common,@nestjs/core,rxjs;@nestjs/websocketsfor gateways) for bun-nest.
Use Bun to install the packages you need:
bun add @kingsleyweb/bun-common
bun add @kingsleyweb/bun-nest @nestjs/common @nestjs/core rxjs reflect-metadata
bun add @kingsleyweb/bun-jobs3.0.0-rc.0, the release candidate, is on npm's next tag, all eight
packages at one version. Until 3.0.0 reaches latest, a plain bun add @kingsleyweb/bun-common (or bun-nest) installs 2.2.0, so ask for the tag:
bun add @kingsleyweb/bun-common@next
bun add @kingsleyweb/bun-nest@next @nestjs/common @nestjs/core rxjs reflect-metadata
bun add @kingsleyweb/bun-jobs@nextdocs/releasing.md is how a release is cut: the
version bump and its CHANGELOG.md entry in a PR, then npm login,
bun scripts/publish.ts --dry-run and bun scripts/publish.ts (one
one-time code for every package; it tags the commit and creates the GitHub
release at the end).
git clone https://github.com/kingsloob1/bun-node.git
cd bun-node
bun installbun scripts/typecheck.ts # every project in the repo; must be clean
bun scripts/typecheck.ts --list # just name themscripts/typecheck.ts checks every tsconfig.json in the repository with
bun check (bun run check at the root runs it too): the packages, their
nested bench and playground projects, benchmarks/ and the example projects.
They all extend tsconfig.base.json, so a file is checked the same way
wherever it is checked from. Run it rather than bun run check in a single
package.
Then, in each affected package directory:
bun run check # bun check on the package's projects
bun run lint # bun lint over the whole package; 0 errors
bun run format:check # bun fmt --check; clean (bun run format formats)
bun run test # type-checks the tests, then runs them; every test must passAfter changing bun-common, run bun-nest's and bun-jobs' checks too.
bun-common's typed route overloads, which bun-nest carries too, are generated:
cd packages/bun-common
bun scripts/generate-verb-overloads.ts # rewrite both packages
bun scripts/generate-verb-overloads.ts --check # fail if stalebun-jobs' integration suites need Redis, Postgres, MariaDB, MySQL and MongoDB.
They skip visibly when their URL is unset. scripts/setup-databases.ts
provides the servers. It never reinstalls an existing server, configures one
only when a connection with the expected credentials fails, and never drops or
resets anything.
bun scripts/setup-databases.ts # system packages
bun scripts/setup-databases.ts --docker # containers instead
bun scripts/setup-databases.ts --dry-run # print the plan, change nothing
bun scripts/setup-databases.ts --only=mongodb # one server
bun scripts/setup-databases.ts --print-env # the env vars for the suitesThe benchmark projects are separate, unpublished packages with their own
package.json and node_modules, so third-party comparators never reach a
published package's dependency tree.
| Project | Measures |
|---|---|
benchmarks/ |
BunRouter throughput against Express 5, Bun.serve routes, Elysia and Hono |
packages/bun-jobs/bench/ |
BunQueue against BullMQ, bee-queue, node-resque, pg-boss, graphile-worker and Agenda; BunRunner against Bree, Agenda and cron timers |
packages/bun-common/bench/ |
parseXmlToObject against fast-xml-parser, htmlparser2 and HTMLRewriter |
Install a project's comparators inside its own directory before running or type-checking it:
(cd benchmarks && bun install)
(cd packages/bun-jobs/bench && bun install)
(cd packages/bun-common/bench && bun install)The bun-jobs benchmarks double as a regression guard:
cd packages/bun-jobs/bench
bun install
bun queue.ts --compare # fails if a figure regressed or a rival overtook
bun runner.ts --compare
bun queue.ts --save-baseline # re-record after a deliberate changebun-node/
├── packages/
│ ├── bun-common/ # HTTP layer: lib/, __tests__/, bench/, playground/, scripts/
│ ├── bun-contract/ # the contract core, no dependency: lib/, __tests__/
│ ├── bun-nest/ # NestJS adapter: lib/, __tests__/
│ ├── bun-jobs/ # jobs and queues: lib/, __tests__/, bench/ (its own package)
│ └── bun-client/ # the typed HTTP client, no dependency: lib/, __tests__/
├── examples/
│ ├── bun-common/ # one runnable project per package
│ ├── bun-nest/
│ ├── bun-jobs/
│ └── bun-ui/ # jobs/, a folder per UI
├── benchmarks/ # router benchmarks (its own package)
├── scripts/
│ ├── typecheck.ts # type-checks every project
│ └── setup-databases.ts # provisions the database servers for the tests
├── tsconfig.base.json # compiler options every tsconfig.json extends
├── tsconfig.json
├── lerna.json
├── nx.json
└── package.json # Bun workspaces for the three packages
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
Please make sure to update tests as appropriate, and keep typecheck, lint and tests clean.