Deno is a modern, secure runtime for JavaScript and TypeScript. Hono works seamlessly with Deno with full TypeScript support out of the box.
Quick Start
Create a new Hono project for Deno:
deno run -A npm:create-hono@latest my-app
Select “deno” as your template when prompted.
Installation
No installation needed! Import Hono directly from a CDN:
import { Hono } from 'https://deno.land/x/hono/mod.ts'
Or use npm specifiers:
import { Hono } from 'npm:hono@latest'
Basic Usage
Create your application in main.ts:
import { Hono } from 'https://deno.land/x/hono/mod.ts'
const app = new Hono()
app.get('/', (c) => c.text('Hello Deno!'))
app.get('/api/hello', (c) => {
return c.json({ message: 'Hello from Deno!' })
})
Deno.serve(app.fetch)
Deno’s Deno.serve() expects a fetch function. Pass app.fetch directly.
Running Your App
deno run --allow-net main.ts
Or with custom port:
import { Hono } from 'https://deno.land/x/hono/mod.ts'
const app = new Hono()
app.get('/', (c) => c.text('Hello Deno!'))
Deno.serve({ port: 3000 }, app.fetch)
Adapter Features
The Deno adapter provides several utilities:
Static Files
Serve static files from a directory:
import { Hono } from 'https://deno.land/x/hono/mod.ts'
import { serveStatic } from 'https://deno.land/x/hono/adapter/deno/index.ts'
const app = new Hono()
app.use('/static/*', serveStatic({ root: './' }))
app.use('/favicon.ico', serveStatic({ path: './favicon.ico' }))
app.get('/', (c) => c.text('Hello!'))
Deno.serve(app.fetch)
WebSocket Support
Upgrade HTTP connections to WebSocket:
import { Hono } from 'https://deno.land/x/hono/mod.ts'
import { upgradeWebSocket } from 'https://deno.land/x/hono/adapter/deno/index.ts'
const app = new Hono()
app.get(
'/ws',
upgradeWebSocket((c) => {
return {
onMessage(event, ws) {
console.log(`Message from client: ${event.data}`)
ws.send('Hello from server!')
},
onClose: () => {
console.log('Connection closed')
},
}
})
)
Deno.serve(app.fetch)
Connection Info
Get connection information including IP address:
import { Hono } from 'https://deno.land/x/hono/mod.ts'
import { getConnInfo } from 'https://deno.land/x/hono/adapter/deno/index.ts'
const app = new Hono()
app.get('/info', (c) => {
const info = getConnInfo(c)
return c.json({
remote: info.remote,
})
})
Deno.serve(app.fetch)
Static Site Generation (SSG)
Generate static files from your Hono app:
import { Hono } from 'https://deno.land/x/hono/mod.ts'
import { toSSG } from 'https://deno.land/x/hono/adapter/deno/index.ts'
const app = new Hono()
app.get('/', (c) => c.html('<h1>Home</h1>'))
app.get('/about', (c) => c.html('<h1>About</h1>'))
// Generate static files
toSSG(app, { dir: './dist' })
Deno Deploy
Deploy your Hono app to Deno Deploy’s edge network.
Create your app
Create a Hono application:import { Hono } from 'https://deno.land/x/hono/mod.ts'
const app = new Hono()
app.get('/', (c) => c.text('Hello Deno Deploy!'))
Deno.serve(app.fetch)
Deploy with deployctl
Install and use deployctl:deno install -A --no-check -r -f https://deno.land/x/deploy/deployctl.ts
deployctl deploy --project=my-project main.ts
Deploy via Git
Alternatively, connect your Git repository:
- Go to Deno Deploy
- Click “New Project”
- Connect your GitHub repository
- Select the entry file (e.g.,
main.ts)
- Deploy
Using Deno KV
Integrate with Deno’s built-in key-value database:
import { Hono } from 'https://deno.land/x/hono/mod.ts'
const app = new Hono()
const kv = await Deno.openKv()
app.get('/kv/:key', async (c) => {
const key = c.req.param('key')
const result = await kv.get([key])
if (!result.value) {
return c.notFound()
}
return c.json({ value: result.value })
})
app.post('/kv/:key', async (c) => {
const key = c.req.param('key')
const body = await c.req.json()
await kv.set([key], body.value)
return c.json({ message: 'Saved' })
})
Deno.serve(app.fetch)
Environment Variables
Access environment variables:
import { Hono } from 'https://deno.land/x/hono/mod.ts'
const app = new Hono()
app.get('/config', (c) => {
const apiKey = Deno.env.get('API_KEY')
return c.json({ configured: !!apiKey })
})
Deno.serve(app.fetch)
Run with environment variables:
API_KEY=secret deno run --allow-net --allow-env main.ts
Or use a .env file with a library like dotenv.
Configuration
Create a deno.json configuration file:
{
"tasks": {
"dev": "deno run --allow-net --allow-read --allow-env --watch main.ts",
"start": "deno run --allow-net --allow-read --allow-env main.ts"
},
"imports": {
"hono": "https://deno.land/x/hono/mod.ts",
"hono/": "https://deno.land/x/hono/"
},
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "hono/jsx"
}
}
Run tasks:
deno task dev # Development with watch mode
deno task start # Production
Using JSX
Hono’s JSX works great with Deno:
import { Hono } from 'https://deno.land/x/hono/mod.ts'
import { jsx } from 'https://deno.land/x/hono/middleware.ts'
const app = new Hono()
app.get('/', (c) => {
return c.html(
<html>
<head>
<title>Hono + Deno</title>
</head>
<body>
<h1>Hello from Deno!</h1>
</body>
</html>
)
})
Deno.serve(app.fetch)
Best Practices
Define imports in deno.json for cleaner import statements.
Use deno.lock to lock dependency versions for reproducible builds.
Only grant the permissions your app needs (e.g., --allow-net, --allow-read).
Use Deno KV for built-in, distributed key-value storage.
Development Features
Watch Mode
Auto-reload on file changes:
deno run --allow-net --watch main.ts
Type Checking
Deno type-checks TypeScript by default. Skip checking for faster startup:
deno run --allow-net --no-check main.ts
Testing
Write tests using Deno’s built-in test runner:
import { assertEquals } from "https://deno.land/std/assert/mod.ts"
import app from "./main.ts"
Deno.test("GET /", async () => {
const res = await app.request('http://localhost/')
assertEquals(res.status, 200)
assertEquals(await res.text(), 'Hello Deno!')
})
Run tests:
Resources
Deno Manual
Official Deno documentation
Deno Deploy
Deploy to the edge with Deno Deploy