Deno
Install NextRush on Deno, run a hello-world server on Deno.serve(), and see what Deno's permission model means for your NextRush app.
Runtime · Secure by default
Secure by default, permission model. Deno refuses to do anything without explicit permission —
no filesystem, network, or environment access until you grant it with a flag. Same
createApp/createRouter API as Node and Bun, running on Deno.serve(). The tradeoff: every
deno run needs the right --allow-* flags, or the process denies the request before your route
ever runs.
Where Deno fits
| Runtime | Best for | Tradeoff |
|---|---|---|
| Node | Production APIs, long-running servers, full ecosystem | Heavier footprint than Bun or edge |
| Bun | Local dev speed, native TypeScript, fast cold start | Younger ecosystem, some node:* gaps |
| Deno · this page | Secure by default, permission model, TS native | Smaller package ecosystem |
| Edge | Global low latency, Cloudflare/Vercel | No long-running server, node:* limited |
| Serverless | Pay-per-request, auto-scaling | Cold starts, no persistent state |
What changes from Node
| Same | Different |
|---|---|
createApp() | listen() import — comes from @nextrush/adapter-deno, not nextrush |
createRouter() | Runtime underneath — Deno.serve(), not node:http |
| Route registration | Permission flags — --allow-net required, --allow-read/--allow-env as needed |
| Context API | npm: specifier — Deno resolves npm packages directly |
| Middleware | No tsx needed — Deno runs .ts directly |
"Partial" means the adapter is Stable 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 · Edge · Serverless each implement the same Context and Application contract. Not sure which one fits? See the runtime decision guide.
Before you begin
- ✓ Deno installed (deno.com)
- ✓ A terminal
- ✓ ~10 minutes
Confirm your Deno version
- Why this matters:
@nextrush/adapter-denotargets Deno's stableDeno.serve()surface.
deno --version
# needs to read deno 2.x.x or higherIf Deno isn't installed yet, follow the install instructions before continuing.
Install NextRush and the Deno adapter
- Why this matters: like Bun, the
nextrushmeta-package does not bundle a runtime adapter — you add@nextrush/adapter-denoalongside it.
Do: Deno resolves npm packages directly with the npm: specifier — no separate lockfile
step needed for a quick script:
import { createApp, createRouter } from 'npm:nextrush';
import { listen } from 'npm:@nextrush/adapter-deno';Or pin the same imports in deno.json so every file in the project resolves them the same way:
{
"imports": {
"nextrush": "npm:nextrush",
"@nextrush/adapter-deno": "npm:@nextrush/adapter-deno"
}
}Behind the scenes:
createAppandcreateRouterstill come fromnextrush— runtime-independentlisten,serve, andcreateHandlercome from@nextrush/adapter-deno— the meta-package'slistenis wired to@nextrush/adapter-nodespecifically- Once imports are in
deno.json, every file can write plainimport { createApp } from 'nextrush'— the import map resolves thenpm:specifier
Run a hello-world server
Create server.ts:
import { createApp, createRouter } from 'nextrush';
import { listen } from '@nextrush/adapter-deno';
const app = createApp();
const router = createRouter();
router.get('/', (ctx) => {
ctx.json({ runtime: 'deno', status: 'ok' });
});
app.route('/', router);
await listen(app, 8080);Run it — Deno requires an explicit network permission:
deno run --allow-net server.tsExpected result — curl http://localhost:8080/ returns {"runtime": "deno", "status": "ok"}
Behind the scenes:
listen(app, 8080)from@nextrush/adapter-denocallsDeno.serve()directly- Each request goes to NextRush's router through the same Context API Node and Bun use
ctx.runtimereads'deno'because the adapter, not your handler, decides that value
--allow-net is not optional. Deno denies network access by default; omitting the flag fails
the process before your route ever runs. Add --allow-read if you serve files from disk, or
--allow-env if your app reads environment variables — grant only what your handlers actually use.
Why Deno's permissions matter
Your server is now running. Before moving on, it's worth understanding what Deno's permission model changes — and what stays the same.
Same: the Context API, createApp, createRouter, route registration, and middleware all
behave identically to Node and Bun. Nothing in your route handler is Deno-specific.
Different: the --allow-* flags are a property of the Deno process, not something
@nextrush/adapter-deno adds or works around. The adapter has no permission-checking code — it
calls Deno.serve() the same way your own code would, and Deno's runtime enforces the sandbox
before the adapter ever runs. A missing permission fails at the OS/runtime boundary, not inside
NextRush.
One adapter-level behavior: @nextrush/adapter-deno adds its own request timeout
(Promise.race-based, since Deno.serve() has no built-in per-request timeout) — defaults to
30 seconds, matching Node and Bun.
Deno runtime working — you're ready to verify and move on.
Deno baseline complete
Confirm the server answers:
curl -i http://localhost:8080/
# → HTTP/1.1 200 OK
# → {"runtime":"deno","status":"ok"}Your project now looks like:
my-api/
deno.json
server.tsBaseline complete — nothing ran that wasn't explicitly permitted, and the request still made it through.
What you learned
- ✓
nextrushgives you the runtime-independent half —createApp,createRouter, and route registration are identical on Deno, Bun, and Node - ✓
listen/serve/createHandlercome from@nextrush/adapter-deno, not the meta-package - ✓ Deno's permission flags are a runtime property, not a NextRush setting —
--allow-net(and--allow-read/--allow-envas needed) gate the process before any NextRush code runs
The same app, every runtime
The code you just wrote runs on every runtime NextRush supports. Only the adapter import changes:
- createApp()
- Router
- Handler
- Deno adapter
- Running
// Node: import { listen } from '@nextrush/adapter-node';
// Bun: import { listen } from '@nextrush/adapter-bun';
// Deno: import { listen } from '@nextrush/adapter-deno'; // ← you are here
// Edge: import { serve } from '@nextrush/adapter-edge';
// 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 →
Deploy to production
Deno Deploy and Docker deployment paths for a NextRush server on Deno.
Deno adapter reference
The full @nextrush/adapter-deno surface — serve(), createHandler(), and Deno-specific utilities.