Serverless y Edge Computing: El Futuro de la Arquitectura Backend en 2025
Hola HaWkers, ¿todavía estás gestionando servidores manualmente o ya migraste al futuro?
En 2025, la arquitectura de backend pasó por una transformación radical. Serverless dejó de ser un buzzword para convertirse en el estándar de la industria, y edge computing está llevando esa revolución aún más lejos - ejecutando código a milisegundos de tus usuarios, en cualquier lugar del mundo.
Empresas están migrando activamente a estas tecnologías porque resuelven problemas reales: mejor SEO, performance superior, costos de servidor reducidos, y escalabilidad automática sin dolor de cabeza.
Qué Cambió en 2025: Serverless Creció
Serverless computing permite correr código sin gestionar servidores. Te enfocas en el código, y la plataforma se encarga de provisioning, scaling, monitoring y todo lo demás.
¿Por qué serverless explotó en 2025?
- Costo: Paga solo por lo que uses (ejecución real, no uptime)
- Escalabilidad: Auto-scaling de 0 a millones de requests
- Simplicidad: Deploy con un comando, sin DevOps complejo
- Cold Start Resuelto: Plataformas modernas redujeron cold starts a <50ms
- DX Mejorada: Herramientas maduras y experiencia de desarrollador excelente
// Ejemplo: Edge Function en Vercel (Next.js 15)
// app/api/user-location/route.ts
import { NextRequest, NextResponse } from 'next/server';
// Esta función corre en el edge, cerca del usuario
export const runtime = 'edge';
export async function GET(request: NextRequest) {
// Geolocation automática del edge runtime
const country = request.geo?.country || 'Unknown';
const city = request.geo?.city || 'Unknown';
const latitude = request.geo?.latitude || 0;
const longitude = request.geo?.longitude || 0;
// Personalizar respuesta basado en la ubicación
const greeting = getLocalizedGreeting(country);
// Buscar datos del banco más cercano geográficamente
const nearestDbRegion = getNearestRegion(latitude, longitude);
return NextResponse.json({
location: {
country,
city,
coordinates: { latitude, longitude }
},
greeting,
dbRegion: nearestDbRegion,
latency: 'sub-50ms', // ¡Magia del Edge!
timestamp: new Date().toISOString()
});
}
function getLocalizedGreeting(country: string): string {
const greetings: Record<string, string> = {
BR: 'Olá! 🇧🇷',
US: 'Hello! 🇺🇸',
GB: 'Hello! 🇬🇧',
ES: 'Hola! 🇪🇸',
FR: 'Bonjour! 🇫🇷',
DE: 'Hallo! 🇩🇪',
JP: 'こんにちは! 🇯🇵',
};
return greetings[country] || 'Hello! 🌍';
}
function getNearestRegion(lat: number, lon: number): string {
// Simplificado - en la práctica usa algoritmo de distancia real
if (lat > 0 && lon < -30) return 'us-east-1';
if (lat > 0 && lon > 0) return 'eu-west-1';
if (lat < 0 && lon < 0) return 'sa-east-1';
return 'ap-southeast-1';
}Este código corre en más de 100 ubicaciones globales simultáneamente. ¿Usuario en Brasil? Código corre en São Paulo. ¿Usuario en Japón? Código corre en Tokyo. Latencia siempre baja.
Edge Computing: Llevando Serverless al Siguiente Nivel
Edge computing ejecuta código lo más cerca posible del usuario final, no en data centers centralizados. Esto reduce latencia drásticamente y mejora experiencia del usuario.
Principales Plataformas Edge en 2025:
- Cloudflare Workers: 300+ ubicaciones, runtime V8 aislado
- Vercel Edge Functions: Integración perfecta con Next.js
- AWS Lambda@Edge: Integrado con CloudFront CDN
- Deno Deploy: Runtime moderno con soporte TypeScript nativo
- Netlify Edge Functions: Deno-based, global distribution
Mira un ejemplo práctico con Cloudflare Workers:
// Cloudflare Worker - A/B Testing en el Edge
export interface Env {
KV_NAMESPACE: KVNamespace;
ANALYTICS: AnalyticsEngineDataset;
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url);
// Implementar A/B testing en el edge - cero latencia
const variant = getABTestVariant(request);
// Log para analytics (asíncrono, no bloquea respuesta)
env.ANALYTICS.writeDataPoint({
blobs: [variant, url.pathname],
doubles: [Date.now()],
indexes: [request.headers.get('cf-ipcountry') || 'unknown']
});
// Buscar contenido personalizado del KV (edge storage)
const cachedContent = await env.KV_NAMESPACE.get(
`content:${variant}:${url.pathname}`,
{ type: 'json' }
);
if (cachedContent) {
return new Response(JSON.stringify(cachedContent), {
headers: {
'Content-Type': 'application/json',
'Cache-Control': 'public, max-age=3600',
'X-Variant': variant,
'X-Edge-Location': request.cf?.colo || 'unknown'
}
});
}
// Fetch del origen si no está en cache
const originResponse = await fetch(
`https://api.example.com${url.pathname}?variant=${variant}`,
{
headers: {
'X-Forwarded-For': request.headers.get('cf-connecting-ip') || '',
'User-Agent': request.headers.get('user-agent') || ''
}
}
);
const data = await originResponse.json();
// Cache en el edge para próximos requests
await env.KV_NAMESPACE.put(
`content:${variant}:${url.pathname}`,
JSON.stringify(data),
{ expirationTtl: 3600 }
);
return new Response(JSON.stringify(data), {
headers: {
'Content-Type': 'application/json',
'X-Variant': variant,
'X-Cache': 'MISS'
}
});
}
};
function getABTestVariant(request: Request): string {
// Verificar cookie existente
const cookies = request.headers.get('cookie') || '';
const variantMatch = cookies.match(/variant=([AB])/);
if (variantMatch) {
return variantMatch[1];
}
// Distribución 50/50 basado en el IP
const ip = request.headers.get('cf-connecting-ip') || '';
const hash = simpleHash(ip);
return hash % 2 === 0 ? 'A' : 'B';
}
function simpleHash(str: string): number {
let hash = 0;
for (let i = 0; i < str.length; i++) {
hash = ((hash << 5) - hash) + str.charCodeAt(i);
hash = hash & hash; // Convertir a entero de 32bit
}
return Math.abs(hash);
}
AWS Lambda: El Gigante del Serverless
AWS Lambda aún domina el mercado serverless en 2025, pero evolucionó significativamente:
// AWS Lambda con Node.js 20 y TypeScript
// handler.ts
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import { DynamoDBDocumentClient, QueryCommand, PutCommand } from '@aws-sdk/lib-dynamodb';
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
// Inicializar clientes fuera del handler (reutilización entre invocaciones)
const dynamoClient = new DynamoDBClient({ region: 'us-east-1' });
const docClient = DynamoDBDocumentClient.from(dynamoClient);
const s3Client = new S3Client({ region: 'us-east-1' });
interface OrderEvent {
userId: string;
items: Array<{ productId: string; quantity: number; price: number }>;
total: number;
}
export const handler = async (
event: APIGatewayProxyEvent,
context: Context
): Promise<APIGatewayProxyResult> => {
// Context info útil para debugging
console.log('Request ID:', context.requestId);
console.log('Function name:', context.functionName);
console.log('Memory limit:', context.memoryLimitInMB);
try {
const body: OrderEvent = JSON.parse(event.body || '{}');
// Validación
if (!body.userId || !body.items?.length) {
return {
statusCode: 400,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ error: 'Invalid order data' })
};
}
// Crear pedido en DynamoDB
const orderId = generateOrderId();
const timestamp = new Date().toISOString();
await docClient.send(new PutCommand({
TableName: process.env.ORDERS_TABLE!,
Item: {
orderId,
userId: body.userId,
items: body.items,
total: body.total,
status: 'pending',
createdAt: timestamp,
ttl: Math.floor(Date.now() / 1000) + (90 * 24 * 60 * 60) // 90 días
}
}));
// Guardar recibo en S3 para auditoría
const receipt = {
orderId,
...body,
timestamp
};
await s3Client.send(new PutObjectCommand({
Bucket: process.env.RECEIPTS_BUCKET!,
Key: `receipts/${body.userId}/${orderId}.json`,
Body: JSON.stringify(receipt, null, 2),
ContentType: 'application/json'
}));
// Invocar otra Lambda para procesamiento asíncrono (opcional)
// await lambdaClient.send(new InvokeCommand({...}));
return {
statusCode: 201,
headers: {
'Content-Type': 'application/json',
'X-Request-Id': context.requestId
},
body: JSON.stringify({
orderId,
status: 'created',
message: 'Order created successfully'
})
};
} catch (error) {
console.error('Error processing order:', error);
return {
statusCode: 500,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
error: 'Internal server error',
requestId: context.requestId
})
};
}
};
function generateOrderId(): string {
return `ORD-${Date.now()}-${Math.random().toString(36).substr(2, 9).toUpperCase()}`;
}
// Configuración serverless.yml o SAM template
/*
functions:
createOrder:
handler: handler.handler
runtime: nodejs20.x
memorySize: 1024
timeout: 30
environment:
ORDERS_TABLE: ${self:custom.ordersTable}
RECEIPTS_BUCKET: ${self:custom.receiptsBucket}
events:
- httpApi:
path: /orders
method: post
iamRoleStatements:
- Effect: Allow
Action:
- dynamodb:PutItem
- dynamodb:Query
Resource: !GetAtt OrdersTable.Arn
- Effect: Allow
Action:
- s3:PutObject
Resource: !Sub '${ReceiptsBucket.Arn}/*'
*/
Deno Deploy: El Nuevo Player Prometedor
Deno Deploy emergió como alternativa fuerte en 2025, con TypeScript nativo y APIs web estándar:
// Deno Deploy - API RESTful completa
// main.ts
import { serve } from 'https://deno.land/std@0.200.0/http/server.ts';
import { create, verify } from 'https://deno.land/x/djwt@v3.0.1/mod.ts';
const kv = await Deno.openKv(); // Deno KV - banco key-value global
interface User {
id: string;
email: string;
name: string;
createdAt: string;
}
// Crypto key para JWT
const key = await crypto.subtle.generateKey(
{ name: 'HMAC', hash: 'SHA-512' },
true,
['sign', 'verify']
);
async function handleRequest(req: Request): Promise<Response> {
const url = new URL(req.url);
const path = url.pathname;
const method = req.method;
// CORS headers
const headers = {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS'
};
if (method === 'OPTIONS') {
return new Response(null, { status: 204, headers });
}
try {
// Rutas
if (path === '/api/users' && method === 'POST') {
return await createUser(req, headers);
}
if (path.startsWith('/api/users/') && method === 'GET') {
const userId = path.split('/')[3];
return await getUser(userId, headers);
}
if (path === '/api/auth/login' && method === 'POST') {
return await login(req, headers);
}
return new Response(
JSON.stringify({ error: 'Not found' }),
{ status: 404, headers }
);
} catch (error) {
console.error('Error:', error);
return new Response(
JSON.stringify({ error: 'Internal server error' }),
{ status: 500, headers }
);
}
}
async function createUser(req: Request, headers: HeadersInit): Promise<Response> {
const body = await req.json();
const user: User = {
id: crypto.randomUUID(),
email: body.email,
name: body.name,
createdAt: new Date().toISOString()
};
// Guardar en Deno KV (replicado globalmente)
await kv.set(['users', user.id], user);
await kv.set(['users_by_email', user.email], user.id);
return new Response(
JSON.stringify({ user }),
{ status: 201, headers }
);
}
async function getUser(userId: string, headers: HeadersInit): Promise<Response> {
const result = await kv.get(['users', userId]);
if (!result.value) {
return new Response(
JSON.stringify({ error: 'User not found' }),
{ status: 404, headers }
);
}
return new Response(
JSON.stringify({ user: result.value }),
{ status: 200, headers }
);
}
async function login(req: Request, headers: HeadersInit): Promise<Response> {
const body = await req.json();
// Buscar usuario por email
const userIdResult = await kv.get(['users_by_email', body.email]);
if (!userIdResult.value) {
return new Response(
JSON.stringify({ error: 'Invalid credentials' }),
{ status: 401, headers }
);
}
const userResult = await kv.get(['users', userIdResult.value as string]);
const user = userResult.value as User;
// Generar JWT
const jwt = await create(
{ alg: 'HS512', typ: 'JWT' },
{
sub: user.id,
email: user.email,
exp: Math.floor(Date.now() / 1000) + (60 * 60 * 24) // 24 horas
},
key
);
return new Response(
JSON.stringify({ token: jwt, user }),
{ status: 200, headers }
);
}
// Iniciar servidor
serve(handleRequest, { port: 8000 });Costos: Serverless vs Servidor Tradicional
Comparemos costos reales en 2025:
Aplicación de ejemplo:
- 10 millones de requests/mes
- 500ms tiempo promedio de ejecución
- 512MB memoria
AWS Lambda:
- Compute: ~$100/mes
- API Gateway: ~$35/mes
- DynamoDB: ~$25/mes (on-demand)
- Total: ~$160/mes
EC2 Tradicional:
- Instancia t3.medium (2 vCPU, 4GB): ~$30/mes
- Load Balancer: ~$25/mes
- RDS (db.t3.small): ~$45/mes
- PERO: Necesitas gestionar, escalar, monitorear
- Total: ~$100/mes (pero con overhead operacional)
Vercel/Netlify (Plan Pro):
- $20/miembro/mes + bandwidth
- Edge functions incluidas
- Total: ~$50-150/mes dependiendo del tráfico
Mejores Prácticas para Serverless en 2025
1. Optimiza Cold Starts:
// ❌ Malo - imports pesados aumentan cold start
import _ from 'lodash';
import moment from 'moment';
import { huge_library } from 'huge-lib';
// ✅ Bueno - imports mínimos y tree-shaking
import { debounce } from 'lodash-es/debounce';
import { formatISO } from 'date-fns';2. Reutiliza Conexiones:
// ❌ Malo - nueva conexión en cada invocación
export const handler = async () => {
const db = await connectToDatabase();
// ...
};
// ✅ Bueno - conexión reutilizada
const db = await connectToDatabase();
export const handler = async () => {
// Usar 'db' existente
};3. Usa Caching Agresivo:
// Edge caching con Vercel
export const config = {
runtime: 'edge',
};
export default async function handler(req: Request) {
const data = await fetchData();
return new Response(JSON.stringify(data), {
headers: {
'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=86400'
}
});
}4. Monitorea Performance:
Usa herramientas como:
- AWS CloudWatch
- Vercel Analytics
- Datadog Serverless
- Sentry para error tracking
El Futuro en 2026 y Más Allá
Tendencias emergentes:
- WebAssembly en el Edge: Correr código compilado con performance nativa
- Serverless Containers: AWS Fargate, Cloud Run evolucionando
- Edge Databases: Turso, Neon, PlanetScale con edge caching
- IA en el Edge: Correr modelos de ML cerca de los usuarios
- Multi-cloud Serverless: Abstracciones para correr en cualquier cloud
Si quieres entender mejor arquitecturas escalables, échale un vistazo a Microservices vs Monolito: Cuándo Usar Cada Uno donde exploramos patrones arquitecturales.

