Native Elysia access
Return, configure, or retrieve the composed Elysia application without replacing it.
AponiaJS deliberately keeps Elysia accessible. Choose the calling surface that fits the application.
Return the native application
Use createNative() when native Elysia or Eden Treaty should own listening,
handling, and shutdown:
import { AponiaFactory } from "@aponiajs/platform-elysia";
const app = await AponiaFactory.createNative(AppModule, {
configureNative: (elysia) =>
elysia
.state("version", "1.0.0")
.get("/health", ({ store }) => ({
ok: true,
version: store.version,
})),
});
app.listen(3000);The return value is the composed Elysia instance itself. Its type preserves
statically declared plugin and controller routes plus everything added by
configureNative.
configureNative must mutate and return the exact Elysia instance it receives.
Returning a replacement instance throws INVALID_NATIVE_APPLICATION.
Keep the managed lifecycle
Use create() when Aponia's startup logging, getUrl(), and managed close()
method are useful:
const application = await AponiaFactory.create(AppModule, {
configureNative: (elysia) =>
elysia.state("version", "1.0.0"),
});
const native = application.getNativeApplication();getNativeApplication() preserves the same accumulated native type.
When to use this escape hatch
Use native access for behavior that the decorated surface does not implement:
- Elysia hooks, macros, error handlers, and lifecycle events;
- application-wide state or decorators declared outside any module;
- routes that need Elysia's complete handler signature;
- an application-wide native plugin.
Request binding and validation no longer require this escape hatch — see request parameters and route validation.
For reusable plugins owned by a module boundary, prefer
ElysiaPluginModule.
For an end-to-end typed client or a typed in-process request, see Eden Treaty.
Controller type boundary
State and decorators from module-imported plugins exist at runtime in every handler, but compiling a controller erases its module imports, so their types reach a handler only when the plugin is named — see typed plugin context.