Um framework web "leve" para Node.js - Hono, Koa, Polka e outros semelhantes - tem menos a ver com o tamanho do arquivo e mais com uma base diferente: em vez de envolver os objetos http.IncomingMessage/http.ServerResponse nativos do Node, esses frameworks se baseiam nas classes Padrão WebRequest e Response, as mesmas que um navegador ou um Cloudflare Worker já utilizam.
Essa única escolha se reflete em quase tudo o mais que esta seção cobre.
É por isso que o mesmo handler de rota pode ser executado no Node, na edge ou no Bun com pouca ou nenhuma alteração, por que o middleware se compõe da maneira que o faz, e por que esses frameworks tendem a vir com uma fração da árvore de dependências do Express.
Noções Básicas do Hono e Koa & Polka mostram o código; esta página é o modelo por baixo dele - o que "leve" realmente oferece, e qual o seu custo.
Frameworks leves substituem objetos de requisição/resposta específicos do Node pela API padrão Web Request/Response, que é o que os torna portáteis entre runtimes e mantém seu núcleo pequeno.
Por que Importa: O design do Express é anterior aos Padrões Web, então ele está vinculado ao módulo http do Node; essa ligação é invisível até que você tente executar o mesmo handler em um local que não seja Node, ou até que o peso das dependências comece a importar para cold starts.
Conceitos Chave:API de Padrões Web, composição de middleware (o modelo da cebola), camada de adaptador, cold start, footprint.
Quando Usar: Implantar a mesma lógica de API tanto em um servidor Node quanto em um runtime de edge/serverless, minimizar a latência de cold start, construir um serviço com uma superfície de dependência genuinamente pequena, ou simplesmente querer primitivas de roteador/middleware sem um grande ecossistema anexado.
Limitações / Trade-offs: Ecossistemas menores significam menos pacotes de middleware testados em batalha e menos respostas da comunidade; algumas APIs exclusivas do Node (sockets brutos, certos padrões de streaming) ainda precisam de uma saída da forma padrão Request/Response.
Tópicos Relacionados: Módulo http do Node, API Fetch, runtimes de edge/serverless, pipelines de middleware, trade-offs na seleção de frameworks.
Todo framework web Node.js tem que responder a uma pergunta primeiro: como é uma requisição dentro de um handler?
Express, Koa (em sua forma clássica) e o módulo http bruto respondem com os objetos nativos do Node - IncomingMessage para a requisição, ServerResponse para a resposta - objetos baseados em streams que existem apenas porque o módulo http do Node é anterior a qualquer padrão web para representar uma troca HTTP em JavaScript.
Hono responde de forma diferente: um handler recebe um objeto Request padrão e retorna um objeto Response padrão, as mesmas classes exatas definidas pela API Fetch e já implementadas em todos os navegadores modernos, no Deno, no Bun e em runtimes de edge como Cloudflare Workers.
O próprio Node suporta essas classes globais nativamente desde a versão 18, então um aplicativo Hono rodando sob @hono/node-server não está simulando uma API de navegador - está usando a mesma que o runtime já fornece.
Uma analogia útil: pense em Request/Response como um padrão de contêiner de transporte.
Antes dos contêineres padronizados, cada porto precisava de seu próprio equipamento de carregamento especializado para cada tipo de carga; uma vez que todos concordaram com a forma do contêiner, qualquer guindaste em qualquer porto podia mover qualquer carga, porque o equipamento só precisava entender o contêiner, não o que estava dentro dele.
O http.IncomingMessage do Node é uma carga moldada para um cais específico; o Request/Response da API Fetch é o contêiner de transporte - e um framework construído em torno do contêiner, não do cais, pode se mover para qualquer porto que também fale contêineres.
// Handler Hono: uma função simples de contexto Request-ish para Responseapp.get("/users/:id", (c) => { return c.json({ id: c.req.param("id") }); // c.json() retorna um Response padrão});
Koa fica no meio: ele ainda envolve os objetos http nativos do Node, mas substituiu o middleware baseado em callback do Express por async/await e um único objeto ctx desde o início, que é por que ele é agrupado com frameworks leves, mesmo que não seja baseado em Padrões Web como Hono é.
Polka vai na direção oposta completamente - ele mantém os objetos nativos do Node e simplesmente adiciona um roteador rápido e minimalista por cima, trocando portabilidade pelo menor footprint possível especificamente no Node.
A parte de "leve" que realmente muda como você escreve código é a composição de middleware, e funciona da mesma forma em Hono, Koa e Express, mesmo que os objetos subjacentes difiram: middleware não roda em uma lista plana e sequencial.
Ele se aninha, como camadas de uma cebola, porque cada função de middleware recebe um callback next() e decide quando - ou se - chamá-lo.
requisição entrando
├─ middleware logger (trabalho antes de next())
│ ├─ middleware auth (trabalho antes de next())
│ │ ├─ handler de rota (camada mais interna)
│ │ └─ auth: trabalho após next() retornar (ex: cabeçalho de resposta)
│ └─ logger: trabalho após next() retornar (ex: logar duração)
└─ resposta saindo
O código registrado antes de await next() roda na entrada, na ordem de registro; o código registrado depois de await next() roda na saída, na ordem inversa - que é por que um middleware de log que mede o tempo de uma requisição tem que envolver a chamada em next(), não apenas logar uma vez no início.
Este modelo de cebola é o que torna o middleware composível: uma verificação de autenticação pode interromper o fluxo ao nunca chamar next(), e um middleware de formatação de resposta pode inspecionar ou reescrever o que o handler produziu antes que chegue ao cliente, porque ele ainda está "dentro" da chamada quando next() retorna.
Por baixo dos panos, a escolha dos Padrões Web também muda como uma requisição chega a essa cadeia de middleware em primeiro lugar.
O núcleo de um aplicativo Hono não tem ideia de que está rodando no Node - @hono/node-server é um adaptador, uma fina camada de tradução que escuta em um http.Server real do Node, converte cada IncomingMessage recebido em um Request padrão, o entrega ao aplicativo Hono, e converte o Response que volta para o que o socket do Node precisa.
Esse adaptador é o único código específico do Node em toda a pilha; troque-o por um adaptador Cloudflare Workers (embutido na plataforma, sem necessidade de tradução) ou um adaptador Bun, e o exato mesmo objeto app roda em outro lugar, sem modificações, porque ele nunca tocou nos objetos do Node para começar.
"Leve" é realmente um atalho para duas propriedades separadas que nem sempre andam juntas: pequeno footprint (menos dependências, menor tamanho de instalação, menos código para analisar e compilar JIT na inicialização) e portabilidade de runtime (funciona fora do Node sem reescrita).
Polka tem a primeira propriedade sem a segunda - é minúsculo, mas é exclusivamente para Node por design.
Hono tem ambos, porque a portabilidade é o que permitiu que seus autores mantivessem o núcleo livre de código específico do Node em primeiro lugar; um framework que usa os globais Buffer ou process do Node dentro de seu núcleo não pode rodar sem modificações em um runtime de edge, então evitá-los é uma restrição que por acaso também encolhe a árvore de dependências.
O footprint ganha seu valor principalmente no cold start: em uma plataforma serverless ou de edge, uma nova instância precisa carregar e inicializar o framework antes que ele possa lidar com sua primeira requisição, e cada megabyte de código de dependência e cada cadeia síncrona de require() adicionam latência a isso.
No entanto, uma vez que um processo Node está aquecido e rodando de forma estável, a diferença entre Hono e Express diminui acentuadamente - ambos são limitados por I/O pelo mesmo event loop, e o overhead do próprio framework raramente é o gargalo em comparação com chamadas de banco de dados ou serialização.
Esse é o trade-off honesto: escolha um framework leve para implantações sensíveis a portabilidade ou cold-start, não sob a suposição de que ele tornará um serviço Node já aquecido dramaticamente mais rápido.
A lacuna do ecossistema é o outro custo real - Express tem mais de quinze anos de middleware, respostas no Stack Overflow e guias de integração que a comunidade de um framework menor ainda não acumulou, então equipes às vezes acabam escrevendo pequenos adaptadores ou middleware elas mesmas que teriam sido um npm install de uma linha no Express.
Abordagem
Força
Fraqueza
Melhor Ajuste
Hono (núcleo Padrões Web)
Roda sem modificação em Node, Workers, Deno, Bun; núcleo minúsculo
Ecossistema de middleware menor que Express
Implantações multi-runtime, APIs de edge/serverless
Koa (async-first, nativo Node)
Middleware async/await limpo, núcleo minimalista, catálogo de plugins existente enorme
Ainda vinculado aos objetos http do Node - sem portabilidade para edge
Serviços exclusivamente Node que desejam a maturidade do ecossistema Express com um núcleo mais limpo
Polka (nativo Node, sem abstração)
Overhead mínimo possível no Node; dependências quase zero
Exclusivo para Node, recursos mínimos embutidos (sem parsing de corpo embutido, etc.)
Serviços exclusivamente Node críticos para latência com necessidades de roteamento simples
Express (nativo Node, "batteries included")
Ecossistema enorme, mais documentado, padrão mais seguro
Maior footprint dos quatro; não portátil fora do Node
APIs Node de propósito geral onde a amplitude do ecossistema supera o footprint
"Leve apenas significa menos pacotes npm." Menos dependências é um sintoma, não a causa - o verdadeiro motor é se o núcleo do framework depende de objetos exclusivos do Node (como http.IncomingMessage) ou não, o que determina tanto o footprint quanto a portabilidade.
"Um aplicativo Hono é basicamente um aplicativo de navegador rodando no servidor." Ele reutiliza as mesmas classesRequest/Response que o navegador define, mas ainda roda código do lado do servidor com acesso completo à API do Node através de sua camada de adaptador - não é isolado como o JavaScript do navegador é.
"Frameworks menores são sempre mais rápidos." Eles geralmente vencem no cold start; uma vez que um processo está aquecido, o overhead do framework raramente é o custo dominante em comparação com chamadas de banco de dados ou serialização.
"Koa é basicamente Express com sintaxe diferente." O núcleo do Koa deliberadamente vem sem roteamento ou parsing de corpo embutidos, dependendo inteiramente de middleware para essas funções - um núcleo menor e mais composível que o do Express, mesmo que ambos usem os objetos http nativos do Node.
"Middleware sempre roda de cima para baixo, uma vez." Cada função de middleware envolve tudo registrado depois dela, então o código antes de await next() roda na entrada, em ordem, e o código depois de next() roda na saída, em ordem inversa - mover um middleware para antes ou depois muda tanto quando ele vê a requisição quanto quando ele vê a resposta.
O que realmente torna um framework "leve" em vez de apenas ter um bundle menor?
Seu núcleo evita depender de objetos específicos do Node (como http.IncomingMessage) e globais exclusivos do Node, construindo em vez disso sobre as classes padrão Request/Response. É isso que o torna pequeno e portátil - as duas coisas geralmente andam juntas, mas não são a mesma propriedade.
Por que os handlers do Hono parecem tão diferentes dos handlers do Express?
Um handler do Express recebe os objetos req/res nativos do Node e modifica res diretamente; um handler do Hono recebe um contexto que envolve um Request padrão e retorna um Response padrão, correspondendo à mesma API que uma chamada Fetch ou um Cloudflare Worker usa.
Usar "Padrões Web" significa que Hono roda o mesmo código de um navegador?
Não - significa que o núcleo do Hono reutiliza as mesmas classes Request/Response que um navegador define, então as formas correspondem, mas o código ainda é executado no lado do servidor com acesso total ao runtime através de qualquer adaptador (Node, Workers, Bun) que o esteja executando.
Como a ordem do middleware realmente afeta o comportamento?
Cada middleware envolve tudo registrado depois dele, então o código antes de await next() roda na entrada, em ordem, e o código depois de next() roda na saída, em ordem inversa - mover um middleware para antes ou depois muda tanto quando ele vê a requisição quanto quando ele vê a resposta.
O que é um adaptador e por que Hono precisa de um para Node?
Um adaptador (@hono/node-server para Node) é a camada de tradução entre os objetos nativos de um runtime e o núcleo Padrão Web do framework - ele converte um IncomingMessage recebido em um Request e converte o Response retornado de volta para o que o socket do Node precisa. É o único código específico do Node na pilha.
Polka é "leve" no mesmo sentido que Hono?
Apenas no eixo do footprint - Polka é exclusivo para Node e não usa a forma Request/Response dos Padrões Web, então ele é pequeno, mas não portátil para runtimes de edge ou não-Node como Hono é.
Mudar para um framework leve tornará minha API mais rápida?
Principalmente no cold start, onde menos código para carregar e inicializar importa mais. Uma vez que um processo está aquecido, o overhead do framework raramente domina em comparação com chamadas de banco de dados, serialização e I/O de rede.
Por que Koa é considerado "leve" se ainda é exclusivo para Node?
Porque seu núcleo é incomumente minimalista para um framework nativo do Node - sem roteador ou parser de corpo embutidos, middleware async/await-first, e um pequeno footprint de dependência - mesmo que não compartilhe a portabilidade de edge do Hono.
Qual é o custo real de escolher um ecossistema de framework menor?
Menos pacotes de middleware pré-construídos e mantidos pela comunidade e menos respostas existentes para problemas comuns - equipes às vezes escrevem pequenas integrações elas mesmas que já existiriam para Express.
Código Node que usa `Buffer` ou `process` ainda pode rodar dentro de um handler Hono?
Sim, no Node - o adaptador dá aos handlers acesso total ao runtime do Node. A restrição que mantém Hono portátil é que seu próprio núcleo evita depender desses globais, não que seu código de aplicativo não possa usá-los quando rodando especificamente no Node.
Eu tenho que escolher um framework para cada serviço do meu sistema?
Não - é comum usar Express ou Fastify para um monólito exclusivo para Node e Hono especificamente para serviços que precisam rodar em uma plataforma de edge ou ser portáteis, escolhendo por serviço com base em onde esse serviço realmente implanta.
Usar `Request`/`Response` padrão significa que perco acesso a respostas de streaming?
Não - o construtor Response padrão aceita um corpo ReadableStream, então o streaming funciona da mesma forma conceitual que com streams do Node, apenas expresso através da API Web Streams em vez das classes de stream do Node.