Edge Framework

Hono

Hono é um framework web ultrafast construído sobre os objetos padrão Request e Response. Escreva uma vez, execute no Cloudflare Workers, Deno, Bun ou Node, com tipos end-to-end através de RPC.

intermediate14 min readUpdated 16 de set. de 2026
index.ts
ts
// index.ts
import { Hono } from "hono";
import { cors } from "hono/cors";
import { logger } from "hono/logger";

type Bindings = { KV: KVNamespace; JWT_SECRET: string };

const app = new Hono<{ Bindings: Bindings }>();

app.use("*", logger());
app.use("/api/*", cors());

app.get("/", (c) => c.text("Hello from the edge"));

app.get("/api/users/:id", async (c) => {
  const id = c.req.param("id");
  const user = await c.env.KV.get(`user:${id}`, "json");
  if (!user) return c.json({ error: "not_found" }, 404);
  return c.json(user);
});

export default app;
Lançado
2021
Executa em
Workers, Deno, Bun, Node
Estilo
Minimalista, web-standard
Ideia central
Request e Response
Linguagem
TypeScript
Versão
4.x

Por que importa

Por que runtimes de edge amam o Hono

Ultrafast em qualquer runtime

Um roteador minúsculo sem dependências de Node inicia em milissegundos e quase não adiciona nada ao cold start, o que é crucial em serverless e na edge.

Uma base de código, múltiplas plataformas

O mesmo app roda em Cloudflare Workers, Deno Deploy, Bun, Vercel e Node. A portabilidade é o objetivo do design, não um pensamento posterior.

Tipos end-to-end com RPC

Exporte um tipo de rota e o cliente infere cada caminho, parâmetro e resposta. Sem geração de código e sem tipos de API escritos à mão.

O panorama completo

As três ideias por trás do Hono

Fale a linguagem de Request e Response da plataforma web, componha comportamentos com middleware e infira tipos do cliente diretamente das rotas do servidor.

Web standards

Portátil

Handlers recebem um Request padrão e retornam um Response, então o framework adiciona roteamento e helpers sem inventar novas primitivas.

Middleware

Compor

Pequenas funções async executam antes ou depois do handler e podem ler e escrever no contexto.

RPC

Inferir

A árvore de rotas é um tipo, então o cliente e o servidor compartilham uma única fonte de verdade para formatos e códigos de status.

HTML5 de uma olhada

O que vem na caixa

Roteamento

Caminhos no estilo Express com parâmetros, wildcards e grupos de rotas.

Middleware

app.use encadeia funções async com um objeto de contexto compartilhado.

Contexto

c.req lê a entrada e c.json, c.text e c.html escrevem a saída.

Middleware nativo

cors, logger, bearerAuth, cache, etag e secureHeaders já vêm no core.

Validadores

Validadores nativos de zod e valibot tipam o corpo parseado.

Adaptadores

Sirva o mesmo app em Workers, Node, Deno, Bun e mais.

O guia completo

Hono: Tudo que voce precisa saber

O que é Hono?

Hono é um framework web pequeno e rápido construído sobre a Web Platform. Em vez de inventar seus próprios objetos de requisição e resposta, ele utiliza as classes padrão Request e Response que navegadores, Cloudflare Workers, Deno e Bun fornecem. Sobre essa base, ele adiciona roteamento, middleware e um objeto de contexto, e nada mais do que você não solicite.

O nome significa “chama” em japonês, e o projeto foca totalmente em velocidade: um núcleo minúsculo, sem dependências integradas do Node e um roteador projetado para cold starts. Essa combinação tornou o Hono a escolha padrão para APIs de edge, onde cada milissegundo de inicialização impacta cada requisição. Como o contrato do runtime é o padrão web, a mesma aplicação também roda em Node, portanto, você nunca fica preso a um único ecossistema.

Roteamento baseado em padrões web

O roteamento parece deliberadamente familiar. Um método e um caminho mapeiam para um handler, parâmetros utilizam :name e wildcards utilizam *.

import { Hono } from "hono";

const app = new Hono();

app.get("/", (c) => c.text("Hello"));
app.get("/posts", (c) => c.json([]));
app.get("/posts/:id", (c) => c.json({ id: c.req.param("id") }));
app.post("/posts", (c) => c.json({ created: true }, 201));

Os routers podem ser divididos em sub-apps e montados, que é a forma como serviços maiores se mantêm organizados:

import { Hono } from "hono";

const api = new Hono();
api.get("/users", listUsers);
api.get("/users/:id", getUser);

app.route("/api", api);

Todo handler retorna um Response. Os helpers de contexto — c.json, c.text, c.html, c.redirect, c.body — constroem a resposta correta com headers e status, e você sempre pode retornar um new Response(...) puro quando precisar de controle total.

O objeto context

O único argumento do handler é o context, convencionalmente nomeado como c. Ele contém a requisição, os helpers de resposta e um local para armazenar valores para a requisição atual.

app.post("/posts", async (c) => {
  const id = c.req.param("id");            // path parameter
  const page = c.req.query("page");        // query string
  const body = await c.req.json();         // parsed body
  const token = c.req.header("authorization");
  c.set("requestId", crypto.randomUUID()); // per-request store
  return c.json({ id, page, body, token });
});

c.env expõe os bindings de runtime: variáveis de ambiente, namespaces KV, bancos de dados D1 e buckets R2 no Workers. c.set e c.get compartilham valores entre middleware e handlers, e c.var fornece acesso tipado a eles. Tudo o que você precisa para uma requisição reside em um único objeto, o que torna a composição de middleware simples e direta.

Middleware

Middleware é uma função assíncrona que recebe o contexto e next. Chame await next() para continuar a cadeia, ou retorne antecipadamente para interrompê-la (short-circuit).

import { createMiddleware } from "hono/factory";

export const timing = createMiddleware(async (c, next) => {
  const start = performance.now();
  await next();
  c.header("Server-Timing", `app;dur=${performance.now() - start}`);
});

app.use("*", timing);

O helper createMiddleware adiciona inferência de tipos, e app.use aceita um padrão de caminho para que o middleware seja executado apenas onde for necessário. A ordem de registro é a ordem de execução, exatamente como no Express.

O Hono traz um conjunto útil de middleware no core:

  • cors para headers de cross-origin.
  • logger para log de requisições.
  • bearerAuth e basicAuth para autenticação.
  • cache para cache de resposta em edge.
  • etag, compress e secureHeaders para higiene de HTTP.
  • csrf para proteção contra cross-site request forgery.
import { cors } from "hono/cors";
import { logger } from "hono/logger";
import { bearerAuth } from "hono/bearer-auth";

app.use("*", logger());
app.use("/api/*", cors());
app.use("/admin/*", bearerAuth({ token: c.env.ADMIN_TOKEN }));

Como estes são middlewares simples, eles se compõem com os seus próprios e com qualquer outra coisa no ecossistema.

Validação e respostas tipadas

O Hono possui validadores nativos para Zod e Valibot. Eles analisam um alvo (json, query, param, form), rejeitam entradas inválidas com um 400 e fornecem ao handler um valor tipado.

import { zValidator } from "@hono/zod-validator";
import { z } from "zod";

const CreatePost = z.object({
  title: z.string().min(1),
  body: z.string(),
});

app.post("/posts", zValidator("json", CreatePost), (c) => {
  const post = c.req.valid("json");
  return c.json({ id: crypto.randomUUID(), ...post }, 201);
});

O valor analisado é tipado, portanto c.req.valid("json") possui exatamente o formato do schema. Você pode customizar a resposta de falha com um hook, que é a maneira de manter os corpos de erro consistentes com o restante da sua API.

RPC: tipos end-to-end sem codegen

O modo RPC é o recurso de maior destaque do Hono. Se você exportar o tipo do seu app, o cliente consegue inferir cada rota e resposta diretamente dele.

// server.ts
const route = app
  .get("/api/users", (c) => c.json([{ id: "1", name: "Ada" }]))
  .post(
    "/api/users",
    zValidator("json", CreateUser),
    (c) => c.json({ id: crypto.randomUUID(), ...c.req.valid("json") }, 201),
  );

export type AppType = typeof route;
// client.ts
import { hc } from "hono/client";
import type { AppType } from "./server";

const client = hc<AppType>("https://api.example.com");

const res = await client.api.users.$post({
  json: { name: "Ada", email: "[email protected]" },
});

if (res.ok) {
  const user = await res.json(); // typed from the server handler
}

Não há arquivo de schema para manter sincronizado nem cliente gerado. Altere uma rota no servidor e o cliente falhará na compilação até que seja atualizado, transformando o “API drift” em um erro de build. Isso funciona melhor em um monorepo ou em um pacote compartilhado onde ambos os lados podem importar o tipo.

Renderizando HTML e JSX

O Hono pode servir HTML diretamente, seja como strings ou através de seu próprio runtime JSX. O JSX foi projetado para renderização no servidor: sem virtual DOM, sem hidratação, apenas saída de string.

import { Hono } from "hono";
import { html } from "hono/html";

const app = new Hono();

app.get("/", (c) => {
  return c.html(
    html`<!doctype html>
      <html>
        <body><h1>Hello from ${c.req.query("name") ?? "the edge"}</h1></body>
      </html>`,
  );
});

Para uma experiência de templating mais completa, hono/jsx fornece componentes e layouts, e helpers como html lidam com o escape de caracteres. É uma ótima escolha para páginas renderizadas no servidor e para fragmentos de HTML retornados por uma edge API.

Um único codebase, múltiplos runtimes

A portabilidade é o objetivo. O código da aplicação nunca importa um módulo específico de runtime; apenas o ponto de entrada (entry point) muda.

// Node
import { serve } from "@hono/node-server";
import app from "./app";

serve({ fetch: app.fetch, port: 3000 });
// Cloudflare Workers
export default app;
// Bun
export default { port: 3000, fetch: app.fetch };

O mesmo objeto app atende aos três. Isso significa que um serviço prototipado no Node pode migrar para Workers por questões de custo ou latência sem a necessidade de reescrita, e um app de Workers pode rodar em uma suíte de testes local através do adaptador de Node.

Fazendo o deploy na edge

No Cloudflare Workers, o deploy é feito através de um comando do Wrangler e um pequeno arquivo de configuração.

pnpm add -D wrangler
npx wrangler deploy
# wrangler.toml
name = "api"
main = "src/index.ts"
compatibility_date = "2026-09-01"

[[kv_namespaces]]
binding = "KV"
id = "xxxxxxxxxxxxxxxx"

Os Bindings definidos aqui aparecem no c.env, totalmente tipados se você os passar como o generic Bindings para new Hono<{ Bindings: Bindings }>(). Vercel, Deno Deploy e Netlify possuem adaptadores documentados, e o mesmo app geralmente é implantado com a alteração de apenas uma linha de entrada. Lembre-se das restrições de runtime: limite tarefas que exijam muito da CPU, evite conexões de banco de dados de longa duração e utilize armazenamento nativo de edge.

Melhores práticas

  • Tipagem de bindings e variáveis através de generics Hono para que c.env e c.get sejam seguros.
  • Valide cada entrada com zValidator e mantenha o schema próximo à rota.
  • Componha middleware com createMiddleware e defina o escopo com um padrão de caminho (path pattern).
  • Exporte AppType e utilize hc no cliente em vez de tipos escritos manualmente.
  • Mantenha os handlers enxutos; mova a lógica reutilizável para funções simples ou serviços.
  • Retorne os códigos de status corretos com c.json(body, status) em vez de sempre retornar 200.
  • Projete para o runtime: sem sistema de arquivos, CPU limitada e armazenamento edge-native.
  • Teste com app.request() para que os testes não precisem de servidor ou rede.
test("GET /posts", async () => {
  const res = await app.request("/posts");
  expect(res.status).toBe(200);
});

Erros comuns

  • Assumir que bibliotecas de Node funcionam em Workers; built-ins e addons nativos frequentemente não funcionam.
  • Manter conexões de banco de dados abertas em um edge runtime em vez de usar HTTP ou bindings.
  • Esquecer de retornar a resposta, fazendo com que o handler resolva para undefined.
  • Registrar cors após as rotas às quais ele deveria ser aplicado.
  • Ler c.req.json() mais de uma vez, o que falha porque o stream do corpo é consumido.
  • Pular a validação e confiar em strings de c.req.query().
  • Deixar AppType divergir ao escrever tipos de cliente manualmente em vez de importá-lo.
  • Executar tarefas pesadas de CPU em uma requisição e atingir o limite de tempo do runtime.

Próximos passos

O Hono traz o modelo de roteamento e middleware que você já conhece do Express para runtimes que sequer existiam quando o Express foi escrito. Se você precisa de um servidor Node de longa duração com validação baseada em schema, compare-o com o Fastify. Para entender os runtimes que o Hono suporta, leia o guia de fundamentos do Node.js e, quando estiver pronto para colocar em produção, o roadmap de backend cobre a implantação na nuvem. Depois, construa uma API pequena, faça o deploy no Workers e consuma-a com um cliente RPC tipado.

Na pratica

Rotas, middleware, validação e RPC

Um serviço Hono sob quatro ângulos: um roteador, um middleware reutilizável, um handler validado e um cliente tipado.

routes/users.ts
import { Hono } from "hono";

const users = new Hono();

users.get("/", (c) => c.json({ users: [] }));

users.get("/:id", async (c) => {
  const id = c.req.param("id");
  const user = await getUser(id);
  if (!user) return c.json({ error: "not_found" }, 404);
  return c.json(user);
});

export default users;

Trade-offs

O Hono é o framework certo para você?

Hono é otimizado para padrões, portabilidade e cold starts. Esse formato é ideal na edge e menos relevante em um servidor Node de longa duração.

Strengths

  • Verdadeiramente portátil

    O mesmo código roda inalterado em Workers, Deno, Bun, Node e diversas plataformas, mantendo suas opções abertas conforme a hospedagem evolui.

  • Minúsculo e rápido

    O core tem poucos kilobytes e nenhuma dependência nativa de Node, então o bundle fica limpo e inicia instantaneamente.

  • Tipos sem codegen

    O modo RPC dá ao cliente conhecimento total de rotas e respostas diretamente dos tipos do servidor, detectando divergências na API em tempo de compilação.

Trade-offs

  • O ecossistema é mais jovem

    Hono tem uma biblioteca de middleware crescente, mas nada comparado às décadas de pacotes do Express. Você escreverá mais código de integração por conta própria.

  • Armazenamento na edge é diferente

    Workers não possuem sistema de arquivos local e têm tempo de CPU limitado. Você deve projetar usando KV, D1 ou R2 em vez de uma conexão de banco de dados tradicional.

  • Nem toda biblioteca Node funciona

    Código que depende de módulos nativos do Node pode não rodar no runtime do Workers. No Node via adaptador funciona bem, mas a portabilidade não é automática.

Perguntas frequentes

Perguntas frequentes

Keep learning

Related topics from the roadmap.

$ comecar a aprender

Pronto para aprender Hono?

Nosso tutorial interativo te guia por Hono passo a passo — com quizzes e codigo real que voce pode executar no navegador.