Embedded Runtime
Overview
AntelopeJS runs in one of two modes:
- Standalone — The
ajsCLI owns the process.ajs project devorajs project startreadsantelope.config.ts, loads the modules and runs until it receives a signal. - Embedded — Your application owns the process. It creates a runtime with
createRuntime(), lists its modules in code, and starts and stops the runtime from its own lifecycle.
Both modes run the same modules with the same core: interface binding, module lifecycle and proxies behave identically. The embedded mode changes who owns the process and where the module list lives, and it lets host code that is not a module call interfaces through the runtime handle.
@antelopejs/core exports createRuntime and AntelopeRuntime since version 1.5.0.
import { createRuntime } from "@antelopejs/core";
const runtime = createRuntime({
modules: {
"@antelopejs/mongodb": { config: { url: process.env.MONGODB_URL } },
},
uses: ["@antelopejs/interface-database"],
});
await runtime.start();
// ... the host application runs ...
await runtime.stop();
Standalone vs Embedded
| Aspect | Standalone | Embedded |
|---|---|---|
| Process owner | The ajs CLI. | Your application. |
| Signals and process handlers | The runtime claims SIGINT and SIGTERM and installs uncaughtException / unhandledRejection handlers. | The host keeps them. The runtime installs nothing unless you opt in through policy. |
| Logger | The runtime writes module logs using the logging section of antelope.config.ts. | The runtime writes no log lines unless you pass logging. Passing it resets the global logger and takes over the log output. |
| Terminal output | Progress spinners on stdout. | None, unless policy.terminal is on. |
| Where configuration lives | antelope.config.ts, with environments, envOverrides and ${path} template substitution. | The modules map passed to createRuntime(). Values are plain JavaScript: read environment variables in host code. |
| Module resolution | Local, package and Git sources, installed into the .antelope/cache folder. | Packages installed in the host's node_modules, or a path to a module folder. Nothing is downloaded and no cache is created. |
ajs commands | All ajs project commands. | No ajs project command. ajs module commands still work on the module folders themselves. |
| Hot reload | ajs project dev --watch reloads changed modules and restarts on configuration changes. | None. The runtime starts in non-development mode with no file watcher; restart the host to pick up changes. |
GetRuntimeInfo() | dev is true under ajs project dev. | dev is always false; env is the env option, default when unset. |
| How application code reaches interfaces | Modules import interface packages; the core binds each import to a provider. | Modules work the same way. Host code calls runtime.use(), and implements interfaces with runtime.provide(). |
How the Runtime Joins the Host
createRuntime() returns an AntelopeRuntime that is not started. start() resolves each entry of modules from the host's node_modules (or from its path), then constructs and starts the modules exactly like a standalone launch.
The runtime also registers the host itself as a module with the reserved id __antelope_host__. The packages listed in uses and provides become that module's dependencies, so the host gets its own provider-bound copy of each interface. This is why host code must go through runtime.use(): a plain import of an interface package from host code loads a second copy of the package that no provider is attached to.
The host module carries no importOverrides, so runtime.use() returns a copy bound to the default provider of each interface. When several loaded modules implement the same interface, steer the default with exportPriority.
The host owns the outer lifecycle; the runtime owns the modules inside it:
Host application
│ createRuntime({ modules, uses })
▼
Runtime handle (not started yet)
│ await start()
▼
Modules constructed and started
│ host calls runtime.use(contract)
▼
Provider-bound interface → provider
│ host finishes serving requests
▼
await runtime.stop()
└─ modules stopped and destroyed
This is an ownership and call-flow map, not another process. A plain host import is not the provider-bound interface shown here.
API Reference
createRuntime(options?)
Creates an AntelopeRuntime that runs as a guest of the calling process. The runtime is not started.
function createRuntime(options?: EmbeddedRuntimeOptions): AntelopeRuntime;
EmbeddedRuntimeOptions accepts the following fields, all optional:
| Option | Type | Default | Description |
|---|---|---|---|
projectFolder | string | process.cwd() | Folder that modules and relative path values resolve from. |
env | string | "default" | Environment name reported to modules by GetRuntimeInfo(). |
modules | Record<string, EmbeddedModuleConfig> | {} | Modules to load, keyed by package name. |
uses | string[] | [] | Interface packages the host consumes. start() fails if one does not resolve. |
provides | string[] | [] | Interface packages the host implements. The host becomes their default provider, and start() fails if one does not resolve. |
logging | AntelopeLogging | unset | Log configuration, with the same shape as the logging section of antelope.config.ts. Setting it turns on the logging policy. |
policy | Partial<RuntimePolicy> | all false | Process responsibilities the runtime takes over from the host. |
Each EmbeddedModuleConfig entry of modules accepts:
| Field | Type | Description |
|---|---|---|
path | string | Module folder, absolute or relative to projectFolder. When unset, the package is resolved from the host's node_modules. |
config | unknown | Configuration passed to the module, as is. |
importOverrides | ImportOverride[] | Provider pins and connections, in the array form described in Interface Bindings. |
disabledExports | string[] | Interfaces the module must not provide. See Disabled Exports. |
exportPriority | Record<string, number> | Priority of the module as the default provider, keyed by interface. See Default provider. |
RuntimePolicy lists the process responsibilities. All of them are off in embedded mode and on in standalone mode:
| Field | Effect when true |
|---|---|
processHandlers | Install uncaughtException and unhandledRejection handlers. |
signals | Claim SIGINT and SIGTERM, and stop the runtime when they arrive. |
terminal | Draw progress spinners on stdout. |
logging | Reset the global logger and take over the log output. Passing the logging option turns this on. |
AntelopeRuntime
| Member | Description |
|---|---|
start(): Promise<void> | Loads, constructs and starts the modules. Concurrent calls share one launch. If a module fails or a uses / provides package does not resolve, the runtime shuts down what it started and the promise rejects. |
stop(): Promise<void> | Stops and destroys the modules. Waits for an in-flight start() to settle first. Does nothing when the runtime is not running. |
isRunning: boolean | true between a successful start() and the next stop(). |
use<T>(request: string): T | Returns the runtime's provider-bound copy of an interface package or one of its subpaths, such as @antelopejs/interface-dms/client-base-url. Throws before start(), and when no loaded module provides the interface. |
provide(packageName, implementation): ProvideHandle | Implements an interface from host code. The package must be listed in provides. Call detach() on the returned handle to remove the implementation. |
manager: ModuleManager | The underlying module manager, for introspection such as runtime.manager.listModules(). The list includes the __antelope_host__ module. Throws before start(). |
start() logs a warning when a loaded module also implements an interface listed in provides: the host wins by default, and importOverrides on the consumers route them to the module instead.
Calls through an interface wait until an implementation is attached. After detach(), calls to the detached interface wait instead of failing.
See also
- Embed AntelopeJS in an Existing App — Step-by-step guide with a complete AdonisJS example
- Configuration — The standalone
antelope.config.tsfile - Runtime —
GetRuntimeInfo()and the development server registry - Project commands — The
ajs projectcommands of the standalone mode