Usar Hono no Node.js permite criar APIs leves com uma interface baseada em Web Standards. O mesmo estilo de código pode rodar em Node.js, runtimes edge, serverless, Bun e Deno, desde que as dependências e integrações sejam compatíveis.
Hono oferece roteamento, middleware, validação, RPC tipado, CORS, JWT, secure headers, streaming e helpers. A portabilidade é uma vantagem, mas exige evitar APIs específicas da plataforma quando o objetivo é executar em vários runtimes. Também é necessário configurar body limits, autenticação, autorização, timeouts e shutdown para produção.
Neste guia, você aprenderá a instalar Hono no Node.js, criar rotas e middleware, trabalhar com context, validar entradas, integrar serviços, proteger APIs, fazer streaming, testar e preparar o deploy.
O que é Hono?
Hono é um framework web pequeno e baseado em padrões da Web. A documentação oficial do Hono apresenta suporte a Node.js e outros runtimes, middleware e RPC. A documentação da MDN sobre Request descreve uma das interfaces utilizadas pelo framework.
Quando usar?
- APIs leves;
- aplicações edge;
- serverless;
- proxies;
- BFFs;
- serviços multi-runtime;
- projetos TypeScript;
- bibliotecas que expõem HTTP.
Quando avaliar outra opção?
- ecossistema depende de middleware Express específico;
- aplicação usa módulos nativos incompatíveis com edge;
- equipe precisa das convenções extensas do NestJS;
- plugins do Fastify são essenciais;
- o runtime alvo exige integração não suportada.
Compare com Fastify com Node.js e NestJS no Node.js.
Criando um projeto
npm create hono@latestSelecione o template Node.js ou configure manualmente.
Instalação manual
npm install hono @hono/node-serverServidor básico
import { Hono } from 'hono';
import { serve } from '@hono/node-server';
const app = new Hono();
app.get('/', c => c.json({
message: 'Hono no Node.js'
}));
serve({
fetch: app.fetch,
port: Number(process.env.PORT || 3000)
});O adapter conecta o modelo Fetch do Hono ao servidor Node.js.
Context
O objeto c fornece request, response, variáveis, headers e helpers:
app.get('/users/:id', c => {
const id = c.req.param('id');
return c.json({ id });
});Query parameters
const search = c.req.query('search');
const limit = Number(c.req.query('limit') || 20);Valide e limite valores. Converter para Number não garante inteiro, intervalo ou ausência de NaN.
Body JSON
const body = await c.req.json();O valor é desconhecido em runtime. Use schema antes de acessar campos.
Roteamento
app.get('/projects', listProjects);
app.post('/projects', createProject);
app.get('/projects/:id', getProject);
app.patch('/projects/:id', updateProject);
app.delete('/projects/:id', deleteProject);Organize handlers por domínio, não em um único arquivo.
Sub-apps
const projects = new Hono();
projects.get('/', listProjects);
projects.post('/', createProject);
app.route('/projects', projects);Sub-apps ajudam a separar módulos e aplicar middleware específico.
Middleware
app.use('*', async (c, next) => {
const startedAt = performance.now();
await next();
logger.info({
method: c.req.method,
path: c.req.routePath,
status: c.res.status,
durationMs: performance.now() - startedAt
}, 'Requisição Hono');
});Chame await next() para executar o restante da cadeia.
Request ID
Use o middleware oficial ou gere um UUID validando o header recebido. Retorne o ID na resposta e inclua nos logs.
Context variables
app.use('*', async (c, next) => {
c.set('requestId', crypto.randomUUID());
await next();
});Tipagem das variables pode ser declarada no generic do Hono.
Context tipado
type Variables = {
requestId: string;
auth: AuthContext;
};
const app = new Hono<{ Variables: Variables }>();Autenticação
const authenticate = createMiddleware(async (c, next) => {
const auth = await authService.authenticate(
c.req.header('authorization')
);
if (!auth) {
return c.json({
code: 'UNAUTHORIZED',
message: 'Autenticação necessária'
}, 401);
}
c.set('auth', auth);
await next();
});Para tokens, consulte JWT Seguro no Node.js.
Middleware JWT
Hono possui middleware JWT, mas configure algoritmo, issuer, audience e chave corretamente. Não aceite configuração padrão sem entender as claims.
Autorização
function requirePermission(permission) {
return createMiddleware(async (c, next) => {
const auth = c.get('auth');
if (!auth.permissions.includes(permission)) {
return c.json({ code: 'FORBIDDEN' }, 403);
}
await next();
});
}O handler ainda deve validar tenant e ownership do recurso. Consulte RBAC no Node.js e ABAC no Node.js.
Multi-tenancy
O tenant vem da identidade, não do body ou query. Toda chamada ao repository recebe o tenant explicitamente.
Veja Multi-Tenancy no Node.js.
Validação
Hono permite integrar validators e bibliotecas como Zod. Um exemplo conceitual:
const CreateProjectSchema = z.object({
name: z.string().min(1).max(100),
description: z.string().max(1000).optional()
}).strict();
app.post('/projects', async c => {
const input = CreateProjectSchema.parse(
await c.req.json()
);
return c.json(await projectService.create(input), 201);
});O próximo artigo desta rodada aprofunda Zod.
Validator middleware
Adapters de validação podem colocar o resultado validado no request. Rejeite campos desconhecidos quando o contrato não permite extensões.
Body limit
Use middleware de limite e configure também o proxy. JSON, formulário e multipart precisam de limites diferentes.
Consulte Multipart Upload no Node.js.
CORS
app.use('/api/*', cors({
origin: ['https://app.example.com'],
allowMethods: ['GET', 'POST', 'PATCH', 'DELETE'],
credentials: true
}));Confirme a API da versão e use allowlist. Consulte CORS em APIs Node.js.
CSRF
Quando usar cookies, habilite proteção CSRF e SameSite adequado. O middleware de CSRF deve considerar origins e métodos.
Secure Headers
Hono oferece middleware para headers. Configure de acordo com API ou aplicação HTML. Para CSP, consulte Helmet e CSP no Node.js.
Cookies
Use helpers para ler e definir cookies, mantendo:
- HttpOnly;
- Secure;
- SameSite;
- Path restrito;
- expiração no servidor.
RPC mode
Hono Client pode inferir tipos das rotas quando handlers e schemas são definidos de forma compatível.
export type AppType = typeof app;O cliente usa esse tipo para chamadas. Assim como no tRPC, a validação runtime continua obrigatória.
Contrato público
Para clientes externos, considere OpenAPI. Consulte OpenAPI com Node.js.
Respostas
return c.json({
id: project.id,
name: project.name
}, 201);Retorne DTOs e não entidades completas.
Erros
app.onError((error, c) => {
logger.error({
err: error,
requestId: c.get('requestId')
}, 'Falha na API');
return c.json({
code: 'INTERNAL_ERROR',
message: 'Erro interno',
requestId: c.get('requestId')
}, 500);
});Não exponha stack ou detalhes internos.
HTTPException
Use exceções controladas para status específicos, mas mantenha códigos de domínio estáveis.
Not found
app.notFound(c => c.json({
code: 'NOT_FOUND',
message: 'Rota não encontrada'
}, 404));Streaming
Como Hono usa Web Streams, handlers podem devolver conteúdo progressivo. Controle desconexão e backpressure.
Consulte Web Streams API no Node.js.
SSE
Server-Sent Events pode ser usado para atualizações unidirecionais. Envie heartbeat, IDs e trate reconexão.
WebSocket
O adapter e runtime determinam suporte. Consulte WebSocket no Node.js.
Proxy
Hono pode atuar como proxy, mas não construa destino diretamente de input. Aplique as defesas de SSRF no Node.js.
Cache middleware
Cacheie apenas respostas apropriadas. Dados autenticados exigem private ou no-store.
ETag
O middleware ETag ajuda em respostas condicionais. Consulte ETag e Cache HTTP no Node.js.
Compressão
Evite compressão duplicada no framework e proxy. Consulte Compressão HTTP no Node.js.
Timeout middleware
Defina prazo por rota e propague AbortSignal para downstreams. Um timeout de resposta não cancela automaticamente banco ou fetch.
Rate limiting
Use middleware externo ou implementação distribuída. Consulte Rate Limiting no Node.js.
Node.js versus edge
No Node.js, você pode usar filesystem, net e módulos nativos. No edge, APIs e limites são diferentes. Mantenha adapters de infraestrutura separados.
Ports e adapters
Defina interfaces para banco, filas e storage. O handler usa um service independente do runtime.
Variáveis de ambiente
Edge e Node.js fornecem configurações de formas diferentes. Crie uma camada de config tipada e validada.
Banco de dados
Em serverless, cuidado com pools e quantidade de conexões. Em Node.js persistente, use pool dimensionado.
Transações
Delegue a uma camada de serviço. Consulte Transações PostgreSQL no Node.js.
Logging
O logger integrado é útil em desenvolvimento. Em produção, use logs JSON com redaction.
Consulte Logs com Pino no Node.js.
Métricas
Monitore rota normalizada, status, duração, tamanho, erro, event loop e downstreams.
Tracing
Propague traceparent e crie spans para banco e fetch. Consulte OpenTelemetry no Node.js.
Health checks
Crie endpoints leves para liveness e readiness. Não use uma consulta cara em toda probe.
Graceful shutdown
O adapter Node.js retorna ou expõe o servidor HTTP conforme a integração. Capture SIGTERM, pare novas conexões e feche recursos.
Consulte Graceful Shutdown no Node.js.
Testando com app.request()
const response = await app.request('/projects', {
headers: {
authorization: `Bearer ${token}`
}
});
assert.equal(response.status, 200);Esse método testa o app sem abrir porta.
Teste de context
Confirme que request IDs e identidades ficam isolados entre chamadas concorrentes.
Teste de validação
Envie JSON inválido, campos extras, strings grandes e tipos incorretos.
Teste de autorização
Inclua sem token, permission ausente, outro tenant e recurso fora do escopo.
Teste multi-runtime
Se portabilidade é um requisito, execute uma suíte mínima em cada adapter alvo.
Teste de streaming
Cancele o cliente e confirme interrupção de trabalho e liberação de recursos.
Teste de proxy
Envie URLs privadas e redirects para localhost quando houver funcionalidade externa.
Deploy em Node.js
Compile no CI, execute como usuário não root e configure timeouts do proxy.
Deploy edge
Respeite limites de CPU, memória, tamanho do bundle e conexões do provedor.
Erros comuns
- Assumir portabilidade automática: dependências usam Node.js.
- Confiar nos tipos: input da rede não é validado.
- Context global: identidade vaza.
- Sem body limit: requisições consomem memória.
- Middleware de auth sem recurso: autorização fica incompleta.
- Proxy com URL livre: SSRF aparece.
- Logs com headers: tokens vazam.
Boas práticas
- Valide entradas em runtime.
- Use context tipado.
- Separe handlers e serviços.
- Autorize por recurso.
- Configure limits e timeouts.
- Use Web Standards quando possível.
- Isole adapters de runtime.
- Redija logs.
- Teste adapters.
- Implemente shutdown.
Conclusão
Usar Hono no Node.js oferece uma API enxuta, baseada em padrões da Web e preparada para vários runtimes. Rotas, middleware e context permanecem simples e tipados.
A portabilidade depende de separar domínio e infraestrutura, enquanto a segurança exige validação, limites e autorização. Com adapters bem definidos e testes multi-runtime, Hono permite compartilhar a mesma base sem assumir que Node.js, edge e serverless possuem as mesmas capacidades.




