Backend-for-Frontend (BFF)

Separate gateways for different client types (mobile/web)

Introduction

In microservices architectures, different clients (web apps, mobile apps, IoT devices) often have different needs. For example:

  • Mobile clients need smaller payloads and offline support.
  • Web clients may require richer data or more complex aggregations.

If all clients share a single API Gateway, they may receive excess data, or the gateway might need client-specific logic — leading to complexity and performance issues.

The Backend-for-Frontend (BFF) Pattern solves this by creating client-specific backend services that sit between the API Gateway and the microservices.

Think of it as personalized assistants: each client gets a tailored backend that understands exactly what it needs.

Problem Statement

  • Single API Gateway must serve all clients → may send unnecessary data.
  • Business logic for different clients may diverge → gateway becomes bloated.
  • Difficult to handle client-specific requirements (formatting, aggregation, caching).

Example:

  • Mobile app requests /user/profile → only needs name and avatar.
  • Web app requests /user/profile → needs name, avatar, recent orders, payment info.
  • Without BFF → API Gateway must include both sets, wasting bandwidth and adding complexity.

Concept Overview

Definition:
The BFF Pattern creates dedicated backend services per client type, tailored to that client’s needs.

Core Idea:

  • Client → calls its dedicated BFF → BFF orchestrates calls to underlying microservices.
  • Keeps API Gateway simple while providing optimized responses.

Diagram (simplified):

Client (Mobile) ---> [ Mobile BFF ] ---> Microservices
Client (Web) ---> [ Web BFF ] ---> Microservices

When to Use

  • Multiple clients with different requirements.
  • When API Gateway alone cannot efficiently serve all clients.
  • Optimizing performance for mobile apps (bandwidth, latency).
  • Handling client-specific transformations, caching, or aggregations.

When to Avoid

  • Single client or minimal client types.
  • Small-scale apps where complexity outweighs benefits.
  • Projects where standardized responses are sufficient for all clients.

Architecture / Flow

  1. Client sends request → its dedicated BFF.
  2. BFF validates request, applies client-specific logic.
  3. BFF calls one or more microservices.
  4. Aggregates responses, formats payload for client.
  5. Sends optimized response to client.

Implementation (Step-by-Step)

Technology Choices

  • Node.js / Express for lightweight BFF services.
  • Spring Boot / Spring Cloud Gateway for Java-based BFF.
  • GraphQL server as a BFF (popular for aggregation).

Example: Node.js Express BFF for Mobile

const express = require('express');
const axios = require('axios');
const app = express();

app.get('/user/profile', async (req, res) => {
try {
// Call underlying microservices
const user = await axios.get('http://user-service:5001/user/123');
const orders = await axios.get('http://order-service:5002/orders?user=123');

// Send only relevant info for mobile
res.json({
name: user.data.name,
avatar: user.data.avatar,
recentOrder: orders.data[0]
});
} catch (error) {
res.status(500).send('Error fetching data');
}
});

app.listen(3001, () => console.log('Mobile BFF running on port 3001'));

Now the mobile client gets exactly what it needs, while the web client can have its own BFF.

Advantages

  • Optimized client responses → less bandwidth, faster load times.
  • Simplifies API Gateway → removes client-specific logic from gateway.
  • Supports multiple clients → web, mobile, IoT, or external partners.
  • Encapsulates client-specific business rules.

Disadvantages / Pitfalls

  • Extra maintenance → separate backend services per client.
  • Can lead to duplicate code if BFFs overlap in functionality.
  • Increases deployment complexity.
  • May introduce latency if orchestration is inefficient.

Best Practices

  • Keep BFF lightweight and stateless.
  • Reuse common service calls via libraries or shared modules.
  • Implement caching to reduce repeated microservice calls.
  • Monitor performance per BFF to prevent bottlenecks.
  • Combine with API Gateway for security, authentication, and rate limiting.

Common Mistakes to Avoid

  • Adding too much business logic → BFF becomes another monolith.
  • Ignoring code reuse → leads to duplicate calls or inconsistent transformations.
  • Failing to version BFF APIs → can break client apps during upgrades.

Comparison with Alternatives

When evaluating the API Gateway pattern, it’s important to understand how it compares with other approaches to exposing microservices. One common alternative is the Direct Client-to-Microservice Communication model, where each client communicates directly with individual services. While this can reduce infrastructure overhead and avoid the gateway becoming a bottleneck, it often results in clients needing to manage multiple service endpoints, handle cross-cutting concerns like authentication, and adapt to frequent service changes. This places unnecessary complexity on the client, which is especially problematic in large-scale or consumer-facing systems.

Another related option is the Backend-for-Frontend (BFF) pattern, where a separate gateway is created for each client type (web, mobile, IoT). Compared to a single API Gateway, BFF provides more flexibility and optimized responses tailored to different device needs. However, it also means maintaining multiple gateway layers, which can increase operational complexity and development costs.

Finally, modern teams sometimes consider a Service Mesh, which provides features like traffic routing, observability, and security at the infrastructure layer. While service meshes excel at handling service-to-service communication, they don’t fully replace the API Gateway, since external clients still need a controlled entry point into the system. In practice, many organizations use a combination of API Gateway and Service Mesh: the gateway handles inbound traffic, while the mesh manages internal communication.

In short, the API Gateway sits in a sweet spot: it abstracts complexity from clients and centralizes cross-cutting concerns, while alternatives either push complexity outward (direct communication), fragment it (BFF), or complement it at the infrastructure layer (service mesh).

Real-World Use Cases

  • Spotify → different BFFs for web, mobile, smart devices.
  • Netflix → multiple BFFs to optimize mobile streaming.
  • Uber → web vs driver app vs rider app BFFs for tailored responses.

Expert Tips 🔥

  • Pair BFF with GraphQL to let clients request exactly what they need.
  • Keep shared logic in microservices to avoid duplication in BFFs.
  • Use async parallel calls inside BFF to optimize performance.
  • Version BFFs carefully to support legacy clients.

Conclusion / Key Takeaways

The BFF Pattern provides client-specific backends to optimize responses, performance, and business logic per client.

  • Use it when clients have different requirements.
  • Avoid unnecessary complexity for small systems.
  • Always monitor, cache, and optimize orchestration inside BFF.

Think of BFFs as personal assistants for each client — delivering exactly what the client needs, efficiently.