Nicolás Duque

Backend for frontend: one API per kind of client

Jan 28, 2026 · 3 min read

A healthcare platform doesn't have one kind of user. At Doktor24 there were patients, practitioners, and people configuring the platform for partners. They all touched the same underlying data, but they needed it in very different shapes. Alongside the frontend work, I built and maintained Backend-for-Frontend (BFF) services in Node.js, each tailored to one of those clients.

The problem with one API for everyone

When every client talks to the same general-purpose API, one of two things happens:

  • The API grows fields and endpoints for every screen, and becomes hard to change because everyone depends on it.
  • Or the API stays generic, and each frontend makes many calls and stitches the data together itself, which is slow and duplicates logic in the browser or the app.

Different users also have different rules about what they're allowed to see. Mixing all of that into one surface makes mistakes more likely.

What a BFF is

A BFF is a thin backend owned by, and designed for, one kind of client. The patient app talks to the patient BFF. The practitioner tool talks to the practitioner BFF. The configurator talks to its own. Each BFF calls the core services and returns exactly what its client needs.

What belongs in a BFF

The rule I follow: a BFF adapts, it doesn't decide.

Good things to put in a BFF:

  • Aggregation. Combine calls to several core services into one response for a screen.
  • Shaping. Rename, trim and format data for the client, so the UI stays simple.
  • Client-specific access checks. What this kind of user can see, enforced before data leaves the backend.
  • Client-specific concerns. Pagination style, caching headers, payload size for mobile.

What doesn't belong in a BFF

  • Business rules. If the rule matters for every client, it lives in a core service. Otherwise the patient and practitioner paths will slowly disagree.
  • Data ownership. A BFF shouldn't be the source of truth for anything.
  • Shared logic copied between BFFs. If you find the same code in two BFFs, it probably belongs in a core service or a shared library.

Trade-offs

BFFs are more services to build, deploy and monitor. They can also become a dumping ground if the team isn't disciplined about the rule above. In return you get:

  • Frontends that are simpler and faster to change.
  • Core services that stay generic and stable.
  • A clear place for each client's access rules.
  • Teams that can change their API without negotiating with every other client.

This fit well with the micro-frontend architecture I described in Micro-frontends with Module Federation: a team could own its part of the UI and the API shaped for it.

When to skip it

If you have one client, or several clients that need nearly the same data, a BFF is overhead. A well-designed API, or GraphQL where clients select what they need, may be enough. BFFs earn their place when clients are genuinely different: different users, different permissions, different devices.

What I'd recommend

  1. One BFF per kind of client, not per screen.
  2. Keep business rules in core services; BFFs only aggregate and shape.
  3. Enforce access rules in the BFF as well as in core services, never only in the UI.
  4. Let the team that owns the client own its BFF.

The pattern is simple, but it's one of the most reliable ways I know to keep several frontends moving without tangling the backend.