Backend for Frontend Pattern: What It Is and When to Use
Backend for Frontend (BFF) pattern creates a dedicated backend service for each user interface or client type. It acts as a tailored middle layer that simplifies and optimizes communication between the frontend and multiple backend services.How It Works
Imagine you have different types of users accessing your app: a web browser, a mobile app, and maybe a smart TV app. Each of these clients needs data in a slightly different way. Instead of making each client talk directly to many backend services, the Backend for Frontend (BFF) pattern creates a special backend just for each client type.
This BFF acts like a personal assistant who knows exactly what the client needs. It gathers data from various backend services, combines it, and sends back only what the client requires. This makes the frontend simpler and faster because it gets exactly the right data in the right format.
Think of it like ordering food: instead of going to multiple kitchens yourself, you have a waiter (the BFF) who collects all your dishes and brings them to your table ready to eat.
Example
This example shows a simple BFF service in Node.js using Express. It fetches user info and order data from two backend services and combines them for a mobile app client.
import express from 'express'; import fetch from 'node-fetch'; const app = express(); const PORT = 3000; // Simulated backend service URLs const USER_SERVICE_URL = 'https://api.example.com/users'; const ORDER_SERVICE_URL = 'https://api.example.com/orders'; app.get('/mobile/user-dashboard', async (req, res) => { try { const userId = req.query.userId; // Fetch user info const userResponse = await fetch(`${USER_SERVICE_URL}/${userId}`); const user = await userResponse.json(); // Fetch user orders const ordersResponse = await fetch(`${ORDER_SERVICE_URL}?userId=${userId}`); const orders = await ordersResponse.json(); // Combine data tailored for mobile client const dashboardData = { name: user.name, recentOrders: orders.slice(0, 3), notifications: user.notifications || [] }; res.json(dashboardData); } catch (error) { res.status(500).json({ error: 'Failed to fetch dashboard data' }); } }); app.listen(PORT, () => { console.log(`BFF server running on port ${PORT}`); });
When to Use
Use the Backend for Frontend pattern when you have multiple client types (web, mobile, IoT) that need different data shapes or workflows. It helps keep frontend code simple and reduces the number of calls each client makes.
It is especially useful when backend services are shared and complex, and you want to avoid exposing all backend details to every client. For example, a mobile app might need less data or a different format than a web app.
Real-world use cases include large e-commerce sites, social media platforms, or any system with diverse user interfaces needing optimized data delivery.
Key Points
- The BFF pattern creates a backend service dedicated to each frontend client.
- It simplifies frontend logic by tailoring data and APIs per client.
- Helps reduce over-fetching or under-fetching of data.
- Improves performance and user experience by optimizing data delivery.
- Useful in microservices where backend APIs are shared but clients differ.