Skip to main content

CreateApplication

CreateApplication creates the top-level module that owns bootstrap. You call it once per entrypoint. The returned ApplicationDefinition has bootstrap() and teardown() methods.

import { CreateApplication } from "@digital-alchemy/core";

export const MY_APP = CreateApplication({
name: "my_app",
services: { ... },
libraries: [...],
configuration: { ... },
priorityInit: [...],
});

Options

PropertyTypeRequiredDescription
namekeyof LoadedModulesModule name — must match the key in LoadedModules
servicesServiceMapObject mapping service names to service functions
librariesLibraryDefinition[]Libraries to load before application services
configurationModuleConfigurationConfig entry declarations for this module
priorityInitstring[]Services to wire first, in listed order

name

The name must exactly match the key you declare in LoadedModules:

export const MY_APP = CreateApplication({ name: "my_app", ... });

declare module "@digital-alchemy/core" {
export interface LoadedModules {
my_app: typeof MY_APP; // ← key must match name
}
}

If they don't match, TServiceParams won't have a typed entry for your app's services.

services

An object mapping string keys to service functions. Each service function must match the ServiceFunction signature — a function that receives TServiceParams and returns any value or a Promise.

services: {
auth: AuthService,
database: DatabaseService,
api: ApiService,
}

libraries

An array of LibraryDefinition objects (created by CreateLibrary). Libraries in this array are wired before application services. The order is determined by the dependency graph, not by array position — but listing them in dependency order is good practice.

libraries: [MY_LIB, OTHER_LIB]

If a library has depends: [X] and X is not in this array, bootstrap throws MISSING_DEPENDENCY.

configuration

Config entry declarations for this module. See Configuration Overview for the full type reference.

priorityInit

Names of services to wire first, in the listed order. Useful when a service needs another service's return value at wiring time (not just inside a lifecycle callback).

priorityInit: ["database", "cache"] // database wires first, then cache, then everything else

If a name in priorityInit doesn't exist in services, bootstrap throws MISSING_PRIORITY_SERVICE.

Methods

bootstrap(options?)

Starts the application. Returns a Promise<TServiceParams> that resolves when Ready completes.

await MY_APP.bootstrap({
configuration: { my_app: { PORT: 8080 } },
});

See Bootstrap Options for all available options.

Throws DOUBLE_BOOT if called on an application that's already running.

teardown()

Runs shutdown stages (PreShutdownShutdownStartShutdownComplete) and cleans up all resources. Called automatically on SIGTERM and SIGINT.

await MY_APP.teardown();

Safe to call if the application is not booted — it's a no-op in that case.

Type pattern

The standard pattern is to export the application from a definition file and import it in entrypoints and tests:

src/app.mts
export const MY_APP = CreateApplication({ ... });

declare module "@digital-alchemy/core" {
export interface LoadedModules { my_app: typeof MY_APP; }
}
src/main.mts
import { MY_APP } from "./app.mts";
await MY_APP.bootstrap();
src/main.dev.mts
import { MY_APP } from "./app.mts";
await MY_APP.bootstrap({ configuration: { boilerplate: { LOG_LEVEL: "debug" } } });

This keeps the module definition separate from bootstrap options, making it easy to have multiple entrypoints with different configurations.