Can I use Hono with Nitro without starting a port?
if i wanna use hono w nitro, but don't want to start an app in a port, but rather, target hono's fetch in-process: is that possible?
I now have a thorough understanding. Let me provide a comprehensive answer.
Yes, absolutely! This is not only possible, it's actually a first-class pattern in Nitro. Here's what's going on under the hood:
##How it works
At its core, every Nitro app exposes a fetch handler — the nitroApp.fetch function (src/runtime/internal/app.ts:153). This is a standard Web fetch-compatible function ((Request) => Response | Promise<Response>). Every Nitro preset — whether it's Cloudflare Workers, Deno Deploy, Node, etc. — ultimately just wires up nitroApp.fetch to whatever runtime interface it needs. No port is inherently required.
##Option 1: Use the standard preset (recommended)
The standard preset does exactly what you want — it exports a bare fetch handler with no server startup:
// src/presets/standard/runtime/server.ts
import { useNitroApp } from "nitro/app";
const nitroApp = useNitroApp();
export default {
fetch: nitroApp.fetch,
};
Build with preset: "standard" and you get a module that just exports { fetch }. You can import it and call fetch(request) directly in-process.
##Option 2: Use the node-middleware preset
If you're in a Node.js environment and want a Node-compatible handler (not a raw fetch), the node-middleware preset exports a connect/express-style middleware — also no port listening:
// src/presets/node/runtime/node-middleware.ts
const nitroApp = useNitroApp();
export const middleware = toNodeHandler(nitroApp.fetch);
##Combining with Hono as the server entry
Since Nitro v3 auto-detects server.ts and Hono's app object already has a standard .fetch() method, you can use Hono as your server entry:
// server.ts
import { Hono } from "hono";
const app = new Hono();
app.get("/", (c) => c.text("Hello, Hono with Nitro!"));
export default app; // Hono exposes .fetch() — Nitro picks it up
This server.ts is registered as a catch-all /** route handler inside Nitro (src/routing.ts:64-71). So when nitroApp.fetch(req) is called, it flows through Nitro's middleware pipeline and eventually reaches your Hono app.
##Putting it all together
// nitro.config.ts
import { defineConfig } from "nitro";
export default defineConfig({
preset: "standard", // or "node-middleware"
});
// server.ts
import { Hono } from "hono";
const app = new Hono();
app.get("/", (c) => c.text("Hello!"));
export default app;
After building, the output is a module that exports { fetch }. You can call it directly in-process:
import server from "./output/server/index.mjs";
const response = await server.fetch(new Request("http://localhost/"));
console.log(await response.text()); // "Hello!"
No port. No HTTP server. Just a fetch call in-process. This is the same pattern used by Cloudflare Workers, service workers, and other edge runtimes — all of which are fundamentally just fetch handlers.
END OF POST