Getting StartedChoose Your Runtime

Edge

Install NextRush on Cloudflare Workers or Vercel Edge, run a hello-world fetch handler, and see what changes when there's no long-running server.

Runtime · Stateless & distributed

No server, no port, global reach. Edge runtimes have no long-running process — your app is a fetch function invoked per request, deployed to whichever network location is closest to the caller. Same createApp/createRouter API as Node, but no serve(), no node:* modules, no filesystem, and no guaranteed shutdown hook. The tradeoff for that global reach is a real set of platform constraints.

Global reachNo server~10 minBeginner

Where Edge fits

RuntimeBest forTradeoff
NodeProduction APIs, long-running servers, full ecosystemHeavier footprint than Bun or edge
BunLocal dev speed, native TypeScript, fast cold startYounger ecosystem, some node:* gaps
DenoSecure by default, permission modelSmaller package ecosystem
Edge · this pageGlobal low latency, Cloudflare/VercelNo long-running server, node:* limited
ServerlessPay-per-request, auto-scalingCold starts, no persistent state

What changes from Node

SameDifferent
createApp()No listen() — edge has no port; you export a fetch handler
createRouter()No node:* modules — Fetch API only
Route registrationLazy boot — app boots on first request, not at startup
Context APINo shutdown hook — Extension.destroy() not guaranteed
MiddlewarePlatform CLI needed — wrangler or vercel

"Partial" means the adapter is functionally complete (Beta, Internal tier — see ADR-0005) but not yet verified against the real platform in CI (see the compatibility matrix) — not that it's missing features.

Targeting a different runtime? Node · Bun · Deno · Serverless each implement the same Context and Application contract. Not sure which one fits? See the runtime decision guide.

Before you begin

  • ✓ A terminal and a package manager
  • ✓ An account with your target platform (Cloudflare or Vercel) if you plan to deploy
  • ✓ ~10 minutes

Choose a target platform and its CLI

  • Why this matters: @nextrush/adapter-edge targets the Fetch API standard, not one platform's SDK — but you still need that platform's CLI to run and deploy.
npm install -g wrangler
wrangler --version
npm install -g vercel
vercel --version

Behind the scenes: the same @nextrush/adapter-edge package produces both platforms' handler shape — createCloudflareHandler returns Cloudflare's { fetch } module export, and createVercelHandler returns the plain function Vercel's Edge runtime expects.

Install NextRush and the edge adapter

  • Why this matters: like Bun and Deno, the nextrush meta-package does not bundle a runtime adapter — you add @nextrush/adapter-edge alongside it.
$ pnpm add nextrush @nextrush/adapter-edge

Behind the scenes:

  • createApp and createRouter still come from nextrush — runtime-independent
  • Handler factories (createCloudflareHandler, createVercelHandler, createFetchHandler) come from @nextrush/adapter-edge
  • Edge has no listen() at all — there is no port to listen on

Run a hello-world fetch handler

Create the handler for your platform:

src/index.ts
import { createApp, createRouter } from 'nextrush';
import { createCloudflareHandler } from '@nextrush/adapter-edge';

const app = createApp();
const router = createRouter();

router.get('/', (ctx) => {
  ctx.json({ runtime: ctx.runtime, status: 'ok' });
});

app.route('/', router);
export default createCloudflareHandler(app);
wrangler.toml
name = "my-nextrush-worker"
main = "src/index.ts"
compatibility_date = "2025-01-01"

Run locally, then deploy:

wrangler dev
wrangler deploy
api/hello.ts
import { createApp, createRouter } from 'nextrush';
import { createVercelHandler } from '@nextrush/adapter-edge';

const app = createApp();
const router = createRouter();

router.get('/', (ctx) => {
  ctx.json({ runtime: ctx.runtime, status: 'ok' });
});

app.route('/', router);
export const config = { runtime: 'edge' };
export default createVercelHandler(app);

Run locally, then deploy:

vercel dev
vercel

Expected result — curl https://your-worker.workers.dev/ returns {"runtime": "cloudflare-workers", "status": "ok"}

Behind the scenes:

  • createCloudflareHandler(app) returns { fetch }, createVercelHandler(app) returns the fetch function directly
  • Both wrap the same internal request runner — lazily boots on first request, then reuses the handler
  • ctx.runtime reports 'cloudflare-workers' or 'vercel-edge' depending on where the code runs

What's structurally different about edge

Your handler is deployed. Before moving on, understand what's genuinely different — and what isn't.

Same: the Context API, createApp, createRouter, route registration, and middleware all behave identically to Node. Nothing in your route handler is edge-specific.

Different: edge runtimes give you a fetch function invoked per request, not a process you start — so @nextrush/adapter-edge has no serve()/listen() at all. The application boots lazily on the first request instead of upfront. One consequence: Extension.destroy() teardown (timers, connections) is not guaranteed to run — edge platforms give you no shutdown hook.

No teardown on edge

Extension.destroy() is not guaranteed to run — there is no shutdown hook on Cloudflare Workers or Vercel Edge. Don't rely on extension teardown for correctness on edge; design for it to be skipped.

Edge runtime working — deployed at the network edge, no server to manage.

Edge baseline complete

Confirm the handler answers:

curl -i https://your-worker.workers.dev/
# → HTTP/1.1 200 OK
# → {"runtime":"cloudflare-workers","status":"ok"}

Your project now looks like (Cloudflare Workers shown):

my-worker/
  wrangler.toml
  src/
    index.ts

Baseline complete — deployed at the edge, answering from the network location closest to the caller.

What you learned

  • nextrush gives you the runtime-independent half — createApp, createRouter, and route registration are identical on edge and Node
  • ✓ The handler factories come from @nextrush/adapter-edge, not the meta-package — and there is no listen() because there is no port
  • ✓ The app boots lazily on the first request, and teardown never runs — a direct consequence of edge having no startup or shutdown hook

The same app, every runtime

The code you just wrote runs on every runtime NextRush supports. Only the adapter import changes:

  1. createApp()
  2. Router
  3. Handler
  4. Edge adapter
  5. Running
// Node:      import { listen } from '@nextrush/adapter-node';
// Bun:       import { listen } from '@nextrush/adapter-bun';
// Deno:      import { listen } from '@nextrush/adapter-deno';
// Edge:      import { serve } from '@nextrush/adapter-edge';    // ← you are here
// Serverless import { handler } from '@nextrush/adapter-serverless';

Next steps

🚀 Build a Task API — recommended · ~20 min

Go past hello-world on the runtime you set up: routing, a JSON body, and a real 404. Start the tutorial →

Continue learning

Was this helpful?

On this page