DEV Community

Nadeem Ur-Rehman
Nadeem Ur-Rehman

Posted on

Your 'BFF' Is Just a Second Backend With Better Marketing

Watch the 40-second version: Backend-for-Frontend Explained for Interviews (Q15/60)

The screen needed five microservice calls to render. Profile from here, orders from there, pricing from somewhere else, and two nobody could explain. So the team did the sensible thing. They built a BFF.

Six months later the BFF had its own database, its own cron jobs, business logic nobody would claim in a meeting, and an on-call rotation. Congratulations. You did not build a backend-for-frontend. You built a second backend and gave it a frontend pattern's name so nobody would ask questions.

I have watched this exact movie more than once. It starts with pure intentions. The frontend is chatty, mobile users on bad connections are suffering, so someone stands up a thin aggregation layer. Thin is doing a lot of work in that sentence, because thin is a property of the present. Give it two quarters and thin quietly becomes "well, the logic has to live SOMEWHERE."

Here is the line interviewers are really testing when they ask where a BFF fits. A BFF has one job: translate the product journey. Aggregate the calls. Shape the payload for the screen. Enforce what this channel is allowed to see. Hide the service topology so the frontend never learns how many services you really have. Domain rules stay in the owning services. The day your BFF starts owning business logic, it stopped being a BFF. Call it what it is and staff it like one.

The non-obvious part: The BFF's real value is what it deletes. Every round trip your phone does not make on a bad connection is latency your users never feel and a failure mode you never debug at 2 a.m. And if you think one BFF can serve web, mobile, and the partner API, enjoy your new distributed monolith. One channel, one BFF. Shared BFFs drift. It is the same gravity that made the monolith, just with more YAML.

The 30-second BFF audit. Run this on yours today:

  1. Does it own business logic? Move it to the owning service.
  2. Does it have its own database? Then it is a backend. Rename it honestly.
  3. Could you rebuild it from the service contracts in a day? If not, it grew roots.
  4. Does each channel get its own BFF? Shared ones drift into monoliths.

In Angular, the cleanest consumer of a BFF is a route resolver. One call in, and the route does not activate until the screen-shaped payload arrives:

@Injectable({ providedIn: 'root' })
export class DashboardResolver implements Resolve<DashboardVm> {
  constructor(private http: HttpClient) {}
  resolve(): Observable<DashboardVm> {
    // one request out, five service calls hidden behind the BFF
    return this.http.get<DashboardVm>('/bff/dashboard');
  }
}
// route: { path: 'dashboard', component: DashboardComponent,
//          resolve: { vm: DashboardResolver } }
Enter fullscreen mode Exit fullscreen mode

Five service calls, one HTTP request, zero business logic in the middle. That is the whole pattern. Keep it boring and it stays a BFF.

I broke this down in 40 seconds here: https://www.youtube.com/shorts/XTJ6mufbTj8

Top comments (0)