React + Spring Full-Stack Architecture: The BFF Pattern
The BFF (Backend for Frontend) pattern between a React frontend and Spring backend: when it is needed, identity and session management, aggregation, contract discipline and comparison with alternatives.
What is a BFF and which problem does it solve?
A BFF (Backend for Frontend) is a thin backend layer dedicated to one specific frontend — web, mobile, any client without a shared denominator — shaped by that frontend's needs. The problem it solves is clear: general-purpose APIs fit no client perfectly; clients either over-fetch, make too many calls, or copy business logic into themselves. The BFF resolves that mismatch at the server layer closest to the client.
When BFF, when direct API?
Situation | Direct API suffices | BFF signal |
|---|---|---|
Client count | One web client | Web + mobile + third parties with different needs |
Calls per page | 1-2 endpoints | One screen aggregates 5+ services |
Identity model | Simple token flow is enough | httpOnly session in browser, tokens kept server-side |
Response shaping | Backend DTOs fit the screens | Screen model differs markedly from backend model |
Team structure | One full-stack team | Frontend team can own its server layer |
The BFF's three main jobs
Aggregation: collecting what a screen needs from multiple Spring services and returning it as one response shaped as the screen model — call orchestration and waterfall latency disappear from the client. Adaptation: arranging field names, formats and pagination for the screen; preserving the screen contract even when backend contracts change. The identity boundary: session management without leaking tokens to the browser — covered below. The shared rule across all three: no business rules in the BFF; rules live in domain services, the BFF is an experience layer only. When that line blurs, the BFF becomes a second, hard-to-maintain monolith.
Identity and sessions: the BFF's strongest justification
The model that fundamentally resolves the SPA token-storage dilemma (localStorage's XSS exposure) is tokens never reaching the browser at all: the BFF drives the OAuth/OIDC flow; access/refresh tokens are held server-side; between browser and BFF only an httpOnly + Secure + SameSite session cookie travels. The React client never sees a token; the BFF attaches tokens to downstream calls itself. In security reviews this pattern is the cleanest answer to "where are tokens stored?" — and it requires CSRF protection (SameSite + tokens) to be built correctly in the BFF.
Implementation on the Spring side
In the Spring ecosystem a BFF is built along two mature paths: a reactive service on WebFlux/WebClient for highly concurrent aggregation, or a simple blocking model on Java 21 virtual threads — both handle parallel downstream calls efficiently. Spring Cloud Gateway offers a ready skeleton when routing + filter needs approach the BFF's; the OAuth client support (spring-security-oauth2-client) assembles the session pattern above from standard components. The resilience minimum: a timeout on every downstream call, a partial-failure strategy (per-section errors instead of failing the whole screen) and circuit breakers.
Contract discipline: the screen model is an API too
The screen models a BFF returns are the formal contract between frontend and BFF: define them with OpenAPI, generate TypeScript types from that definition, and version breaking changes. GraphQL is the alternative solution to the same problem — flexible query power in exchange for server-side complexity (N+1 resolvers, query cost control); if the team lacks GraphQL maturity, a well-designed REST BFF is more predictable in most enterprise scenarios.
Business impact: team velocity, architecturally
The BFF's return is measured in screen development speed: the frontend team adds fields and reshapes responses in its own layer without waiting for the backend sprint; mobile and web evolve without breaking each other's API. The cost must be written honestly too: one more service to operate, one more pipeline. Our decision criterion is practical: if calls-per-screen, token storage needs and client diversity point to BFF in the table, the investment pays back quickly; if not, direct APIs with good DTO design are enough.
Frequently asked questions
Is a BFF the same as an API gateway?
No: a gateway is client-agnostic horizontal infrastructure (routing, rate limiting, TLS); a BFF is an experience layer dedicated to one frontend. They can be used together.
Is a separate BFF per client mandatory?
The pattern's name suggests it, but pragmatism rules: clients whose needs truly diverge earn separate BFFs; two similar web experiences can share one.
Do Next.js API routes count as a BFF?
Functionally yes — they can take on the same jobs. In an enterprise Java ecosystem, a Spring-based BFF usually integrates better with team skills, observability and security standards.
How do we prevent business logic drifting into the BFF?
With a written rule and code review: composition and formatting allowed, business rules and persistent state forbidden. The test: if the same rule is needed by a second client, its home is the domain service.
BFF checklist
BFF need validated against the decision table
Tokens server-side; browser holds only an httpOnly session cookie
CSRF protection (SameSite + tokens) built in the BFF
Timeouts + circuit breakers + partial-failure strategy on downstream calls
Screen models defined in OpenAPI; TS types generated
Business-rule boundary written; enforced in code review
BFF metrics (per-screen latency, downstream breakdown) dashboarded
SSH Yazılım designs and implements BFF architectures end to end in React + Spring projects. Let us sharpen your frontend-backend boundary together.