API Gateway vs Backend-for-Frontend

By Oleksandr Andrushchenko — Published on
0 Likes
0 Dislikes
API Gateway vs Backend-for-Frontend
API Gateway vs Backend-for-Frontend

Microservice architectures often contain dozens of internal APIs, but exposing those services directly to browsers, mobile applications, and external clients creates coupling between clients and the internal service topology. API Gateways and Backend-for-Frontend (BFF) services solve different parts of this problem.

An API Gateway provides a shared entry point for routing, authentication, rate limiting, observability, and other cross-cutting concerns. A BFF provides a client-specific API that composes and transforms backend data around the needs of a particular frontend. They are complementary patterns rather than competing replacements.

Table of Contents

Why an API Layer Is Needed

Direct client-to-microservice communication appears simple when a system contains only a few services. As the architecture grows, clients must understand service addresses, authentication requirements, API versions, failure behavior, and which services provide the data required for each screen.

Browser
   |
   +------> Customer Service
   +------> Order Service
   +------> Payment Service
   +------> Inventory Service
   +------> Recommendation Service

Mobile App
   |
   +------> Customer Service
   +------> Order Service
   +------> Payment Service
   +------> Inventory Service

This exposes internal architecture to clients. Splitting one service into two can require frontend changes even though the business capability remains unchanged.

Network behavior also becomes inefficient. A page may require several backend requests, while mobile applications may need smaller payloads or fewer network round trips than desktop clients.

An intermediate API layer creates a stable boundary:

Clients
   |
   v
External API Layer
   |
   +------> Service A
   +------> Service B
   +------> Service C
   +------> Service D

The important architectural question is which responsibilities belong in that layer. Infrastructure-level concerns generally belong in a gateway, while client-specific business composition generally belongs in a BFF.

API Gateway

An API Gateway is a shared entry point positioned between API consumers and backend services. It routes requests to the appropriate service and can enforce policies consistently before traffic reaches application workloads.

Typical responsibilities include routing, authentication enforcement, TLS termination, rate limiting, request-size limits, access logging, metrics, tracing, and sometimes protocol translation.

Advantages

  • Single entry point: clients do not need to discover individual service addresses.
  • Centralized routing: internal topology can change without changing public URLs.
  • Consistent security controls: authentication, TLS, request limits, and access policies can be applied before traffic reaches services.
  • Rate limiting: abusive or excessive traffic can be rejected at the platform boundary.
  • Observability: request rates, response codes, latency, and trace context can be captured consistently.
  • Protocol abstraction: external HTTP interfaces can sometimes map to different internal communication mechanisms.

Disadvantages

  • Critical infrastructure dependency: gateway degradation can affect many otherwise healthy services.
  • Additional latency: every external request passes through another network hop.
  • Configuration complexity: routing, policies, certificates, limits, and deployments require operational ownership.
  • Risk of business-logic accumulation: excessive transformation and orchestration can turn the gateway into another monolith.
  • Shared change surface: poorly managed gateway configuration can create coordination between independent teams.

When to Use an API Gateway

An API Gateway is useful when many services need to be exposed through one controlled boundary. It is especially valuable for public APIs, microservice platforms with common security requirements, centralized traffic policies, and systems that need stable external URLs independent of internal topology.

A gateway is usually a good place for generic infrastructure behavior. It is usually a poor place for rules such as calculating whether an order can be cancelled, determining which products belong in a recommendation, or combining domain state into a client-specific workflow.

API Gateway Example

Consider several externally accessible API routes:

GET  /api/orders/123
POST /api/orders
GET  /api/products/42
GET  /api/profile

             |
             v

        API Gateway
       /     |      \
      /      |       \
     v       v        v
 Orders   Catalog   Customer
 Service  Service    Service

The gateway can validate authentication and route the request according to its path:

routes:
  - path: /api/orders/*
    upstream: order-service
    # Authentication and request limits are platform concerns.
    authentication: required
    rate_limit_per_minute: 600

  - path: /api/products/*
    upstream: catalog-service
    authentication: optional
    rate_limit_per_minute: 1200

  - path: /api/profile
    upstream: customer-service
    authentication: required
    rate_limit_per_minute: 300

The gateway does not need to understand how an order is created or how customer profiles are stored. It applies policies and forwards requests to the service that owns the capability.

Backend-for-Frontend

A Backend-for-Frontend is a backend API designed around the requirements of a particular frontend or closely related class of clients. Instead of exposing generic backend service contracts directly, the BFF provides operations and response models optimized for frontend workflows.

A platform might have a Web BFF and Mobile BFF because the clients have different latency, payload, release, and presentation requirements.

Advantages

  • Client-specific contracts: APIs can match the workflows and data required by each frontend.
  • Reduced network round trips: multiple backend calls can be composed into one client request.
  • Smaller payloads: mobile clients can receive only the fields needed for a screen.
  • Frontend independence: internal service decomposition is hidden behind a stable frontend-oriented contract.
  • Independent evolution: web and mobile APIs can change at different speeds when their requirements diverge.

Disadvantages

  • Additional services: every BFF requires deployment, monitoring, ownership, and capacity planning.
  • Logic duplication: similar aggregation code can appear across Web and Mobile BFFs.
  • Potential domain leakage: business rules can accidentally move from owning services into frontend-specific layers.
  • Dependency fan-out: one BFF request can depend on several backend services.
  • Unnecessary complexity: separate BFFs provide little value when all clients require almost identical contracts.

When to Use a BFF

A BFF becomes useful when frontend requirements diverge enough that one generic API creates excessive requests, over-fetching, conditional client logic, or constant compromise between teams.

For example, a desktop order page may display payment details, shipment history, product information, and recommendations. A mobile list view may require only an order number, status, total, and delivery estimate.

A BFF can provide separate contracts without forcing operational microservices to expose presentation-specific endpoints.

BFF Example

A frontend may otherwise need four requests to render an order page:

GET /orders/ord_7281
GET /payments?order_id=ord_7281
GET /shipments?order_id=ord_7281
GET /customers/cus_381

A Web BFF can expose one operation:

GET /web/orders/ord_7281

Internally, independent calls can execute concurrently:

import asyncio


async def get_order_page(
    order_id: str,
    order_client,
    payment_client,
    shipment_client,
) -> dict:
    # Fetch independent dependencies concurrently so latency is
    # approximately bounded by the slowest call instead of their sum.
    order_task = order_client.get_order(order_id)
    payment_task = payment_client.get_by_order(order_id)
    shipment_task = shipment_client.get_by_order(order_id)

    order, payment, shipment = await asyncio.gather(
        order_task,
        payment_task,
        shipment_task,
    )

    # The response is designed for this frontend rather than exposing
    # the complete internal representation of every service.
    return {
        "id": order["id"],
        "status": order["status"],
        "total": order["total"],
        "payment_status": payment["status"],
        "delivery": {
            "status": shipment["status"],
            "estimated_date": shipment["estimated_date"],
        },
    }

This reduces client round trips, but it does not eliminate distributed-system failure modes. The BFF still needs deadlines, concurrency limits, tracing, and explicit behavior when one dependency fails.

Cross-service API composition is also a common data-query strategy. More about choosing between runtime composition and materialized read models can be found here: Managing Data Across Multiple Services.

API Gateway vs BFF

The main difference is responsibility. An API Gateway is infrastructure-oriented; a BFF is client-oriented. A gateway controls how traffic enters the platform, while a BFF determines how backend capabilities are presented to a particular frontend.

Area API Gateway Backend-for-Frontend
Primary responsibility Traffic management and common policies Client-specific API composition
Scope Shared across many APIs Specific frontend or client family
Routing Core responsibility Usually internal dependency calls
Authentication enforcement Common responsibility Consumes validated identity and may enforce application authorization
Rate limiting Strong fit Usually not primary responsibility
Response aggregation Possible, but should remain limited Core responsibility
Client-specific transformations Poor fit at scale Strong fit
Domain business rules Avoid Avoid; keep in owning services
Deployment ownership Often platform team Often frontend/product team
Main scaling dimension Total platform ingress Traffic from a particular client

Choosing the Right Pattern

Use an API Gateway when the problem is routing, authentication enforcement, traffic control, protocol handling, or another concern that should behave consistently across many APIs.

Use a BFF when the problem is that different clients require different backend interactions or response shapes.

Use both when both problems exist:

                Internet
                   |
                   v
              API Gateway
             /           \
            /             \
           v               v
       Web BFF         Mobile BFF
       / |  \            /   \
      v  v   v          v     v
   Orders Catalog    Orders  Profile
      |    Payments     |
      +------ Internal Services ------+

The gateway remains responsible for platform-level ingress policies. Each BFF owns client-specific composition. Domain services remain responsible for business rules and authoritative data.

This separation prevents a single gateway configuration from becoming the implementation layer for every frontend workflow.

Production Design Example

Consider an e-commerce platform supporting a browser application, a mobile application, and external partner integrations. All three consumers need access to some of the same microservices, but their API requirements differ significantly.

The browser needs rich composite pages, the mobile application prioritizes small payloads and fewer requests, and partners need stable domain-oriented APIs that should not depend on frontend presentation requirements.

Combining API Gateway and BFF

A production architecture can separate these responsibilities explicitly:

                    Web Browser
                         |
                    Mobile App
                         |
                  Partner Clients
                         |
                         v
                   API Gateway
              /          |          \
             /           |           \
            v            v            v
        Web BFF      Mobile BFF    Partner API
        / |  \         / |  \           |
       /  |   \       /  |   \          |
      v   v    v     v   v    v         v
   Orders Catalog Payments Profile   Orders
      |      |       |      |           |
      +------+-------+------+-----------+
                         |
                  Domain Services

The API Gateway handles TLS, authentication validation, coarse-grained authorization policies, rate limits, request-size limits, routing, and ingress telemetry.

The Web BFF exposes operations such as:

GET /web/home
GET /web/orders/{id}
GET /web/account
GET /web/checkout

The Mobile BFF can expose smaller responses:

{
  "order_id": "ord_7281",
  "status": "shipped",
  "total": "149.90",
  "delivery_date": "2026-08-14"
}

The Web BFF might return additional shipment history, payment summaries, product images, and related actions for the same order.

Partner integrations should not normally use either BFF because those contracts are tied to frontend needs. A separate stable partner API can expose business capabilities appropriate for external integration.

The gateway can route each client category without understanding the business operation:

routes:
  - path: /web/*
    upstream: web-bff
    authentication: required

  - path: /mobile/*
    upstream: mobile-bff
    authentication: required

  - path: /partner/*
    upstream: partner-api
    authentication: required
    # Partner traffic gets an independent capacity policy.
    rate_limit_per_minute: 300

Authorization still belongs at multiple appropriate boundaries. The gateway can verify identity and reject obviously unauthorized traffic, but an Order Service remains responsible for determining whether a particular identity is permitted to cancel a specific order.

The API contracts behind these layers should remain stable and business-oriented. More about service API boundaries, compatibility, idempotency, and error contracts can be found here: Designing APIs for Microservice Architectures.

Production capacity planning should treat the gateway and BFFs differently. The gateway scales according to total ingress traffic, while each BFF scales according to its frontend workload and dependency fan-out. A single Web BFF request that triggers five internal calls can generate substantially more backend traffic than its external request rate suggests.

For example:

Web traffic:                4,000 requests/sec
Average BFF fan-out:          3.5 backend calls
------------------------------------------------
Generated backend traffic: 14,000 calls/sec

Mobile traffic:             6,000 requests/sec
Average BFF fan-out:          1.8 backend calls
------------------------------------------------
Generated backend traffic: 10,800 calls/sec

Capacity models should therefore include fan-out amplification, connection pools, dependency concurrency, cache behavior, and downstream rate limits rather than considering only incoming requests.

Common Mistakes

Gateway and BFF problems usually appear when responsibilities are mixed or an intermediate layer accumulates behavior that belongs to domain services.

Mistake Why It Causes Problems Better Approach
Putting business logic in the API Gateway The shared ingress layer becomes coupled to many domains and increasingly difficult to deploy safely. Keep gateway behavior focused on routing and cross-cutting infrastructure policies.
Using one BFF for every unrelated client Client-specific conditions accumulate until the BFF becomes another general-purpose backend. Separate BFFs when client requirements and release patterns materially diverge.
Creating a BFF for every frontend automatically Nearly identical APIs duplicate code, infrastructure, deployments, and operational work. Add separate BFFs only when client requirements justify independent contracts.
Moving domain rules into BFFs Business behavior becomes duplicated across clients and can produce inconsistent decisions. Keep authoritative business rules inside domain services.
Allowing unbounded BFF fan-out One external request can create excessive backend traffic and amplify overload. Bound concurrency, reduce dependencies, cache suitable reads, or create purpose-built projections.
Calling BFF dependencies sequentially Independent service latencies accumulate and make composite endpoints unnecessarily slow. Execute independent calls concurrently within an explicit latency budget.
Treating the gateway as the only authorization layer Infrastructure policies cannot reliably enforce resource-specific domain permissions. Validate identity at ingress and enforce domain authorization inside owning services.
Ignoring partial dependency failures A non-critical recommendation or profile service can make an entire composite page unavailable. Classify dependencies as required or optional and define degraded responses explicitly.
Sharing gateway configuration without ownership controls One team's routing or policy change can affect unrelated APIs. Use automated validation, scoped configuration ownership, and controlled deployments.
Exposing BFF APIs to external integrations Partners become coupled to presentation-specific contracts that change with frontend requirements. Provide stable domain-oriented external APIs separately.
Ignoring gateway capacity A shared ingress bottleneck can affect every backend even when individual services have spare capacity. Measure gateway saturation, latency, connection limits, and throughput independently.
Monitoring only external requests BFF fan-out, dependency latency, and internal errors remain hidden behind one client request. Trace each composite request across the gateway, BFF, and downstream services.

Production Checklist

Gateway and BFF layers should have explicit responsibilities, failure policies, and independent capacity models before they become critical request-path components.

  • Define layer responsibilities: document which concerns belong to the gateway, BFFs, and domain services.
  • Keep business rules in domain services: prevent client-specific layers from becoming alternative sources of business truth.
  • Use stable routing: hide internal service topology behind external API contracts.
  • Enforce ingress limits: configure request-size, rate, connection, and timeout limits before traffic reaches backend services.
  • Set BFF latency budgets: assign deadlines to downstream calls based on the client endpoint's total latency target.
  • Bound fan-out: measure how many backend calls each BFF operation generates and control concurrency.
  • Parallelize independent reads: avoid sequential dependency calls when no ordering requirement exists.
  • Classify dependencies: decide which downstream failures must fail the request and which can produce degraded responses.
  • Propagate identity securely: preserve authenticated identity without allowing clients to forge internal identity headers.
  • Enforce domain authorization: validate resource-specific permissions inside the service owning the operation.
  • Propagate trace context: correlate gateway requests with BFF and downstream service calls.
  • Measure fan-out amplification: include generated internal traffic when planning backend capacity.
  • Scale layers independently: size the gateway for total ingress and each BFF for its own workload and dependency profile.
  • Test degraded operation: verify behavior when optional dependencies are slow, unavailable, or returning partial data.
  • Keep partner contracts separate: avoid exposing presentation-oriented BFF endpoints as long-lived integration APIs.

Conclusion

API Gateways and Backend-for-Frontend services address different architectural concerns. A gateway provides a controlled entry point and centralizes infrastructure policies, while a BFF adapts backend capabilities to the requirements of a specific client.

Combining the patterns can provide a clean separation: gateway for ingress concerns, BFF for client composition, and domain services for business behavior. The design becomes problematic when these responsibilities collapse into one large intermediary layer.

Key Takeaway

Use an API Gateway to control how traffic enters the platform and a BFF to control how backend capabilities are presented to a specific frontend. Keep domain rules in the services that own them, and treat gateway latency, BFF fan-out, dependency failures, and observability as first-class production concerns.

Comments (0)