zmdbzero-maintenance data layer
Docs Benchmarks Anti-patterns OpenAPI
Docs / Server framework

Application Bootstrap & LifecycleSupported

createApp bootstraps an application from a root module: it compiles the DI graph, builds the router, and registers every controller's routes — once. It exposes lifecycle hooks and await using graceful shutdown. Its optional second argument accepts protocol-neutral application extensions, including the transportExtension and the typed grpcExtension.

Bootstrapping#

import { createApp } from '@zmdb/core/web';

const app = createApp(AppModule);
await app.init(); // run lifecycle init hooks

// serve over any runtime:
await app.handle({ method: 'GET', path: '/ping', headers: {} }); // framework-neutral
await app.fetch(new Request('http://x/ping')); // Fetch (Hono/edge)

app.lazy contains the per-app handles for lazy module imports. It is empty for an all-eager graph.

Lifecycle hooks#

Implement any of these on a controller (or provider) and they run at the right time:

import type { OnModuleInit, OnApplicationBootstrap, OnShutdown } from '@zmdb/core/app/lifecycle';

class Db implements OnModuleInit, OnShutdown {
  onModuleInit() {
    /* connect */
  }
  onShutdown() {
    /* close pool */
  }
}
phaseorder
init()eager instances: onModuleInitonApplicationBootstrap → configured extensions in order
lazy loadthat subtree's constructed providers/controllers: init pass → bootstrap pass
shutdownextensions stop in reverse order → instances onShutdown in reverse construction order

“All” means every constructed object provider and controller. Value providers enter the ledger when registered; factory providers enter only when resolved. A factory first resolved after init() is still shut down, without retroactive init hooks, and an unresolved factory is never constructed for lifecycle.

Graceful shutdown with await using#

createApp returns an AsyncDisposable, so Stage-3 explicit resource management cleans up automatically:

await using app = createApp(AppModule);
await app.init();
// ... serve ...
// at scope exit: transports close, then onShutdown hooks run via Symbol.asyncDispose

Design notes#

Continue with the generated HTTP client, client applications and the generated integration reference.