hono-node-workers-server #
Node.js Worker Threads runtime adapter for Hono.
This adapter keeps Hono routing and middleware in the main thread, then runs selected route logic in a new Node.js Worker for each request. Worker route modules use Web-standard Request and Response objects so the route logic stays easy to port to other Hono runtimes.
Requirements #
- Node.js 22+
- Hono 4+
Server #
import { Hono } from 'hono'
import { serve, workerRoute } from 'hono-node-workers-server'
const app = new Hono()
app.get(
'/hello/:name',
workerRoute(new URL('./routes/hello.mjs', import.meta.url), {
env: () => ({ greeting: 'Hello' }),
})
)
serve({ fetch: app.fetch, port: 3000 })
Worker Route #
import { defineWorkerRoute } from 'hono-node-workers-server/worker'
export default defineWorkerRoute(async (request, context) => {
const url = new URL(request.url)
return Response.json({
greeting: context.env.greeting,
name: context.params.name,
excited: url.searchParams.get('excited') === 'true',
})
})
The worker route file must be importable by a plain Node.js worker. In practice, point workerRoute() at compiled JavaScript, an .mjs file, or another module Node can import directly.
Portability #
Worker route modules are just fetch-style handlers. To run the same logic in a normal Hono route, call it from a Hono handler:
import hello from './routes/hello.mjs'
app.get('/hello/:name', (c) => {
return hello(c.req.raw, {
params: c.req.param(),
env: { greeting: 'Hello' },
})
})
API #
serve(options, listeningListener?) #
Starts a Node HTTP server.
serve({ fetch: app.fetch, port: 3000 })
createAdaptorServer(options) #
Creates a Node HTTP server without calling .listen().
const server = createAdaptorServer({ fetch: app.fetch })
workerRoute(moduleSpecifier, options?) #
Creates a Hono middleware handler that runs the route module in a fresh Worker Thread.
workerRoute(new URL('./routes/echo.mjs', import.meta.url), {
exportName: 'default',
env: (c) => ({ requestId: c.req.header('x-request-id') }),
timeoutMs: 1000,
})
Options:
exportName: export to call from the worker module. Defaults todefault.env: selects cloneable data to pass ascontext.env. If omitted,context.envisundefined.timeoutMs: aborts the worker if it does not produce a response in time.
Current Limitations #
- A new Worker Thread is created for each request. There is no worker pool yet.
- Only HTTP/1 is implemented.
- WebSockets are not implemented.
context.envmust be structured-cloneable. Useoptions.envto select only the data a worker route needs.RequestandResponseobjects are serialized across the worker boundary; Node cannot clone them directly.