Migrating to the Pluggable-Runtimes Release
This release makes the HTTP engine pluggable — KickJS now runs on Express, Fastify, or h3. It's a major version because the public surface around the HTTP layer changed, but for the common case the upgrade is a no-op.
TL;DR
- Express apps need no code changes. Express stays the zero-config default; existing apps behave exactly as before.
- New: opt into another engine with one line —
bootstrap({ modules, runtime: fastifyRuntime() }). See HTTP Runtimes. - A few type and adapter-author details changed; they're listed below.
For app authors
Nothing required
Your controllers speak RequestContext, not Express, so they already run on any engine. bootstrap({ modules }) keeps using Express. Done.
Optional: make the runtime explicit
New projects scaffolded with kick new now emit the runtime explicitly:
import { bootstrap, expressRuntime } from '@forinda/kickjs'
export const app = await bootstrap({ modules, runtime: expressRuntime() })You don't have to add this to existing apps — it's purely for clarity and to make switching engines a one-line edit. To switch:
import { fastifyRuntime } from '@forinda/kickjs/fastify' // pnpm add fastify @fastify/middie
// or
import { h3Runtime } from '@forinda/kickjs/h3' // pnpm add h3Response-helper return types
ctx.json() / ctx.html() / ctx.problem.* and friends now return RuntimeResponse instead of Express's Response. The value is almost never consumed (handlers just call the helper and return), so this rarely matters. If you stored it — const r: Response = ctx.json(...) — drop the annotation or use ctx.res for the raw engine response.
Do not use ctx.res to send anything a helper already covers — a file download is the one that bites, and ctx.download(buffer, filename, type?) handles it on all three engines.
getExpressApp() → getRuntimeApp()
app.getExpressApp() still works but is deprecated. Prefer app.getRuntimeApp(), which returns the engine-native app typed from the active runtime.
For adapter authors
Use ctx.http instead of ctx.app
AdapterContext gained an engine-agnostic http surface — the supported way to add routes, mounts, static dirs, and middleware:
beforeMount({ http }) {
http.route('GET', '/_my/panel', (ctx) => ctx.html(PANEL))
http.serveStatic('/_my/assets', assetsDir)
http.use(myConnectMiddleware)
}ctx.app is still available as the engine-native escape hatch (Express by default), but an adapter written against ctx.http works on every runtime.
AdapterContext.app is now runtime-typed
AdapterContext.app and getRuntimeApp() are typed ActiveRuntime['app'] — Express by default. If you build a mock AdapterContext in tests, it now needs an http entry alongside app.
Removed packages
@forinda/kickjs-auth, @forinda/kickjs-prisma and @forinda/kickjs-drizzle were removed in v8, along with their kick add entries. The @forinda/kickjs-db-{pg,mysql,sqlite} shims are frozen at their last published version. Nothing uninstalls itself — an app pinned to one keeps working against the version it was built for — but none of them come with you to v8.
Replacements: BYO auth composed from context decorators, and @forinda/kickjs-db with its /pg · /mysql · /sqlite subpaths. See the v8 migration guide.