O Backend for Frontend no Node.js, conhecido como BFF, cria uma API específica para cada tipo de cliente. Web, aplicativo móvel, painel administrativo e integrações de parceiros podem ter necessidades diferentes de dados, latência, autenticação e formato de resposta.
Em vez de obrigar todos os clientes a consumir uma API genérica e fazer dezenas de chamadas, o BFF agrega serviços internos e entrega um contrato alinhado à interface. Porém, ele não deve copiar regras de negócio nem se tornar um monólito com toda a lógica do sistema.
Neste guia, você aprenderá arquitetura, agregação, contratos, autenticação, cache, falha parcial, timeouts, GraphQL, segurança, observabilidade, deploy e testes.
O que é Backend for Frontend?
Backend for Frontend é um padrão em que cada experiência possui uma camada backend dedicada. A referência Backend for Frontend de Sam Newman apresenta o padrão. A documentação Backends for Frontends Pattern da Microsoft explica cenários e consequências.
Para entrada compartilhada, consulte API Gateway no Node.js. Para contratos, veja OpenAPI com Node.js.
Problema de uma API genérica
Uma tela mobile pode precisar de cinco campos e imagens pequenas. Um painel web pode precisar de tabelas, filtros e detalhes. Uma API única tende a:
- retornar dados demais;
- exigir muitas chamadas;
- acoplar clientes entre si;
- introduzir parâmetros específicos;
- ficar difícil de evoluir;
- transferir composição para o frontend.
Arquitetura
Web App → Web BFF ─┐
Mobile → Mobile BFF ├→ Serviços internos
Admin → Admin BFF ─┘Um API Gateway pode rotear cada cliente ao BFF correto.
BFF versus API Gateway
- Gateway: autenticação geral, roteamento, limites e proteção.
- BFF: composição e contrato específico da experiência.
Em sistemas pequenos, um serviço pode cumprir ambos os papéis, mas as responsabilidades devem continuar claras.
Rota agregada
GET /mobile/homeO BFF pode consultar perfil, pedidos recentes e recomendações.
Agregação paralela
const [profile, orders, recommendations] = await Promise.allSettled([
profileClient.getSummary(userId),
ordersClient.getRecent(userId, 5),
recommendationClient.getForUser(userId)
]);Defina quais respostas são obrigatórias.
Falha parcial
{
"profile": { "name": "Ana" },
"recentOrders": [],
"recommendations": null,
"warnings": ["recommendations_unavailable"]
}Uma falha opcional não precisa derrubar a tela inteira.
Dados obrigatórios
Se autenticação ou perfil básico falha, talvez a resposta inteira deva falhar. Classifique dependências.
Timeout por chamada
async function withTimeout(promiseFactory, ms) {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), ms);
try {
return await promiseFactory(controller.signal);
} finally {
clearTimeout(timer);
}
}Orçamento total
Se a rota possui prazo de 800 ms, cada dependência precisa de orçamento menor. Não espere três serviços por 800 ms em sequência.
Cancelamento
Quando o cliente desconecta, aborte chamadas internas quando possível.
Retries
Repita apenas chamadas idempotentes e dentro do orçamento. Um retry longo pode tornar a tela mais lenta que uma degradação.
Consulte Retry com Backoff no Node.js.
Circuit breaker
Se recomendações falham repetidamente, abra o circuito e retorne sem essa seção.
Bulkhead
Use limites separados por dependência. Um serviço lento não deve consumir todas as conexões do BFF.
Contrato específico
{
"header": {
"displayName": "Ana",
"avatarUrl": "..."
},
"cards": [],
"actions": []
}O BFF pode devolver um view model próximo ao que a interface precisa.
Não devolva HTML sem necessidade
Um BFF costuma retornar JSON. Server-side rendering é outra decisão e pode coexistir.
Transformação de campos
Converta modelos internos para DTOs externos. Não exponha respostas brutas de microserviços.
Acoplamento ao frontend
O BFF pode evoluir junto com a interface. Isso é uma vantagem, mas exige ownership claro entre equipes.
Versionamento
Clientes móveis antigos permanecem instalados por meses. O Mobile BFF precisa manter contratos compatíveis ou versionados.
Veja Versionamento de API no Node.js.
Web BFF
A web pode ser atualizada rapidamente, permitindo mudanças coordenadas no contrato.
Mobile BFF
Considere:
- rede lenta;
- modo offline;
- payload pequeno;
- versões antigas;
- imagens adaptadas;
- paginação;
- sincronização incremental.
Admin BFF
Painéis internos podem exigir filtros, auditoria e ações privilegiadas. Não reduza controles de segurança por serem internos.
Parceiros
Um Partner BFF pode adaptar contratos públicos sem expor serviços internos.
GraphQL como BFF
GraphQL permite que o cliente selecione campos, mas ainda precisa de resolvers, autorização, limites e DataLoader.
REST como BFF
REST com endpoints orientados a telas é simples e previsível. Não é necessário adotar GraphQL apenas para ter BFF.
Server-driven UI
O BFF pode retornar blocos e ações para a interface. Isso acelera experimentos, mas aumenta acoplamento e exige schema rigoroso.
Feature flags
O BFF pode avaliar flags por cliente e retornar a variante.
Consulte Feature Flags no Node.js.
Autenticação
O BFF valida sessão ou token e propaga identidade segura aos serviços.
Cookies no Web BFF
Um BFF no mesmo domínio pode usar cookies HttpOnly, Secure e SameSite, reduzindo exposição do token ao JavaScript.
CSRF
Autenticação por cookie exige proteção CSRF em operações de mudança.
Mobile tokens
Aplicativos usam OAuth, PKCE e armazenamento seguro. Consulte OAuth 2.0 com PKCE.
Autorização
O BFF pode ocultar botões, mas os serviços precisam validar permissões. Interface não é barreira de segurança.
Propagação de identidade
Use token interno com audience específica ou headers assinados. Não encaminhe claims arbitrários do cliente.
Token exchange
Em arquiteturas avançadas, o BFF troca o token externo por credencial de serviço limitada.
Segredos
O BFF pode proteger credenciais de APIs de terceiros que não devem chegar ao navegador.
CORS
Quando web e BFF compartilham origem, CORS pode ser evitado. Em origens diferentes, use allowlist.
Cache
Dados públicos podem ser cacheados. Dados por usuário exigem chave correta, private ou no-store.
Cache por seção
Recomendações podem ter TTL de minutos, enquanto saldo precisa de dados atuais.
ETag
Uma resposta agregada pode usar ETag, mas qualquer dependência relevante precisa invalidar a representação.
Paginação
Não agregue coleções infinitas. Use cursor e limites. Consulte Paginação em APIs Node.js.
N+1 interno
Evite consultar um serviço por item. Solicite endpoints batch ou use modelos de leitura.
Batch endpoint
POST /internal/products/batch
{
"ids": ["1", "2", "3"]
}O serviço deve limitar quantidade e preservar autorização.
Modelo de leitura
Quando uma tela exige joins constantes entre serviços, uma projeção CQRS pode ser melhor que fan-out em toda requisição.
Veja CQRS no Node.js.
Uploads
O BFF pode emitir URL pré-assinada para object storage, evitando proxy de arquivo grande.
Streaming
Se precisa encaminhar download, use streams e backpressure.
WebSocket
Um BFF pode adaptar eventos internos para o protocolo da interface. Configure autenticação, reconexão e limites.
SSE
Para notificações unidirecionais, SSE pode ser mais simples. Preserve Last-Event-ID.
Erros
Mapeie erros internos para códigos estáveis:
{
"code": "HOME_PARTIALLY_UNAVAILABLE",
"message": "Parte do conteúdo não está disponível",
"requestId": "..."
}Não exponha topologia
Evite mensagens como “recommendation-service-3 falhou”. Use logs internos para detalhes.
Observabilidade
Registre cliente, versão do app, rota, dependências chamadas, duração e degradações.
Métricas
Monitore:
- latência total;
- latência por dependência;
- falhas parciais;
- fan-out;
- payload;
- cache hit;
- versões de cliente;
- timeouts;
- circuit breaker.
Veja Métricas Prometheus no Node.js.
Tracing
Crie span para a requisição e cada chamada interna. Isso mostra qual serviço domina a latência.
Logs
Use logs estruturados, sem tokens ou respostas completas. Consulte Logs com Pino no Node.js.
Health checks
Liveness verifica o processo. Readiness pode confirmar configuração e conectividade essencial, sem testar todos os serviços a cada segundo.
Graceful shutdown
Pare de receber tráfego, cancele chamadas e aguarde requisições em andamento.
Escalabilidade
Mantenha o BFF stateless. Escale separadamente conforme o tráfego do cliente.
Ownership
A equipe responsável pela experiência deve participar do contrato e das prioridades do BFF.
Duplicação entre BFFs
Alguma duplicação é aceitável para independência. Extraia biblioteca apenas quando a regra é realmente transversal e estável.
Não compartilhe banco de domínio
O BFF deve usar APIs ou modelos de leitura publicados, não consultar tabelas internas de todos os serviços.
Deploy independente
Web e Mobile BFFs podem ter ciclos diferentes. Use contratos internos compatíveis.
Canary
Libere nova composição para uma fração de usuários e compare métricas.
Testes unitários
Teste transformação de DTO, degradação e políticas de timeout.
Testes de contrato
Valide que o BFF continua entendendo respostas dos serviços.
Testes de integração
Simule serviços lentos, indisponíveis e respostas incompletas.
Teste de falha parcial
test('retorna home sem recomendações', async () => {
recommendations.fail();
const response = await request('/mobile/home');
assert.equal(response.status, 200);
assert.equal(response.body.recommendations, null);
assert.ok(response.body.warnings.includes(
'recommendations_unavailable'
));
});Teste de segurança
Confirme que tenant e usuário vêm da identidade validada e que headers forjados são ignorados.
Teste de carga
Meça fan-out, pool de conexões e latência p99 durante falha de dependência.
Quando usar?
- clientes têm necessidades diferentes;
- mobile precisa de payload otimizado;
- web exige composição frequente;
- equipes evoluem independentemente;
- segredos devem ficar no servidor;
- contratos genéricos ficaram complexos.
Quando evitar?
- um único cliente simples;
- API já atende bem;
- equipe não consegue operar mais serviços;
- o BFF apenas repassa tudo;
- não existe ownership;
- duplicação supera o benefício.
Erros comuns
- Regra de negócio no BFF: domínio diverge.
- Fan-out sem limite: latência cresce.
- Sem timeout: tela fica presa.
- Token no navegador: superfície aumenta.
- Cache por usuário incorreto: dados vazam.
- Mesmo BFF para tudo: o padrão perde propósito.
- Consultar bancos internos: serviços ficam acoplados.
Boas práticas
- Crie contrato por experiência.
- Mantenha regras de domínio nos serviços.
- Defina timeouts.
- Trate falha parcial.
- Limite fan-out.
- Use batch e projeções.
- Proteja identidade.
- Meça por dependência.
- Tenha ownership claro.
- Adote apenas quando necessário.
Conclusão
O Backend for Frontend no Node.js adapta APIs às necessidades de web, mobile, administração ou parceiros. Ele reduz chamadas, payloads e complexidade no cliente.
O BFF funciona melhor como camada de experiência, não como novo centro de regras de negócio. Com timeouts, falha parcial, contratos específicos e observabilidade por dependência, ele melhora a interface sem criar um gateway monolítico para todos os clientes.




