Patrón arquitectónico donde cada tipo de cliente tiene su propio backend dedicado que adapta las APIs de microservicios a las necesidades específicas de ese cliente.
Backend for Frontend (BFF) es un patrón arquitectónico donde cada tipo de cliente — web, móvil, IoT, aplicaciones de escritorio — tiene su propio backend dedicado. En lugar de forzar a todos los clientes a consumir las mismas APIs genéricas, cada BFF actúa como una capa de adaptación que agrega, transforma y optimiza datos específicamente para las necesidades de su cliente.
El patrón surge de la realidad práctica de que diferentes clientes tienen diferentes patrones de acceso a datos, restricciones de red, capacidades de procesamiento y experiencias de usuario. Una aplicación web puede necesitar datos ricos y detallados, mientras que una aplicación móvil requiere respuestas más ligeras y optimizadas para conexiones lentas. Un dispositivo IoT podría necesitar solo un subconjunto mínimo de datos en formato binario.
Cada BFF es propiedad del equipo frontend correspondiente, lo que permite mayor autonomía y velocidad de desarrollo. Esto contrasta con un API Gateway centralizado que intenta servir a todos los clientes con una interfaz única.
El patrón más común es crear un BFF dedicado para cada plataforma cliente:
// BFF Web - Optimizado para aplicaciones web
app.get('/api/dashboard', async (req, res) => {
const [user, analytics, notifications, settings] = await Promise.all([
userService.getProfile(req.userId),
analyticsService.getDashboardData(req.userId),
notificationService.getRecent(req.userId, 10),
settingsService.getUserPreferences(req.userId)
]);
// Agregación rica para web con múltiples widgets
res.json({
user: {
name: user.fullName,
avatar: user.profileImage,
role: user.role
},
dashboard: {
metrics: analytics.summary,
charts: analytics.chartData,
notifications: notifications.map(n => ({
id: n.id,
message: n.content,
timestamp: n.createdAt,
priority: n.priority
})),
quickActions: settings.enabledActions
}
});
});
// BFF Mobile - Optimizado para dispositivos móviles
app.get('/api/dashboard', async (req, res) => {
const [user, criticalNotifications] = await Promise.all([
userService.getProfile(req.userId),
notificationService.getCritical(req.userId, 3)
]);
// Respuesta ligera para móvil
res.json({
user: user.displayName,
avatar: user.thumbnailImage,
alerts: criticalNotifications.length,
hasUpdates: criticalNotifications.length > 0
});
});GraphQL puede actuar como un BFF natural, permitiendo a cada cliente solicitar exactamente los datos que necesita:
# Schema GraphQL como BFF
type Query {
dashboard(platform: Platform!): DashboardData
}
type DashboardData {
user: User
metrics: [Metric]
notifications: [Notification]
settings: UserSettings
}
enum Platform {
WEB
MOBILE
TABLET
}// Resolver que adapta según la plataforma
const resolvers = {
Query: {
dashboard: async (_, { platform }, { userId }) => {
const baseData = await getDashboardData(userId);
switch (platform) {
case 'WEB':
return {
...baseData,
metrics: baseData.metrics, // Datos completos
notifications: baseData.notifications.slice(0, 10)
};
case 'MOBILE':
return {
user: baseData.user,
metrics: baseData.metrics.filter(m => m.priority === 'HIGH'),
notifications: baseData.notifications.slice(0, 3)
};
default:
return baseData;
}
}
}
};El patrón BFF añade complejidad innecesaria en ciertos escenarios:
| Aspecto | BFF | API Gateway | GraphQL |
|---|---|---|---|
| Propósito | Adaptar datos por cliente | Enrutar y proteger | Query flexible |
| Propiedad | Equipo frontend | Equipo de plataforma | Compartido |
| Lógica de negocio | Agregación y transformación | Routing y autenticación | Resolución de datos |
| Cantidad | Uno por tipo de cliente | Uno centralizado | Uno con múltiples queries |
| Complejidad | Media-Alta | Baja-Media | Media |
| Flexibilidad | Alta por cliente | Baja | Muy alta |
| Overhead de red | Optimizado | Variable | Optimizado |
// ❌ Antipatrón: BFF que solo reenvía llamadas
app.get('/api/users/:id', (req, res) => {
// Solo proxy, sin valor añadido
return userService.getUser(req.params.id);
});// ✅ Patrón correcto: BFF que agrega valor
app.get('/api/users/:id', async (req, res) => {
const [user, permissions, preferences] = await Promise.all([
userService.getUser(req.params.id),
authService.getUserPermissions(req.params.id),
settingsService.getPreferences(req.params.id)
]);
return {
profile: {
name: user.fullName,
email: user.email,
avatar: user.profileImage
},
capabilities: permissions.map(p => p.action),
settings: preferences.ui
};
});Los BFFs deben limitarse a agregación y transformación de datos, no implementar lógica de negocio compleja que debería residir en los microservicios subyacentes.
Un BFF puede coexistir con otros patrones arquitectónicos:
El patrón BFF resuelve el problema fundamental de APIs genéricas que intentan servir múltiples clientes con necesidades divergentes. En organizaciones con equipos frontend autónomos, permite que cada equipo optimice su backend para patrones de acceso específicos sin impactar otros clientes. Esto reduce la latencia, mejora la experiencia de usuario y acelera el desarrollo al eliminar dependencias entre equipos. Sin embargo, introduce complejidad operacional — cada BFF debe ser desplegado, monitoreado y mantenido independientemente, lo que requiere considerar cuidadosamente el tradeoff entre autonomía del equipo y overhead de infraestructura.
Estilo arquitectónico que estructura una aplicación como colección de servicios pequeños, independientes y desplegables, cada uno con su propia lógica de negocio y datos.
Principios y prácticas para diseñar interfaces de programación claras, consistentes y evolucionables que faciliten la integración entre sistemas.
Patrón que proporciona un punto de entrada único para múltiples microservicios, manejando routing, autenticación, rate limiting y agregación de respuestas.
Patrón arquitectónico que extiende los microservicios al frontend, permitiendo que equipos independientes desarrollen y desplieguen partes de una aplicación web de forma autónoma.
Patrón arquitectónico donde los componentes se comunican mediante eventos asíncronos, permitiendo sistemas desacoplados, escalables y reactivos.