Skip to Content
getting-startedHello World

Last Updated: 3/9/2026


Hello World

Let’s build your first Hono application from scratch and understand what’s happening.

Prerequisites

Before you start, complete the Quick Start to set up your development environment.

The Simplest Hono App

Create a file called index.ts:

import { Hono } from 'hono' const app = new Hono() app.get('/', (c) => { return c.text('Hello Hono!') }) export default app

This is a complete web application. Let’s break it down.

Understanding the Code

Import Hono

import { Hono } from 'hono'

Hono is the main class. Everything starts here.

Create an App Instance

const app = new Hono()

This creates your application. You can create multiple apps and compose them together.

Define a Route

app.get('/', (c) => { return c.text('Hello Hono!') })

This registers a route handler:

  • app.get() — Handle GET requests
  • '/' — The path to match
  • (c) => { ... } — The handler function
  • c — The Context object (more on this below)
  • c.text('Hello Hono!') — Return a text response

Export the App

export default app

Different runtimes expect different exports. Cloudflare Workers and Bun use this pattern. For Node.js, you’d start the server differently (see Node.js deployment).

The Context Object

The c parameter is a Context object. It’s your interface to the request and response:

app.get('/hello', (c) => { // Access the request const userAgent = c.req.header('User-Agent') // Set response headers c.header('X-Custom-Header', 'Hello') // Return different response types return c.text('Plain text') // return c.json({ message: 'JSON response' }) // return c.html('<h1>HTML response</h1>') })

Learn more in Context API.

Different Response Types

Text Response

app.get('/text', (c) => { return c.text('Hello Hono!') })

Returns Content-Type: text/plain.

JSON Response

app.get('/json', (c) => { return c.json({ ok: true, message: 'Hello Hono!', }) })

Returns Content-Type: application/json.

HTML Response

app.get('/html', (c) => { return c.html('<h1>Hello Hono!</h1>') })

Returns Content-Type: text/html.

Custom Status Code

app.post('/posts', (c) => { return c.json({ message: 'Created!' }, 201) })

The second argument sets the HTTP status code.

Custom Headers

app.get('/custom', (c) => { return c.json( { message: 'Hello' }, 200, { 'X-Custom': 'My header' } ) })

The third argument sets custom headers.

HTTP Methods

Handle different HTTP methods:

app.get('/posts', (c) => c.text('List posts')) // GET app.post('/posts', (c) => c.text('Create post')) // POST app.put('/posts/:id', (c) => c.text('Update post')) // PUT app.delete('/posts/:id', (c) => c.text('Delete')) // DELETE

Path Parameters

Capture values from the URL:

app.get('/posts/:id', (c) => { const id = c.req.param('id') return c.text(`Post ID: ${id}`) })

Visit /posts/123 → “Post ID: 123”

Multiple Parameters

app.get('/posts/:postId/comments/:commentId', (c) => { const { postId, commentId } = c.req.param() return c.text(`Post ${postId}, Comment ${commentId}`) })

Query Parameters

Access query strings:

app.get('/search', (c) => { const query = c.req.query('q') const page = c.req.query('page') ?? '1' return c.text(`Search: ${query}, Page: ${page}`) })

Visit /search?q=hono&page=2 → “Search: hono, Page: 2”

Request Body

Handle POST data:

app.post('/posts', async (c) => { const body = await c.req.json() return c.json({ message: 'Created!', data: body, }, 201) })

Note: Use await when accessing the request body.

Raw Response

You can also return a raw Response object:

app.get('/raw', () => { return new Response('Raw response', { status: 200, headers: { 'Content-Type': 'text/plain' }, }) })

This is useful when you need full control.

What’s Next

Learn routing: Read Basic Concepts to understand request/response flow and middleware.

Add middleware: Check out the Middleware Guide to add authentication, logging, and more.

Go deeper: Explore the Routing guide for advanced patterns like wildcards and regex.

Deploy: See Deployment guides for your platform.