Backend-for-frontend as a deliberate "the UI knows nothing about source systems" boundary
A backend-for-frontend earns its keep when the UI should not know which systems supply the data. On a recent consolidation project, the upstream pipeline pivoted two weeks before contract end and the front end never noticed. That is the test.
The boundary that actually matters
I want to talk about backend-for-frontend, or BFF, in a way that I think is more useful than the framework conversations usually allow. BFF is not really a piece of technology. It is a boundary you choose to maintain, with a specific job: keeping the front end ignorant of where its data comes from.
That ignorance is the whole point. If your UI knows that some data comes from one system and some from another, you have not built a BFF. You have built a thin proxy that happens to sit in front of several back ends, and you are paying the cost of an extra hop for none of the benefit.
So the question I want to answer here is a simple one. When is that boundary worth maintaining, and when is it overhead you do not need?
What a BFF actually buys you
In plain language, a BFF gives the front end a single stable contract, while leaving the seams behind it free to move.
That is the whole offer. The UI talks to one place. It asks questions in the shape it wants the answers in. Behind the BFF, you can rearrange source systems, change ingestion schedules, swap a vendor, fix a calculation, and the front end stays still.
If you do not need that property, you do not need a BFF. You have a back end, and that is fine.
The decision criterion
Here is the question I ask before I reach for this pattern.
Are there multiple back-end concerns that the UI should not see?
If the answer is yes, a BFF is paying for something real. If the answer is no, then you are about to build two back ends where one would do, and you will spend the rest of the project keeping them in sync.
A concrete example of "yes": a dashboard that consolidates information about a person from a primary system, a nightly batch ingest from a second system, and a deep link into a third system that you cannot replace yet. The UI should not know any of that. It should ask "give me everything about this person" and get an answer.
A concrete example of "no": a single CRUD application with one database, one team, and one product. Putting a BFF in front of that gains you nothing and adds a layer that has to be maintained, deployed, versioned, and reasoned about.
A concrete shape
The shape I find works well on consolidation projects has three parts, viewed from the front end's perspective.
First, the front end itself. It speaks only to the BFF. It has no knowledge of source systems, ingestion timing, or which calculations live where.
Second, the BFF. Deliberately thin. Its job is to expose the data shape the UI needs, and nothing else. It does not do the heavy lifting of consolidation, and it does not own the rules.
Third, behind the BFF, a consolidation engine where the actual domain logic lives. That engine knows about source systems, about how to reconcile them, about which numbers come from which feed and how to combine them. It is the place where a domain expert can iterate on rules without anything else moving.
The source systems sit further back again. Their schemas never reach the front end. That is not an accident, and it is not a side effect of how the layers happened to fall out. It is a constraint I impose on purpose, and I defend it during the build.
Designing the contract
Most of the value of a BFF lives in the design of its contract, so it is worth being explicit about how I think about that.
The contract should model the questions the UI is asking, not the schemas of the source systems.
On the engagement I have in mind, the dashboard had a concept of a "learner overview". A supervisor needed to see, on one screen, where a particular learner was across several streams of activity that lived in different upstream systems. The temptation, when designing the BFF, is to expose endpoints that mirror the source systems, and let the front end stitch them together.
That is the trap. The moment the BFF starts mirroring source-system shapes, you have built two back ends instead of one, and the front end is back in the business of knowing where things come from.
So instead, the BFF endpoint was "learner overview". One call. Returns everything the supervisor needs about that learner, across all sources, in one shape. The shape was designed around what the screen needed to render, not around what the upstream feeds happened to provide.
That is the discipline. Every endpoint is named after a question the UI asks. Every response is shaped for a screen, or a section of a screen, or a workflow step. Source-system vocabulary stays behind the BFF.
The trap of the leaky pass-through
I want to spend a moment on this because it is the most common failure mode I see.
A BFF that is a leaky pass-through looks fine in the early weeks. The front end calls one URL. There is, technically, a layer in between. The architecture diagram has the right boxes on it.
Then someone needs a field that is in source system A but not in source system B, so a flag appears in the response. Then a deadline pushes someone to expose a "raw" endpoint "just for now". Then the front end starts branching on which source the data came from, because the BFF is now telling it. By month six, the front end has detailed knowledge of every back end, and the BFF is a tax rather than a boundary.
The fix is not technical. It is editorial. Someone has to say no to shapes that leak source-system structure into the UI, and yes to the work of designing a UI-centric shape instead. If nobody is doing that work, the boundary will erode, and the cost of the layer will exceed its value.
A concrete payoff
The reason I am confident in this pattern is that I have watched it earn its keep under pressure.
On the engagement I mentioned, the upstream data pipeline had to be pivoted with about two weeks left on the contract. The internals of how data was being consolidated had to change in a fairly fundamental way.
The BFF contract did not move. The front end was unaware anything had happened.
That is the test of whether you have a real boundary or a paper one. If a meaningful change to the back of the system can happen without the front end noticing, the boundary is doing its job. If every back-end change ripples into the UI, the boundary exists in name only and you should stop pretending it is buying you anything.
A second, smaller payoff from the same engagement. The domain expert iterated on the calculations behind the consolidation engine more than once during the build. Every time, the BFF contract stayed still, and the front end stayed still. The work landed where it should have landed, in the engine, and nowhere else had to be touched.
When a BFF is overkill
I am wary of architecture patterns being recommended without the conditions that make them sensible, so let me be direct about when I would not use one.
If you have a small system with a single back end, no consolidation across sources, and a single team owning everything from the UI down to the database, do not put a BFF in. You will gain nothing and pay for the extra layer in deployment, versioning, and cognitive load.
If you have one back end today and you suspect you might have more later, I would still not pre-emptively introduce a BFF. I would introduce it when the second concern actually arrives, because the shape of the contract should be informed by the real second source, not a guess at it.
If your front end is genuinely happy talking to one back-end service, that service is your back end. Calling it a BFF does not make it one.
The boundary, not the tool
The thing I want a non-technical reader to take away from this is that BFF is a boundary, not a tool.
Choosing it is a choice to maintain a property over time: that the front end does not know where its data comes from. Defending it is editorial work, week after week, on every endpoint and every change request. The framework you use to implement it barely matters. The discipline does.
So the decision in front of you, if you are weighing this for your own product, is not "should I use a BFF framework". It is "is the property of UI ignorance worth maintaining for this product, given how many back-end concerns the UI is shielding the user from".
If the answer is yes, the pattern earns its place, and you should design the contract around the questions the UI is asking. If the answer is no, you have a back end, and that is the right answer for plenty of products.
If you are looking at a consolidation project and trying to work out whether this boundary is worth the cost on your build, I am happy to talk it through. No pitch, just a conversation about the shape of what you have got.
