Runtime
The dependency-injection container, module bootstrap, lifecycle hooks and the Context base class.
Build modular, testable backends where controllers express intent, channels own side effects, and brokers carry the transport.
npm install @glandjs/core @glandjs/common @glandjs/events @glandjs/http @glandjs/nodeimport { Controller } from '@glandjs/common'import { Get } from '@glandjs/http'import type { ExpressContext } from '@glandjs/express'import type { EventTypes } from '../shared/events.interface'
@Controller('products')export class ProductController { @Get() async list(ctx: ExpressContext<EventTypes>) { const products = await ctx.call('db:product:all', {}) return ctx.send({ products }) }}Controllers reply. They never touch the database.
import { Channel, On } from '@glandjs/common'import type { Product } from '../shared/events.interface'
@Channel('db')export class Database { private products = new Map<string, Product>()
@On('product:all') async allProducts(): Promise<Product[]> { return Array.from(this.products.values()) }}Channels own side effects, addressed as db:product:all.
import 'reflect-metadata'import { GlandFactory } from '@glandjs/core'import { ExpressBroker } from '@glandjs/express'import { AppModule } from './app.module'
async function bootstrap() { const { app, shutdown } = await GlandFactory.create(AppModule) const http = app.connectTo(ExpressBroker) http.listen(3000) await http.ready()}void bootstrap()Brokers carry the transport. Swap the adapter, keep the app.
Keep domain behavior independent from transport, make side effects explicit, and let small primitives compose into the application you actually need.
Controllers never call business logic. They emit domain events; channels decide what happens next. Side effects become observable and replaceable.
The HTTP layer has no server in it. Express, Fastify, Koa, Hono and node:http each implement the same contract, so the same controller, middleware and assertions produce the same results on all five.
The emitter is three methods and a couple of kilobytes. The broker adds channels, mesh networking and async watchers on top of it. Nothing is hidden.
Event names and payload shapes live in one typed map. A renamed event or a changed payload is a compile error, not a production incident.
Assert the events a controller emitted. Call a channel handler with a fake context. Because side effects live in channels, your suites stay small.
Adding a transport means implementing one abstract adapter. And because a broker is just a class, WebSocket or RPC is the same exercise — there is no big-bang migration.
Every request follows the same path. Each step has a single job, so you always know where a behavior lives and what to replace when it changes.
Receives the context, expresses intent and replies. It performs no side effects.
ctx.call(‘db:product:all’)The contract between the two sides. A renamed event or payload is a compile error.
EventTypesOwns the side effect: persistence, audit logs, notifications. Easy to fake in tests.
@Channel(‘db’)Carries the transport. Swap HTTP for another protocol without touching the domain.
ExpressBrokerThe ecosystem is split by responsibility, so the runtime stays small and your dependency graph stays understandable.
Runtime
The dependency-injection container, module bootstrap, lifecycle hooks and the Context base class.
Decorators
The decorators and metadata keys that make up the DSL: Module, Controller, Channel, On and Inject.
Eventing
The namespaced event broker: channels, mesh networking, request/response calls and async watchers.
Primitive
A zero-dependency, tree-routed event emitter with wildcard matching. Three methods, nothing else.
Protocol
The framework-agnostic HTTP core: route decorators, HttpContext, the middleware onion, HttpCore and the HttpBroker.
Adapter
The Express 5 adapter. Wires Gland controllers and channels to a real HTTP server.
Adapter
The Fastify 5 adapter, with the middleware onion composed into a single real hook.
Adapter
The Koa 3 adapter: a native router, native extended verbs and a real promise onion.
Adapter
The Hono 4 adapter, running on Node and on the edge through the Fetch API.
Adapter
The node:http adapter: the reference implementation of the contract, with no framework and no dependencies.
Every API reference, the HTTP guides, the adapter matrix and the changelogs are published from the Gland repositories themselves, on every build. A guide is written where the code is, and the site republishes it.
Start with the mental model, build the smallest working app, then go deeper into controllers, channels, modules and brokers.
Install the packages, declare one event map and ship a complete product API with channels.