The first app
A Hono app is an object created with new Hono(). You add routes to it and then pass its app.fetch function to a server. On Node.js the server is started by the serve() function from the @hono/node-server package.
The entry file
Right after creating the project, src/index.ts looks like this:
// src/index.ts
import { serve } from '@hono/node-server'
import { Hono } from 'hono'
const app = new Hono()
app.get('/', (c) => {
return c.text('Hello Hono!')
})
serve({
fetch: app.fetch,
port: 3000,
}, (info) => {
console.log(`Server is running on http://localhost:${info.port}`)
})Piece by piece:
| Line | What it does |
|---|---|
new Hono() | creates the app |
app.get('/', ...) | adds a route for a GET request to / |
c | the context — an object with the request and methods for the response |
c.text(...) | creates a plain-text response |
serve(...) | starts a Node.js HTTP server and passes every request to app.fetch |
The second argument of serve() is called when the server is ready and prints the address to the terminal.
The first JSON
Hono is most often used for APIs, so add a route that returns the list of blog posts:
// src/index.ts
const posts = [
{ id: 1, title: 'First post', body: 'Hello, world!' },
{ id: 2, title: 'Second post', body: 'Learning Hono.' },
]
app.get('/posts', (c) => {
return c.json(posts)
})Put this code before the serve() call. The c.json() method turns the array into a JSON string and sets the Content-Type: application/json header itself. Open http://localhost:3000/posts and the browser shows an array of two posts.
A request from the terminal
APIs are handy to check with curl:
curl http://localhost:3000/postsThe terminal prints the same JSON. The -i flag also shows the response headers:
curl -i http://localhost:3000/postsThe first line of the response is HTTP/1.1 200 OK, and the headers include content-type: application/json.
Restart on changes
npm run dev watches your files. Change the text in c.text(), save the file and refresh the page — the new text appears without a manual restart.
Port
The port is set in serve(). To change it without editing the code, read it from an environment variable:
// src/index.ts
const port = Number(process.env.PORT ?? 3000)
serve({ fetch: app.fetch, port })Environment variables get their own lesson later.
Common mistake
Running npm run dev a second time in another terminal while the first one is still running. The second process crashes with EADDRINUSE: port 3000 is already taken. The server should run as a single instance — stop the extra one with Ctrl+C or set a different port.