tnl.dev :: docs

frameworks.

Connect your app to tnl dev.

choose an integration

tnl dev needs to know which local HTTP listener to publish. tnl init wires up recognized projects or prints the action needed for custom files. Pick the integration for your app:

AppConnection to tnl dev
ViteAdd the tnl() plugin.
Next.jsWrap the config in withTnl().
Node or Bun HTTP serverUse tnl.port and register the server.
Other appUse a fixed tnl dev --port.

api servers

On Node or Bun, tnl.port is 0 under tnl dev so the OS selects a free port; outside tnl it uses the usual runtime port or 3000. Register the actual bound HTTP server with await tnl.register(server). For example, with Node:

server.ts (Node)
import { createServer } from "node:http";
import { tnl } from "@tnldotdev/tnl";
 
const server = createServer((_request, response) => response.end("hello"));
server.listen(tnl.port, "127.0.0.1");
await tnl.register(server);

With Bun:

server.ts (Bun)
import { tnl } from "@tnldotdev/tnl";
 
const server = Bun.serve({
  hostname: "127.0.0.1",
  port: tnl.port,
  fetch: () => new Response("hello"),
});
await tnl.register(server);

Keep your existing server framework: register the server returned by Express's app.listen(tnl.port) or Hono's Node serve({ fetch: app.fetch, port: tnl.port }); for Fastify, await app.listen({ port: tnl.port }), then register app.server. For Bun with Hono, pass app.fetch to Bun.serve. If tnl init cannot safely change a custom entrypoint, make these edits yourself. The target must be local HTTP, not HTTPS or a remote host. See the development workflow.

use a service url in your app

When your project configuration defines web and api, tnl generates browser-safe metadata for their worktree-specific public URLs. Read the API URL from the frontend or server:

apps/web/src/api.ts
import { tnl } from "@tnldotdev/tnl";
 
const apiURL = tnl.services?.api?.url;

tnl dev updates metadata for configured projects; run tnl config generate to generate it without starting a tunnel. Include .tnl/project.d.ts in TypeScript for typed service names and ignore .tnl/ in Git. The URL may exist before the API service is running. The metadata contains no access token; your app still handles authentication. See project metadata and security.