ReferenceRuntime Adapters
@nextrush/adapter-deno

Deno

Deno HTTP adapter for NextRush — connects your application to Deno.serve().

Connect your NextRush application to Deno's native Deno.serve() API. This adapter bridges NextRush's middleware system to Deno's HTTP server.

Source & internals

Package@nextrush/adapter-deno
StatusStable
Support tierPublic — stable, semver-guarded
Included in nextrush?No — standalone install
RuntimeDeno >=2.0 only

Installation

Import directly in Deno (no npm required):

import { createApp } from 'npm:@nextrush/core';
import { serve } from 'npm:@nextrush/adapter-deno';

Or with import maps in deno.json:

{
  "imports": {
    "@nextrush/core": "npm:@nextrush/core",
    "@nextrush/adapter-deno": "npm:@nextrush/adapter-deno"
  }
}

Deno Permissions Required

Deno requires explicit network permission to run an HTTP server. Use --allow-net at minimum. See Deno Permissions for details.


Quick Start

import { createApp } from '@nextrush/core';
import { listen } from '@nextrush/adapter-deno';

const app = createApp();

app.use(async (ctx) => {
  ctx.json({ runtime: 'deno', message: 'Hello World!' });
});

listen(app, 8080);
// Output: 🚀 NextRush listening on http://localhost:8080 (Deno)

Run with Deno:

deno run --allow-net src/main.ts

API Reference

serve(app, options?)

Start the HTTP server with full configuration control.

import { createApp } from '@nextrush/core';
import { serve } from '@nextrush/adapter-deno';

const app = createApp();

const server = serve(app, {
  port: 8080,
  host: '0.0.0.0',
  onListen: ({ port, hostname }) => {
    console.log(`Server running at http://${hostname}:${port}`);
  },
  onError: (error) => {
    console.error('Server error:', error);
  },
});

ServeOptions

ServeOptions

PropertyTypeDescription
portnumber= 8080Port to listen on
hoststring= '0.0.0.0'Host to bind to
onListen?(info: { port: number; host: string; hostname: string }) => voidCallback when server starts listening
onError?(error: Error) => voidCustom error handler for uncaught server errors
cert?stringTLS certificate in PEM format. Deprecated — use tls.cert instead; removed in a future minor version.
key?stringTLS private key in PEM format. Deprecated — use tls.key instead; removed in a future minor version.
tls?{ cert: string; key: string; ca?: string }TLS configuration (canonical shape — matches @nextrush/adapter-bun). Deno.serve() negotiates HTTP/1.1 vs HTTP/2 via ALPN automatically once this is present. Prefer this over the deprecated flat cert/key fields.
shutdownTimeoutnumber= 30000Grace period in ms for draining in-flight requests during shutdown
gracefulShutdown?boolean | GracefulShutdownOptionsOpt-in: wire SIGTERM/SIGINT to the same close() drain logic. `true` installs handlers for the default signal set; `{ signals, timeout }` overrides them. Omitted by default — no signal handler is installed and process behavior is unchanged.

ServerInstance

The returned server instance provides control methods:

interface ServerInstance {
  server: DenoServer; // Underlying Deno server
  port: number; // Actual port
  hostname: string; // Actual hostname

  close(): Promise<void>; // Graceful shutdown
  address(): { port; hostname };
  finished: Promise<void>; // Resolves when server stops
}

listen(app, port?)

Quick-start shorthand with default logging.

import { createApp } from '@nextrush/core';
import { listen } from '@nextrush/adapter-deno';

const app = createApp();
const server = listen(app, 8080);
// Output: 🚀 NextRush listening on http://localhost:8080 (Deno)

createHandler(app)

Create a raw handler for advanced use cases.

import { createApp } from '@nextrush/core';
import { createHandler } from '@nextrush/adapter-deno';

const app = createApp();
const handler = createHandler(app);

// Use directly with Deno.serve
Deno.serve({ handler, port: 8080 });

TLS/HTTPS & HTTP/2

Enable HTTPS with TLS certificates. Deno.serve() negotiates HTTP/1.1 vs HTTP/2 via ALPN automatically once TLS is configured — there is no separate protocol option.

import { serve } from '@nextrush/adapter-deno';

const server = serve(app, {
  port: 443,
  tls: {
    cert: await Deno.readTextFile('./cert.pem'),
    key: await Deno.readTextFile('./key.pem'),
  },
});

Migrating from the flat cert/key fields

The top-level cert/key options are deprecated in favor of tls (matching @nextrush/adapter-bun's shape) and will be removed in a future minor version:

// Before (deprecated)
serve(app, { cert, key });

// After
serve(app, { tls: { cert, key } });

Deno Permissions

NextRush requires network permission to run:

# Minimum required
deno run --allow-net app.ts

# With file access (for static files, etc.)
deno run --allow-net --allow-read app.ts

# Development (more permissive)
deno run --allow-all app.ts

Server Lifecycle

Waiting for Server Finish

Deno adapter exposes a finished promise:

const server = serve(app, { port: 8080 });

// Wait for server to complete (useful in scripts)
await server.finished;

Graceful Shutdown

Handle server shutdown properly:

const server = serve(app, { port: 8080 });

Deno.addSignalListener('SIGTERM', async () => {
  console.log('Shutting down...');
  await server.close(); // Closes app + server
  Deno.exit(0);
});

Or wire it declaratively with gracefulShutdown instead of listening for signals yourself:

const server = await serve(app, {
  port: 8080,
  gracefulShutdown: true, // installs SIGTERM + SIGINT, using shutdownTimeout as the drain window
});

// Or override the signal set / drain timeout explicitly:
const server2 = await serve(app, {
  port: 8080,
  gracefulShutdown: { signals: ['SIGTERM'], timeout: 5_000 },
});

Omitting gracefulShutdown installs no signal handler — process behavior is unchanged. The handler is removed once close() completes, so repeated serve()/close() cycles never accumulate duplicate listeners.


Client IP Access

The adapter extracts client IP from Deno's connection info:

app.use(async (ctx) => {
  // Available via context
  const ip = ctx.ip; // From remoteAddr
  ctx.json({ clientIp: ip });
});

Deno Deploy

For Deno Deploy, use createHandler:

import { createApp } from '@nextrush/core';
import { createHandler } from '@nextrush/adapter-deno';

const app = createApp();

app.use(async (ctx) => {
  ctx.json({
    message: 'Hello from Deno Deploy!',
    region: Deno.env.get('DENO_REGION'),
  });
});

Deno.serve(createHandler(app));

TypeScript

Full TypeScript support with Deno's native TS:

import type { Application } from '@nextrush/core';
import type { ServeOptions, ServerInstance } from '@nextrush/adapter-deno';
import { serve, listen, createHandler } from '@nextrush/adapter-deno';

const options: ServeOptions = {
  port: 8080,
  hostname: '0.0.0.0',
};

const server: ServerInstance = serve(app, options);

Was this helpful?

On this page