DEV Community

Cover image for O que é Backend for Frontend (BFF)?
Lucas
Lucas

Posted on • Originally published at apidog.com

O que é Backend for Frontend (BFF)?

Um Backend for Frontend (BFF) é um serviço de backend dedicado a um frontend específico. Em vez de web, iOS, Android e integrações externas consumirem o mesmo backend genérico, cada cliente recebe uma camada server-side própria para agregar, adaptar e devolver exatamente o payload que aquela interface precisa.

Experimente o Apidog hoje

Sam Newman nomeou e popularizou o padrão em 2015, a partir de trabalhos realizados no SoundCloud. Mais de uma década depois, BFF continua sendo uma abordagem útil para equipes que executam microsserviços por trás de múltiplos clientes, e a Microsoft o documenta como um padrão de arquitetura de nuvem.

O problema que um BFF resolve

Um sistema normalmente começa simples:

[ Web app ] ---> [ Backend ] ---> [ Banco / Serviços ]
Enter fullscreen mode Exit fullscreen mode

Depois surgem novos clientes:

  • aplicativo mobile;
  • integração com parceiros;
  • widget;
  • painel administrativo;
  • clientes internos.

Se todos usam o mesmo backend, esse backend precisa atender necessidades diferentes ao mesmo tempo. Isso gera dois problemas comuns.

Over-fetching e under-fetching

Um endpoint genérico retorna um formato fixo.

Exemplo:

GET /customers/123
Enter fullscreen mode Exit fullscreen mode

Para um painel web, talvez faça sentido retornar:

{
  "id": "123",
  "name": "Ana",
  "email": "ana@example.com",
  "orders": [],
  "recommendations": [],
  "accountSettings": {}
}
Enter fullscreen mode Exit fullscreen mode

Mas um app mobile talvez precise apenas disso:

{
  "name": "Ana",
  "unreadNotifications": 4
}
Enter fullscreen mode Exit fullscreen mode

Quando o mesmo endpoint atende os dois casos:

  • o mobile baixa dados demais e descarta boa parte deles;
  • ou precisa fazer várias chamadas extras para montar a tela.

Clientes “tagarelas”

Sem uma API adaptada à tela, o frontend precisa orquestrar tudo:

Mobile Home
 ├─ GET /profile
 ├─ GET /notifications/count
 ├─ GET /feed
 └─ GET /recommendations
Enter fullscreen mode Exit fullscreen mode

Isso aumenta:

  • latência;
  • consumo de bateria;
  • complexidade no frontend;
  • dificuldade de testar;
  • acoplamento entre UI e microsserviços.

O BFF move essa orquestração para o servidor:

Mobile Home
 └─ GET /mobile/home
       ├─ Profile Service
       ├─ Notification Service
       ├─ Feed Service
       └─ Recommendation Service
Enter fullscreen mode Exit fullscreen mode

O cliente faz uma chamada; o BFF chama os serviços necessários, combina os dados e entrega um payload pronto para a tela.

Como o padrão BFF funciona

O BFF fica entre um cliente específico e os serviços downstream:

[ Web app ]     ---> [ Web BFF ]     ---\
[ iOS app ]     ---> [ iOS BFF ]     -----> [ Microservices ]
[ Android app ] ---> [ Android BFF ] ---/
Enter fullscreen mode Exit fullscreen mode

Cada BFF normalmente executa três tarefas.

1. Agregar

O BFF chama vários serviços e retorna uma única resposta para o cliente.

app.get("/mobile/home", async (req, res) => {
  const userId = req.user.id;

  const [profile, notifications, feed] = await Promise.all([
    profileClient.getProfile(userId),
    notificationClient.getUnreadCount(userId),
    feedClient.getFeed(userId)
  ]);

  res.json({
    user: {
      name: profile.name,
      avatarUrl: profile.avatarUrl
    },
    unreadNotifications: notifications.count,
    feed: feed.items.slice(0, 10)
  });
});
Enter fullscreen mode Exit fullscreen mode

Essa é a agregação de API aplicada a uma experiência específica. Para a versão geral do conceito, veja o padrão agregador de API.

2. Remodelar

O BFF adapta o formato para o cliente:

  • remove campos desnecessários;
  • renomeia propriedades;
  • achata objetos aninhados;
  • formata valores;
  • reduz payloads para mobile;
  • retorna respostas mais ricas para desktop.

Exemplo de resposta otimizada para mobile:

{
  "name": "Ana",
  "avatarUrl": "https://cdn.example.com/avatar.png",
  "unreadNotifications": 4,
  "latestPosts": [
    {
      "id": "p1",
      "title": "Novo pedido enviado"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

3. Traduzir

O BFF também pode lidar com decisões específicas do cliente:

  • paginação diferente para mobile e web;
  • cache por tipo de cliente;
  • tradução entre protocolos;
  • composição de dados;
  • tratamento de erros adequado à UI.

Os microsserviços continuam genéricos e orientados a capacidades de negócio. O BFF concentra a modelagem específica do cliente.

Se você está revisando sua arquitetura de serviços, estes guias ajudam a contextualizar: microsserviços versus APIs e transição de um monolito para microsserviços.

Um BFF por experiência do cliente

A regra prática é:

uma experiência de cliente distinta = um BFF
Enter fullscreen mode Exit fullscreen mode

Exemplos:

Web app     ---> Web BFF
iOS app     ---> iOS BFF
Android app ---> Android BFF
Partner API ---> Partner BFF
Enter fullscreen mode Exit fullscreen mode

Isso evita condicionais espalhadas no mesmo backend:

// Sinal de alerta
if (clientType === "mobile") {
  return mobilePayload;
}

if (clientType === "web") {
  return webPayload;
}

if (clientType === "partner") {
  return partnerPayload;
}
Enter fullscreen mode Exit fullscreen mode

Quando um único BFF começa a atender clientes muito diferentes, ele vira novamente um backend genérico.

A exceção: se iOS e Android tiverem experiências quase idênticas e forem mantidos pela mesma equipe, pode fazer sentido usar um único BFF mobile. O critério é similaridade e propriedade, não apenas o nome da plataforma.

A propriedade pertence à equipe de frontend

Um BFF não deve ser apenas “mais uma API” controlada por uma equipe central de backend. A equipe que mantém o cliente deve ser dona do BFF.

Isso permite que a equipe:

  • altere UI e endpoint juntos;
  • priorize o backlog conforme a necessidade do produto;
  • escolha runtime e linguagem adequados;
  • publique mudanças sem depender da fila de outra equipe;
  • teste o contrato da API junto com a experiência do usuário.

Exemplo de divisão saudável:

Equipe Web
 ├─ Web App
 └─ Web BFF

Equipe Mobile
 ├─ iOS App
 ├─ Android App
 └─ Mobile BFF

Equipe Plataforma
 ├─ API Gateway
 ├─ Observabilidade
 └─ Autenticação compartilhada
Enter fullscreen mode Exit fullscreen mode

Essa separação combina bem com a ideia de camada de experiência em conectividade orientada por API.

BFF vs. Gateway de API

BFF e gateway de API parecem parecidos em diagramas, mas resolvem problemas diferentes.

Um gateway de API é um ponto de entrada compartilhado para preocupações transversais:

  • autenticação;
  • autorização;
  • rate limiting;
  • roteamento;
  • terminação TLS;
  • logs;
  • métricas;
  • políticas globais.

Um BFF é específico de uma experiência:

  • agrega dados para uma tela;
  • adapta payloads para um cliente;
  • traduz necessidades da UI;
  • reduz chamadas do frontend;
  • isola mudanças por equipe.

Eles podem ser usados juntos:

[ Client ]
   |
   v
[ API Gateway ]
   |
   v
[ Client-specific BFF ]
   |
   v
[ Microservices ]
Enter fullscreen mode Exit fullscreen mode

Use o gateway para o que é igual entre clientes. Use o BFF para o que é diferente.

Para comparações relacionadas, veja:

Quando usar um BFF

Use BFF quando estas condições forem verdadeiras.

Você tem clientes realmente diferentes

Exemplo:

Web dashboard: precisa de dados completos e tabelas grandes
Mobile app: precisa de payloads pequenos e respostas rápidas
Partner API: precisa de formato estável e limitado
Enter fullscreen mode Exit fullscreen mode

Quanto mais as experiências divergem, mais o BFF ajuda.

O backend compartilhado virou gargalo

Sinais comuns:

  • toda mudança de frontend exige negociação com várias equipes;
  • um endpoint tem muitos parâmetros condicionais;
  • o payload cresceu para atender todos os clientes;
  • mudanças simples demoram porque afetam consumidores demais.

Você precisa otimizar payload por cliente

Mobile pode priorizar:

  • respostas pequenas;
  • cache agressivo;
  • menos chamadas;
  • campos essenciais.

Desktop pode priorizar:

  • dados ricos;
  • filtros;
  • agregações;
  • visualizações completas.

A equipe precisa escolher seu próprio runtime

Um BFF pode ser escrito no stack mais produtivo para aquela equipe, desde que respeite os contratos e padrões operacionais da organização.

Quando não usar um BFF

BFF adiciona custo. Evite quando ele não resolve um problema real.

Você tem apenas um cliente

Se existe uma única interface, um BFF provavelmente é só um salto extra.

[ App único ] ---> [ Backend ]
Enter fullscreen mode Exit fullscreen mode

Nesse caso, mantenha a arquitetura simples.

Seus clientes consomem os mesmos dados

Se web e mobile usam praticamente o mesmo payload, BFFs separados podem duplicar esforço sem benefício.

GraphQL já resolve a modelagem

Com GraphQL, cada cliente pode solicitar exatamente os campos necessários a partir de um endpoint. Isso reduz over-fetching e under-fetching.

Se você já tem uma camada GraphQL com resolvers adequados ao frontend, um BFF separado pode não agregar muito. Veja o que é GraphQL antes de adicionar outra camada.

Gateway + microsserviços já são suficientes

Para sistemas simples, um gateway de API na frente de microsserviços bem projetados pode ser o bastante.

Desvantagens reais do BFF

Mesmo quando o padrão se encaixa, ele traz custos.

Duplicação de código

Três BFFs podem acabar implementando a mesma lógica:

  • formatação de datas;
  • validação comum;
  • tratamento de erros;
  • headers padrão;
  • autenticação auxiliar.

Mitigação:

  • mova lógica realmente compartilhada para bibliotecas;
  • mantenha autenticação, rate limiting e observabilidade no gateway;
  • deixe o BFF focado em adaptação de payload e orquestração por cliente.

Mais serviços para operar

Cada BFF precisa de:

  • pipeline de CI/CD;
  • deploy;
  • monitoramento;
  • logs;
  • alertas;
  • gestão de secrets;
  • política de segurança;
  • ownership claro.

Se a equipe não consegue operar mais serviços, talvez ainda não seja hora de introduzir BFFs.

Um salto de rede extra

O BFF adiciona uma chamada entre cliente e serviços. Porém, em muitos casos ele reduz a latência percebida porque substitui várias chamadas do cliente por uma única chamada agregada.

Meça:

  • p95/p99 de latência;
  • tamanho dos payloads;
  • número de chamadas por tela;
  • taxa de erro;
  • tempo de renderização no cliente.

Risco de virar um backend inchado

Um BFF não deve conter regra de negócio central. Essa lógica pertence aos microsserviços.

O BFF deve cuidar principalmente de:

  • composição;
  • transformação;
  • adaptação;
  • experiência do cliente.

Se ele começa a possuir regras de negócio amplas, o acoplamento volta.

Implementando um BFF na prática

Um fluxo simples para adotar BFF:

1. Escolha uma tela problemática

Comece pequeno. Por exemplo:

Tela inicial do app mobile
Enter fullscreen mode Exit fullscreen mode

Mapeie as chamadas atuais:

GET /profile
GET /notifications/count
GET /feed
GET /recommendations
Enter fullscreen mode Exit fullscreen mode

2. Defina o payload ideal para o cliente

Não copie os modelos internos dos microsserviços. Modele a resposta pelo que a tela precisa.

{
  "user": {
    "name": "Ana",
    "avatarUrl": "https://cdn.example.com/avatar.png"
  },
  "unreadNotifications": 4,
  "feed": [
    {
      "id": "post-1",
      "title": "Seu pedido foi enviado"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

3. Crie um endpoint orientado à experiência

GET /mobile/home
Enter fullscreen mode Exit fullscreen mode

Evite endpoints genéricos demais. O BFF pode expor APIs alinhadas à experiência do cliente.

4. Agregue chamadas em paralelo

Exemplo em Node.js/Express:

app.get("/mobile/home", async (req, res, next) => {
  try {
    const userId = req.user.id;

    const [profile, notificationCount, feed] = await Promise.all([
      profileService.getProfile(userId),
      notificationService.getUnreadCount(userId),
      feedService.getLatest(userId, { limit: 10 })
    ]);

    res.json({
      user: {
        name: profile.name,
        avatarUrl: profile.avatarUrl
      },
      unreadNotifications: notificationCount,
      feed: feed.items.map((item) => ({
        id: item.id,
        title: item.title
      }))
    });
  } catch (error) {
    next(error);
  }
});
Enter fullscreen mode Exit fullscreen mode

5. Teste contrato e regressão

Inclua testes para garantir que o BFF entrega o formato esperado:

expect(response.body).toEqual({
  user: {
    name: expect.any(String),
    avatarUrl: expect.any(String)
  },
  unreadNotifications: expect.any(Number),
  feed: expect.any(Array)
});
Enter fullscreen mode Exit fullscreen mode

6. Monitore como produto

Para cada endpoint BFF, monitore:

  • latência;
  • erros por dependência downstream;
  • tamanho da resposta;
  • cache hit rate;
  • uso por versão do cliente;
  • endpoints não utilizados.

Mantendo contratos BFF sincronizados com Apidog

A parte difícil de executar BFFs na prática são os contratos. Cada BFF expõe sua própria API voltada ao cliente e também depende dos contratos dos microsserviços subjacentes. Essa quantidade de interfaces entre equipes pode gerar divergência, bugs e clientes quebrados.

Imagem

É aqui que o Apidog se encaixa no fluxo de trabalho. Apidog é uma plataforma de design, teste, mocking e documentação de API. Para BFFs, ele ajuda a manter cada contrato em um lugar único.

1. Projete o contrato primeiro

Defina o endpoint do BFF antes de implementar:

GET /mobile/home
Enter fullscreen mode Exit fullscreen mode

Com resposta esperada:

{
  "user": {
    "name": "string",
    "avatarUrl": "string"
  },
  "unreadNotifications": 0,
  "feed": [
    {
      "id": "string",
      "title": "string"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

No Apidog, esse contrato pode ser definido visualmente com OpenAPI por baixo. Essa é a abordagem de design de API contrato-primeiro aplicada ao BFF, mantendo o contrato de API explícito.

2. Crie um mock antes da implementação

Com o contrato definido, a equipe de frontend pode começar a desenvolver contra um mock do BFF, sem esperar:

  • implementação do BFF;
  • disponibilidade dos microsserviços;
  • dados reais completos.

Isso reduz bloqueios entre frontend e backend.

3. Teste o contrato no CI

Automatize validações para garantir que o BFF continua retornando o payload esperado.

Exemplos de verificações:

  • status code correto;
  • campos obrigatórios presentes;
  • tipos compatíveis;
  • estrutura do JSON estável;
  • erros padronizados;
  • resposta compatível com o contrato.

Assim, uma mudança downstream que quebre o BFF pode ser detectada antes de chegar ao cliente.

4. Documente para frontend e backend

A documentação interativa gerada a partir do contrato ajuda as equipes a compartilharem a mesma fonte de verdade:

  • frontend sabe como consumir o BFF;
  • backend entende quais dados o BFF precisa;
  • QA sabe quais cenários testar;
  • produto consegue visualizar o comportamento esperado.

Escopo importante: o Apidog não constrói, hospeda ou executa seu BFF, e também não é um gateway de API. Ele é usado para projetar, simular, testar e documentar os contratos de API que cada BFF suporta.

Tratar cada BFF como um produto, com contrato estável e bem documentado, torna o padrão mais sustentável.

Checklist para decidir se você precisa de BFF

Use esta lista antes de criar um novo serviço:

[ ] Tenho mais de um cliente?
[ ] Esses clientes precisam de payloads diferentes?
[ ] O frontend faz chamadas demais para montar uma tela?
[ ] O backend compartilhado virou gargalo entre equipes?
[ ] A equipe cliente pode operar o BFF?
[ ] O gateway não resolve esse problema?
[ ] GraphQL não cobre melhor esse caso?
[ ] O contrato do BFF será testado e documentado?
Enter fullscreen mode Exit fullscreen mode

Se a maioria das respostas for “sim”, BFF provavelmente faz sentido.

FAQ

Um BFF é um microsserviço?

Um BFF é um serviço server-side e, em uma arquitetura de microsserviços, geralmente é implantado como um serviço independente. Mas sua função é diferente.

Um microsserviço normalmente possui uma capacidade de negócio. Um BFF possui uma experiência de cliente e existe para agregar e remodelar serviços para esse cliente.

Quantos BFFs devo ter?

A regra prática é um BFF por experiência de cliente distinta.

Exemplo:

Web app     -> Web BFF
iOS app     -> iOS BFF
Android app -> Android BFF
Enter fullscreen mode Exit fullscreen mode

Combine clientes apenas quando eles forem muito parecidos e tiverem a mesma equipe responsável.

GraphQL substitui BFF?

Pode substituir parte do problema, especialmente a modelagem de payload. GraphQL permite que o cliente peça os campos exatos de que precisa.

BFF ainda pode ser útil quando você precisa de:

  • orquestração específica por cliente;
  • tradução de protocolo;
  • runtime separado;
  • lógica de composição fora do servidor GraphQL compartilhado.

Posso usar BFF e gateway de API juntos?

Sim. É comum.

Cliente -> Gateway -> BFF -> Microsserviços
Enter fullscreen mode Exit fullscreen mode

O gateway lida com preocupações compartilhadas. O BFF lida com o que é específico do cliente.

Quem deve ser dono do BFF?

A equipe que mantém o frontend correspondente. Essa propriedade é central para o padrão, porque permite entregar mudanças de UI e API juntas.

Um BFF adiciona latência?

Ele adiciona um salto de rede, então existe custo. Porém, muitas vezes reduz a latência total percebida porque diminui o número de chamadas feitas pelo cliente e permite que o BFF chame serviços em paralelo.

Meça antes e depois.

Top comments (0)