Escape Hatches
The config-driven package/entity stack is the default path, not a cage.
When the managed surface stops being the right abstraction, these are the supported escape hatches.
Route-level escape hatches
Section titled “Route-level escape hatches”Generated-route executor overrides
Section titled “Generated-route executor overrides”Replace the executor behind a generated CRUD or named-operation route while keeping the route shell, OpenAPI spec, and middleware intact. Use defineEntityExecutor() with an overrides map.
Full examples: Override a generated route
Extra routes inside the entity shell
Section titled “Extra routes inside the entity shell”Add routes that live alongside generated entity routes using extraRoutes and defineEntityRoute(). They share the same collision checking and specificity ordering as generated routes.
Full examples: Add an extra route
File-based routes with routesDir
Section titled “File-based routes with routesDir”Use this when the route belongs to the app directly rather than to a package-owned entity/domain module. Author the route with createRoute(...), createRouter(), and router.openapi(...), then let routesDir auto-discover and mount the route module.
Full examples: File-based routes
Raw Hono routers and middleware
Section titled “Raw Hono routers and middleware”Use raw Hono when:
- you need a lower-level router shape
- the route is middleware-heavy and does not fit the managed package/domain route shell
- you are integrating third-party Hono middleware or request handling patterns directly
This is still a supported path. It is just lower-level than package/entity authoring.
Persistence escape hatches
Section titled “Persistence escape hatches”Factories wiring
Section titled “Factories wiring”Use entity({ wiring: { mode: 'factories', ... } }) when you want custom repo-backed behavior while keeping the entity shell.
This is the normal escape hatch for custom repos, store-specific adapter behavior, and persistence code that still maps cleanly to an entity adapter.
Full examples: Factories wiring mode
Manual adapter wiring
Section titled “Manual adapter wiring”Use entity({ wiring: { mode: 'manual', buildAdapter(...) } }) when you need full control over adapter construction.
This is the stronger escape hatch for non-standard persistence composition, custom driver integration, and repo layers that do not fit the standard factories path.
Full examples: Manual wiring mode
Composite factories
Section titled “Composite factories”Use createCompositeFactories(...) when a package owns several related entities that share a backing store and should be wired together.
Full examples: Composite factories
Storage backend swapping
Section titled “Storage backend swapping”Switch the backing store for entities at the app root without changing entity definitions or adapter code. Supports memory, SQLite, Postgres, Redis, and Mongo.
Full examples: Backend swapping at the app root
Raw SQL
Section titled “Raw SQL”Raw SQL belongs in the adapter or repo layer, not in the entity DSL itself.
Use it when you need hand-written joins, database-specific query tuning, or reporting queries that do not map to the operation DSL. The route shell or package layer can still sit above that repo code.
Drizzle
Section titled “Drizzle”Drizzle is also an escape hatch, not the primary config-driven abstraction.
The right place for Drizzle code is usually a custom repo used by factories wiring, a manual adapter implementation, or a package-local service used by a package domain route. Keep the boundary explicit instead of pretending it is the entity DSL itself.
Consumer shape escape hatches
Section titled “Consumer shape escape hatches”System fields, storage fields, and conventions
Section titled “System fields, storage fields, and conventions”defineEntity(...) accepts systemFields, storageFields, and conventions to rename audit fields, storage column names, ID generation strategies, and Redis key formats without forking adapters.
Full examples: System fields, storage fields, and conventions
Runtime composition escape hatches
Section titled “Runtime composition escape hatches”Package domain routes
Section titled “Package domain routes”A package domain({ routes: [...] }) route is the first step out of pure entity CRUD/operation generation. Use it when the route spans multiple entities, handles orchestration, or has a package-level response model.
Full examples: Package domain routes
createEntityPlugin()
Section titled “createEntityPlugin()”Use createEntityPlugin() when you need lower-level orchestration that entity(...) and definePackage(...) do not cover. This is the lower-level compatibility and escape-hatch surface beneath package-first authoring.
Full examples: Config-Driven Domain example
Raw plugins
Section titled “Raw plugins”Use a raw SlingshotPlugin when you need full lifecycle control, custom bootstrapping that does not fit package/entity compilation, or direct router mounting in plugin phases.
This is the broadest escape hatch and should be treated as the lowest-level public authoring surface.
Full examples: Plugin Interface
Middleware escape hatches
Section titled “Middleware escape hatches”Three levels, from managed to raw:
- Package middleware referenced by name from entity/domain routes
- Raw Hono middleware mounted through routers or plugin phases
- Full plugin lifecycle hooks for setup-time and post-assembly behavior
Use the lowest level that actually solves the problem.
Decision guide
Section titled “Decision guide”Use:
- package/entity authoring for the normal case
- executor overrides to replace generated route behavior
- extra routes for entity-adjacent endpoints
- package domain routes for orchestration and custom package endpoints
- factories/manual adapters for custom persistence
- raw SQL or Drizzle inside repo/adapter code
routesDiror raw Hono routers for app-level file-based routes- raw plugins for lifecycle-level escape hatches
See also
Section titled “See also”- Generated Routes, Overrides, and Extra Routes — full examples for overrides and extra routes
- Storage and Adapter Wiring — full examples for all wiring modes
- defineEntity — system fields, storage fields, and conventions
- Package Domain Routes — typed routes that belong to the package
- Routes — file-based routes and the route decision matrix
- Adapters and Factories
- Cross-Entity and Transactions
- Packages and Capabilities