---
title: "Deno Adapter"
description: "The Deno Adapter provides runtime integration for running Hono applications within the Deno environment. It bridges Hono's middleware and helper systems with Deno-specific platform APIs, exposing m..."
last_updated: "2026-10-12T08:14:12.721744+00:00"
canonical_url: "https://www.doc0.dev/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/technical/runtime-adapters/deno-adapter"
---

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [src/adapter/deno/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/deno/index.ts)
- [src/adapter/deno/websocket.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/deno/websocket.ts)
- [src/adapter/deno/serve-static.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/deno/serve-static.ts)
- [src/hono-base.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/hono-base.ts)
- [src/adapter/cloudflare-pages/handler.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/cloudflare-pages/handler.ts)
- [src/adapter/deno/deno.d.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/deno/deno.d.ts)
- [src/adapter/bun/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/bun/index.ts)
- [src/adapter/cloudflare-workers/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/cloudflare-workers/index.ts)
- [src/adapter/deno/ssg.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/deno/ssg.ts)
- [src/adapter/lambda-edge/handler.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/lambda-edge/handler.ts)
- [src/adapter/aws-lambda/handler.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/aws-lambda/handler.ts)
- [src/adapter/bun/websocket.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/bun/websocket.ts)
- [src/helper/ssg/ssg.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/helper/ssg/ssg.ts)
- [src/middleware/serve-static/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/middleware/serve-static/index.ts)
- [src/adapter/service-worker/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/service-worker/index.ts)
- [src/adapter/cloudflare-pages/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/cloudflare-pages/index.ts)
- [src/hono.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/hono.ts)
- [package.json](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/package.json)
- [src/adapter/deno/conninfo.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/deno/conninfo.ts)
- [src/helper/proxy/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/helper/proxy/index.ts)
- [src/adapter/bun/serve-static.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/bun/serve-static.ts)
- [src/adapter/netlify/handler.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/netlify/handler.ts)
- [src/adapter/cloudflare-workers/websocket.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/cloudflare-workers/websocket.ts)
- [src/adapter/vercel/handler.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/vercel/handler.ts)
- [src/adapter/service-worker/handler.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/service-worker/handler.ts)
- [src/context.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/context.ts)
- [src/helper/websocket/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/helper/websocket/index.ts)
- [src/adapter/vercel/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/vercel/index.ts)
- [src/helper/adapter/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/helper/adapter/index.ts)
- [runtime-tests/workerd/index.ts](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/runtime-tests/workerd/index.ts)
</details>

## Overview

The Deno Adapter provides runtime integration for running Hono applications within the Deno environment. It bridges Hono's middleware and helper systems with Deno-specific platform APIs, exposing modules for [static file serving](https://www.doc0.dev/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/technical/helpers-and-tooling/static-file-serving), WebSocket upgrading, [static site generation](https://www.doc0.dev/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/technical/helpers-and-tooling/static-site-generation), and connection network metadata extraction.

Sources: [src/adapter/deno/index.ts:1-9](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/deno/index.ts#L1-L9)

## Module exports and entry points

### Public API Surface

The `hono/deno` entry point exposes specific utility modules designed for the Deno runtime environment. These exports bridge standard Hono mechanics with Deno platform features such as file system-based static asset delivery, static site generation module bindings, WebSocket connection upgrades, and remote connection metadata retrieval.

| Export Name | Source Module | Purpose |
| --- | --- | --- |
| `serveStatic` | `./serve-static` | Serves static files from the Deno file system [Static Site Generation](https://www.doc0.dev/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/technical/helpers-and-tooling/static-site-generation) |
| `toSSG` | `./ssg` | Generates static sites using Deno file system bindings |
| `denoFileSystemModule` | `./ssg` | Provides Deno file system methods for static site generation output |
| `upgradeWebSocket` | `./websocket` | Upgrades standard HTTP connections to Deno WebSocket streams |
| `getConnInfo` | `./conninfo` | Extracts remote client network metadata from Deno incoming connections |

Sources: [src/adapter/deno/index.ts:1-9](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/deno/index.ts#L1-L9)

### Runtime Environment Detection

The adapter helper module defines the runtime identifier `'deno'` alongside other supported execution engines. When evaluating runtime environments through `getRuntimeKey`, the Deno runtime is identified by matching the `navigator.userAgent` string against known user agent configurations.

| Runtime Key | User Agent String / Detection Criteria |
| --- | --- |
| `deno` | `Deno` |
| `bun` | `Bun` |
| `workerd` | `Cloudflare-Workers` |
| `node` | `Node.js` |
| `edge-light` | `global.EdgeRuntime` string presence |
| `fastly` | `global.fastly` definition check |
| `other` | Fallback when no specific runtime matches |

Sources: [src/helper/adapter/index.ts:43-84](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/helper/adapter/index.ts#L43-L84)

> [!NOTE]
> Environment variable resolution in the adapter helper accesses `Deno.env.toObject()` when the runtime key resolves to `'deno'`, mapping runtime configuration directly into typed bindings.

Sources: [src/helper/adapter/index.ts:29-33](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/helper/adapter/index.ts#L29-L33)

## Serving static files from disk

### File System Adapter Integration

The `serveStatic` helper in `src/adapter/deno/serve-static.ts` wraps Hono's core `baseServeStatic` middleware from `src/middleware/serve-static` to deliver assets directly from the Deno file system. It destructs `open`, `lstatSync`, and `errors` from the global `Deno` namespace to handle file resolution and directory checks.

```typescript
const { open, lstatSync, errors } = Deno

export const serveStatic = <E extends Env = Env>(
  options: ServeStaticOptions<E> = {}
): MiddlewareHandler => {
  return async function serveStatic(c, next) {
    const getContent = async (path: string) => {
      try {
        if (isDir(path)) {
          return null
        }

        const file = await open(path)
        return file.readable
      } catch (e) {
        if (!(e instanceof errors.NotFound)) {
          console.warn(`${e}`)
        }
        return null
      }
    }
    const isDir = (path: string) => {
      let isDir
      try {
        const stat = lstatSync(path)
        isDir = stat.isDirectory
      } catch {}
      return isDir
    }
    return baseServeStatic({
      ...options,
      getContent,
      join,
      isDir,
    })(c, next)
  }
}
```

Sources: [src/adapter/deno/serve-static.ts:6-42](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/deno/serve-static.ts#L6-L42)

### Asset Resolution and Error Handling

When a request arrives, `getContent` first checks whether the target path points to a directory using the internal `isDir` helper backed by `Deno.lstatSync`. If the path represents a directory, `getContent` returns `null` immediately to trigger directory index fallback or routing continuation. Otherwise, it attempts to open the file via `Deno.open` and returns its `.readable` stream property.

```typescript
const getContent = async (path: string) => {
  try {
    if (isDir(path)) {
      return null
    }

    const file = await open(path)
    return file.readable
  } catch (e) {
    if (!(e instanceof errors.NotFound)) {
      console.warn(`${e}`)
    }
    return null
  }
}
const isDir = (path: string) => {
  let isDir
  try {
    const stat = lstatSync(path)
    isDir = stat.isDirectory
  } catch {}
  return isDir
}
```

Sources: [src/adapter/deno/serve-static.ts:12-34](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/deno/serve-static.ts#L12-L34)

> [!WARNING]
> Any caught exception during file opening that is not an instance of `Deno.errors.NotFound` is logged via `console.warn`, whereas `NotFound` errors are silently ignored to allow clean fallback handling by downstream middleware.

Sources: [src/adapter/deno/serve-static.ts:20-25](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/deno/serve-static.ts#L20-L25)

## WebSocket upgrade integration

### Upgrade Mechanism and Subprotocol Negotiation

The `upgradeWebSocket` helper wraps Hono's `defineWebSocketHelper` to handle full-duplex WebSocket connections in Deno. It first inspects the incoming request headers; if the `upgrade` header does not equal `'websocket'`, the helper returns `undefined` to let standard HTTP request handling proceed.

```typescript
export const upgradeWebSocket: UpgradeWebSocket<WebSocket, Deno.UpgradeWebSocketOptions> =
  defineWebSocketHelper(async (c, events, options) => {
    if (c.req.header('upgrade') !== 'websocket') {
      return
    }

```

Sources: [src/adapter/deno/websocket.ts:4-9](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/deno/websocket.ts#L4-L9)

To ensure browser compatibility, the helper extracts the first requested subprotocol from the `sec-websocket-protocol` header. Echoing this subprotocol back prevents connection rejections in strict clients such as Google Chrome when subprotocols are negotiated.

```typescript
// Echo the negotiated subprotocol back to the client. Browsers (e.g. Chrome)
// reject the connection when a subprotocol was requested but the response is
// missing the `Sec-WebSocket-Protocol` header.
const subprotocol = c.req.header('sec-websocket-protocol')?.split(',')[0]?.trim()

const { response, socket } = Deno.upgradeWebSocket(c.req.raw, {
  ...(subprotocol ? { protocol: subprotocol } : {}),
  ...options,
})
```

Sources: [src/adapter/deno/websocket.ts:10-18](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/deno/websocket.ts#L10-L18)

> [!NOTE]
> The `Deno.upgradeWebSocket` function accepts `req` along with `UpgradeWebSocketOptions`, returning an object containing both the HTTP `response` and the underlying `socket`.

Sources: [src/adapter/deno/websocket.ts:15-18](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/deno/websocket.ts#L15-L18), [src/adapter/deno/deno.d.ts:49-55](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/deno/deno.d.ts#L49-L55)

### WSContext Event Bridging

Once the native socket is established, `upgradeWebSocket` instantiates a `WSContext<WebSocket>` wrapper that maps property getters and methods onto the Deno socket. It wires event handlers `onopen`, `onmessage`, `onclose`, and `onerror` directly to the corresponding callbacks defined in the event parameter object.

```typescript
const wsContext: WSContext<WebSocket> = new WSContext({
  close: (code, reason) => socket.close(code, reason),
  get protocol() {
    return socket.protocol
  },
  raw: socket,
  get readyState() {
    return socket.readyState as WSReadyState
  },
  url: socket.url ? new URL(socket.url) : null,
  send: (source) => socket.send(source),
})
socket.onopen = (evt) => events.onOpen?.(evt, wsContext)
socket.onmessage = (evt) => events.onMessage?.(evt, wsContext)
socket.onclose = (evt) => events.onClose?.(evt, wsContext)
socket.onerror = (evt) => events.onError?.(evt, wsContext)

return response
```

Sources: [src/adapter/deno/websocket.ts:20-37](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/deno/websocket.ts#L20-L37)

The configuration options accepted by Deno's WebSocket upgrade routine are typed through `Deno.UpgradeWebSocketOptions`, supporting protocol selection and idle timeout configuration.

| Option | Type | Default | Purpose |
| --- | --- | --- | --- |
| `protocol` | `string` | — | Sets the `.protocol` property on the client-side WebSocket to match requested subprotocols |
| `idleTimeout` | `number` | `30` | Maximum seconds without a pong frame before connection is deemed unhealthy and closed; set to `0` to disable |

Sources: [src/adapter/deno/deno.d.ts:60-78](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/deno/deno.d.ts#L60-L78)

## Extracting connection network metadata

### Connection Info Helper Signature and Environment Binding

The `getConnInfo` helper extracts remote client connection metadata from the [execution context](https://www.doc0.dev/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/technical/core-engine/execution-context) in Deno environments. It conforms to the `GetConnInfo` type definition and reads `remoteAddr` directly from the environment bindings property `c.env`.

```typescript
import type { GetConnInfo } from '../../helper/conninfo'

/**
 * Get conninfo with Deno
 * @param c Context
 * @returns ConnInfo
 */
export const getConnInfo: GetConnInfo = (c) => {
  const { remoteAddr } = c.env
  return {
    remote: {
      address: remoteAddr.hostname,
      port: remoteAddr.port,
      transport: remoteAddr.transport,
    },
  }
```

Sources: [src/adapter/deno/conninfo.ts:1-16](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/deno/conninfo.ts#L1-L16)

### Remote Address Mapping

The function returns a structured `ConnInfo` object containing a nested `remote` object. It maps property values from the Deno `remoteAddr` instance to standard address fields.

| Field | Source Property | Type / Description |
| --- | --- | --- |
| `address` | `remoteAddr.hostname` | Remote IP address or hostname of the connected client |
| `port` | `remoteAddr.port` | Network port number used by the client connection |
| `transport` | `remoteAddr.transport` | Underlying transport protocol (`tcp` or `udp`) |

Sources: [src/adapter/deno/conninfo.ts:8-16](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/deno/conninfo.ts#L8-L16)

> [!NOTE]
> `getConnInfo` assumes that `c.env` provides a populated `remoteAddr` object with `hostname`, `port`, and `transport` properties matching Deno's network address structure.

Sources: [src/adapter/deno/conninfo.ts:8-15](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/deno/conninfo.ts#L8-L15)

## Static site generation with Deno

### File System Module Integration

The `hono/deno` adapter integrates with static site generation by wiring Deno native file system APIs into Hono's core SSG framework. The `denoFileSystemModule` object satisfies the `FileSystemModule` interface by implementing file writing and directory creation primitives.

```typescript
export const denoFileSystemModule: FileSystemModule = {
  writeFile: async (path, data) => {
    const uint8Data =
      typeof data === 'string' ? new TextEncoder().encode(data) : new Uint8Array(data)
    await Deno.writeFile(path, uint8Data)
  },
  mkdir: async (path, options) => {
    return Deno.mkdir(path, { recursive: options?.recursive ?? false })
  },
}
```

Sources: [src/adapter/deno/ssg.ts:9-18](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/deno/ssg.ts#L9-L18)

When `writeFile` is invoked, it checks whether the provided data is a string; if so, it encodes the text into a `Uint8Array` using `TextEncoder`, otherwise it wraps or casts the input data as a `Uint8Array` before calling `Deno.writeFile`. The `mkdir` method forwards directory creation requests to `Deno.mkdir`, defaulting the recursive flag to `false` if options are omitted.

```typescript
writeFile: async (path, data) => {
  const uint8Data =
    typeof data === 'string' ? new TextEncoder().encode(data) : new Uint8Array(data)
  await Deno.writeFile(path, uint8Data)
},
mkdir: async (path, options) => {
  return Deno.mkdir(path, { recursive: options?.recursive ?? false })
},
```

Sources: [src/adapter/deno/ssg.ts:10-17](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/deno/ssg.ts#L10-L17)

> [!NOTE]
> Both `denoFileSystemModule` and the `toSSG` export are marked as experimental features whose APIs may change in future releases.

Sources: [src/adapter/deno/ssg.ts:4-8](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/deno/ssg.ts#L4-L8), [src/adapter/deno/ssg.ts:20-24](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/deno/ssg.ts#L20-L24)

### SSG Execution Function

The `toSSG` adapter function matches the `ToSSGAdaptorInterface` signature, taking a Hono application instance and generation options, and delegating execution to the base `toSSG` utility bundled with `denoFileSystemModule`.

```typescript
export const toSSG: ToSSGAdaptorInterface = async (app, options) => {
  return baseToSSG(app, denoFileSystemModule, options)
}
```

Sources: [src/adapter/deno/ssg.ts:25-27](https://github.com/blade47/hono/blob/e50df01453e71b071c3e6136b161b160b9fdf916/src/adapter/deno/ssg.ts#L25-L27)

## Related

- [WebSocket Support](https://www.doc0.dev/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/technical/helpers-and-tooling/websocket-support)
- [Static File Serving](https://www.doc0.dev/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/technical/helpers-and-tooling/static-file-serving)


## Sitemap

See the full [sitemap](https://www.doc0.dev/docs/552ca36e-f67e-41c3-a07a-def9bd9551b0/llms.txt) for all pages in this wiki.
