Cloudflare Workers vs AWS Lambda: comparativa de costes para un backend Flutter entre 1 millón y 100 millones de peticiones al mes

Si alguna vez elegiste serverless como backend para tu app Flutter y buscaste “Cloudflare Workers vs AWS Lambda comparativa de costes”, seguramente te encontraste con la mayoría de artículos rematando con conclusiones vagas del tipo “Workers es más barato” o “el ecosistema de Lambda es más grande”. En la práctica, el ganador cambia según la naturaleza de la carga de trabajo y el volumen de tráfico. Este artículo toma los tres casos de uso más habituales en apps Flutter — un servidor de envío de push (llamadas a FCM/APNs), un manejador de webhooks (verificación de RevenueCat, Stripe, App Store Server Notifications) y un servidor de API genérico —, y calcula la factura real en los tramos de 1 millón, 10 millones y 100 millones de peticiones mensuales, incorporando tanto la diferencia estructural de facturación entre ambas plataformas como el coste adicional de API Gateway.
Resumen clave
- Cloudflare Workers solo cobra el tiempo de CPU consumido, y el tiempo de espera mientras aguarda la respuesta de una API externa no entra en la factura. AWS Lambda cobra el tiempo de ejecución total (wall-clock), incluida la espera, multiplicado por la memoria asignada.
- Las peticiones y el tiempo de ejecución de Lambda tienen un nivel Always Free permanente de 1 millón de peticiones + 400.000 GB-segundos al mes. El plan gratuito de Workers solo cubre 100.000 peticiones al día (unos 3 millones al mes) y 10 ms de CPU por invocación; en cuanto se supera ese límite de CPU hay que pasar al plan de pago, con un mínimo de 5 $/mes.
- Cuando expones Lambda por HTTP, añadir API Gateway suma 1,00 $ por millón de peticiones con HTTP API, o 3,50 $ con REST API, como coste aparte. Si solo necesitas un único endpoint, Lambda Function URL elimina por completo este coste. Workers, al llevar el enrutado integrado en el runtime, ni siquiera tiene esta partida.
- Con los supuestos de este artículo (300 ms de wall-clock por petición, 20 ms de CPU real, 256 MB de memoria), Workers empieza a salir más barato a partir de unos 5,5 millones de peticiones al mes si usas API Gateway, o de unos 11 millones si usas Function URL. Por debajo de esos umbrales, Lambda es más ventajoso.
- En cambio, para funciones de cómputo intensivo como el redimensionado de imágenes, Lambda resulta más barato en todo el rango de tráfico con una configuración de memoria baja (256 MB). Ahora bien, si la carga es pesada y obliga a subir la memoria a 1,1-1,4 GB o más para conseguir suficiente potencia de CPU, esta ventaja se diluye.
La diferencia fundamental de facturación: tiempo de CPU vs tiempo de ejecución total
Lo primero que hay que entender al comparar ambas plataformas es que difieren en “qué se mide como tiempo para cobrar”.
Según la documentación oficial de precios de Cloudflare, Workers solo factura el número de peticiones y el tiempo de CPU. Mientras un Worker hace un fetch a una API externa y espera la respuesta, el isolate de V8 no está ejecutando instrucciones de verdad, sino esperando, así que ese tramo no aparece en la factura en absoluto. Aunque encadenes cinco llamadas a APIs externas y el conjunto tarde 2 segundos en responder, si el código JS que realmente se ejecuta ahí dentro (parseo, serialización, ramas condicionales, etc.) suma 20 ms, lo único que se cobra son esos 20 ms. El límite de CPU por invocación es de 30 segundos por defecto, ampliable hasta 5 minutos (300.000 ms) mediante configuración en el plan de pago, y los Cron Triggers y los consumidores de Queue admiten hasta 15 minutos.
AWS Lambda, por el contrario, mide el tiempo total desde que arranca el código del handler hasta que devuelve la respuesta, en base wall-clock, y lo multiplica por la memoria asignada a la función (en GB) para facturar en GB-segundos. Mientras espera la respuesta de una API externa, ese entorno de ejecución se sigue contando como “en ejecución”, así que ese tiempo de espera también se factura tal cual. Es decir, en el mismo manejador de webhooks, da igual que la API externa responda en 250 ms o en 800 ms: para Lambda esa diferencia se traduce directamente en una diferencia de coste en GB-segundos. El tiempo de ejecución de Lambda se redondea a milisegundos, el timeout máximo de la función es de 900 segundos (15 minutos) y la memoria se puede configurar entre 128 MB y 10.240 MB, en incrementos de 1 MB. Como referencia, se sabe que el punto de 1.769 MB equivale a la potencia de cómputo de 1 vCPU completa, por lo que las funciones intensivas en CPU suelen desplegarse con una memoria cercana o superior a ese umbral.
La conclusión práctica de esta diferencia estructural es sencilla. Cuanto más tiempo pase una carga de trabajo esperando respuestas de APIs externas o de bases de datos (carga ligada a E/S), más favorece a Workers; cuanto más tiempo de cómputo puro consuma (carga ligada a CPU), más se estrecha o se invierte la brecha entre ambas plataformas. Los servidores de envío de push (llamadas a la API HTTP v1 de FCM) o los manejadores de webhooks (verificación de firma seguida de una llamada a una API externa) que se suelen construir en un backend Flutter son casos típicos de carga ligada a E/S.
Misma lógica, distinto esqueleto de código
En la práctica, el código que se despliega en ambas plataformas es casi idéntico. A continuación se muestra la versión Worker, escrita con Hono, de un handler que recibe un webhook de tipo RevenueCat/Stripe, verifica la firma y dispara un push por FCM.
// Cloudflare Worker (Hono)
import { Hono } from "hono";
type Bindings = { WEBHOOK_SECRET: string; FCM_PROJECT_ID: string };
const app = new Hono<{ Bindings: Bindings }>();
app.post("/webhooks/push", async (c) => {
const rawBody = await c.req.text();
const signature = c.req.header("X-Signature") ?? "";
if (!(await verifyHmacSignature(rawBody, signature, c.env.WEBHOOK_SECRET))) {
return c.text("invalid signature", 401);
}
const event = JSON.parse(rawBody);
const accessToken = await getFcmAccessToken(c.env); // 서비스 계정 JWT 교환
await fetch(
`https://fcm.googleapis.com/v1/projects/${c.env.FCM_PROJECT_ID}/messages:send`,
{
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ message: buildFcmMessage(event) }),
},
);
return c.json({ ok: true });
});
export default app;
Al migrarlo a Lambda + Function URL, solo cambia el mecanismo de disparo; la lógica se mantiene igual.
// AWS Lambda (Node.js, Function URL 트리거)
import type { APIGatewayProxyEventV2, APIGatewayProxyResultV2 } from "aws-lambda";
export const handler = async (
event: APIGatewayProxyEventV2,
): Promise<APIGatewayProxyResultV2> => {
const rawBody = event.body ?? "";
const signature = event.headers["x-signature"] ?? "";
if (!(await verifyHmacSignature(rawBody, signature, process.env.WEBHOOK_SECRET!))) {
return { statusCode: 401, body: "invalid signature" };
}
const payload = JSON.parse(rawBody);
const accessToken = await getFcmAccessToken();
await fetch(
`https://fcm.googleapis.com/v1/projects/${process.env.FCM_PROJECT_ID}/messages:send`,
{
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ message: buildFcmMessage(payload) }),
},
);
return { statusCode: 200, body: JSON.stringify({ ok: true }) };
};
La experiencia de desarrollo a nivel de código es prácticamente idéntica. La diferencia que aborda este artículo es enteramente una cuestión de quién mide, y cómo, el tiempo empleado en procesar cada petición, y cómo se traduce eso en la factura.
Comparativa de niveles gratuitos: dos ofertas aparentemente generosas, con trampa
| Concepto | Cloudflare Workers (Free) | AWS Lambda (Always Free) |
|---|---|---|
| Límite de peticiones | 100.000/día (~3 millones/mes) | 1 millón/mes |
| Límite de cómputo | 10 ms de CPU por invocación | 400.000 GB-segundos/mes |
| Facturación del tiempo de espera | No aplica (no forma parte del cómputo) | Sí (incluida en el wall-clock) |
| Vigencia | Gratuito permanente | Gratuito permanente (independiente del crédito de 12 meses para cuentas nuevas) |
| Al superar el límite | Hay que pasar al plan de pago (desde 5 $/mes) | Se factura por consumo a partir del excedente |
Si solo se miran los números, el “1 millón de peticiones + 400.000 GB-segundos gratis para siempre” de Lambda parece mucho más generoso, pero la verdadera trampa del plan Free de Workers no está en el número de peticiones, sino en el límite de 10 ms de CPU por invocación. Un parseo y respuesta JSON simple entra sin problema en esos 10 ms, pero en cuanto se añade verificación de firma HMAC, validación de esquema con algo como Zod, o decodificación de JWT, el código real supera esos 10 ms con más facilidad de lo que parece. Al superar este límite, la propia petición se corta con un error de exceso de CPU, así que cualquier API o manejador de webhooks con algo de lógica real prácticamente obliga a pasar al plan de pago de 5 $/mes. Lambda, en cambio, puede operar de verdad a 0 $ si el tráfico cabe dentro del nivel gratuito, incluso reservando memoria y tiempo con holgura.
La trampa de API Gateway: el enrutado de Lambda trae una factura escondida
La propia función Lambda no entiende HTTP de forma nativa. Para invocarla por HTTPS desde un navegador o una app Flutter hay que poner algo delante, y esa elección afecta al coste total más de lo que parece.
- API Gateway (HTTP API): 1,00 $ por millón de peticiones (en el primer tramo de 300 millones), y 0,90 $ por millón a partir de ahí. Soporta dominio personalizado, enrutado de varias Lambda por ruta, autorizadores JWT/Lambda, y planes de uso (API keys, cuotas).
- API Gateway (REST API): 3,50 $ por millón de peticiones (en el primer tramo de 333 millones). Tiene funciones más pesadas —integración con WAF, transformación de petición/respuesta, caché—, pero también es más caro.
- Nivel gratuito limitado a 12 meses: las cuentas nuevas de AWS tienen 1 millón de peticiones gratis al mes durante 12 meses, tanto en HTTP API como en REST API. Los cálculos de este artículo parten de la facturación normal, una vez terminado ese periodo.
- Lambda Function URL: una función puede tener adjunto, gratis, un único endpoint HTTPS dedicado. No añade ningún coste aparte: solo se aplica la tarifa habitual de peticiones y tiempo de ejecución de Lambda. A cambio, solo permite una URL por función (no se pueden agrupar varias Lambda bajo una misma API por rutas), y carece de funciones de gestión como API keys, planes de uso, integración con WAF o validación de peticiones.
El manejador de webhooks o el servidor de envío de push de una app Flutter suele ser una función de propósito único a la que le basta con uno o pocos endpoints. En ese caso, las funciones de enrutado y gestión de uso de API Gateway no hacen falta desde el principio, así que Function URL es suficiente. En cambio, si necesitas agrupar varias funciones Lambda bajo una misma API por rutas, emitir API keys a socios externos y gestionar cuotas —un servidor de API genérico—, entonces sí necesitas API Gateway.
Cloudflare Workers ni siquiera tiene esta distinción. Da igual cuántas rutas manejes, ya sea mediante la configuración de routes en wrangler.toml o con un router dentro del propio código del Worker (Hono, itty-router, etc.): el coste por petición es el mismo.
# wrangler.toml — Workers는 라우팅에 별도 과금 항목이 없다
name = "push-webhook-worker"
main = "src/index.ts"
compatibility_date = "2025-01-01"
routes = [
{ pattern = "api.example.com/webhooks/*", zone_name = "example.com" },
{ pattern = "api.example.com/push/*", zone_name = "example.com" }
]
Simulación de la factura por tramo de tráfico: 1 millón, 10 millones y 100 millones de peticiones al mes
Los cálculos siguientes parten de estos supuestos. Los valores reales varían según cada servicio, así que se recomienda sustituirlos por los tuyos propios en las fórmulas que aparecen más adelante.
- Memoria de Lambda de 256 MB (una configuración habitual en webhooks y APIs ligeras), arquitectura x86_64
- Escenario A (ligado a E/S) — manejador de webhooks, servidor de envío de push: wall-clock de 300 ms por petición, de los cuales 20 ms son CPU real (los otros 280 ms son espera de respuesta de una API externa)
- Escenario B (ligado a CPU) — redimensionado de imágenes, generación de PDF, etc.: wall-clock de 200 ms por petición, 180 ms de CPU (espera casi nula)
- En el lado de Lambda se asume la facturación normal, una vez agotado el nivel gratuito de 12 meses de API Gateway, calculada con HTTP API (la opción más barata frente a REST API)
Escenario A: ligado a E/S (manejador de webhooks, servidor de envío de push)
| Peticiones/mes | Workers (Paid, desde 5 $) | Solo cómputo Lambda | Lambda + Function URL | Lambda + API Gateway (HTTP API) |
|---|---|---|---|---|
| 1 millón | 5,00 $ | 0,00 $ | 0,00 $ | 1,00 $ |
| 10 millones | 8,40 $ | 7,63 $ | 7,63 $ | 17,63 $ |
| 100 millones | 71,40 $ | 138,13 $ | 138,13 $ | 238,13 $ |
Escenario B: ligado a CPU (redimensionado de imágenes, firma, cifrado, etc.)
| Peticiones/mes | Workers (Paid, desde 5 $) | Solo cómputo Lambda | Lambda + Function URL | Lambda + API Gateway (HTTP API) |
|---|---|---|---|---|
| 1 millón | 8,00 $ | 0,00 $ | 0,00 $ | 1,00 $ |
| 10 millones | 40,40 $ | 3,47 $ | 3,47 $ | 13,47 $ |
| 100 millones | 391,40 $ | 96,47 $ | 96,47 $ | 196,47 $ |
Al poner las dos tablas una junto a otra aparece un punto interesante. En el escenario A (ligado a E/S), Lambda sale muchísimo más barato en el tramo de bajo tráfico, pero a medida que crece el tráfico Workers acaba imponiéndose. En cambio, en el escenario B (ligado a CPU), con el supuesto de 256 MB, Lambda es más barato en todo el rango. La siguiente sección explica por qué, y señala el punto de equilibrio exacto.
Por qué el ganador cambia según la naturaleza de la carga de trabajo
Se muestran a continuación las fórmulas usadas en los cálculos, tal cual, para que puedas sustituir tus propias cifras y recalcular por tu cuenta.
Coste mensual de Workers (USD) = 5
+ max(0, peticiones_millones - 10) × 0,30
+ max(0, CPU_ms_por_peticion × peticiones_millones - 30) × 0,02
Coste de cómputo de Lambda (USD) = max(0, peticiones_millones - 1) × 0,20
+ max(0, GBs_totales - 400.000) × 0,0000166667
GBs_totales = peticiones × memoria(GB) × wall_clock_promedio_segundos
Al sustituir en esta fórmula las cifras del escenario A y resolver el punto donde se cruzan ambas curvas, se obtiene que, comparando solo el coste de cómputo, Workers empieza a superar a Lambda en torno a los 11 millones de peticiones al mes. Si a eso se le suma API Gateway (HTTP API, 1,00 $ por millón de peticiones), la pendiente de la curva de coste de Lambda se vuelve más pronunciada y el punto de equilibrio se adelanta a aproximadamente 5,5 millones de peticiones al mes, casi la mitad. Dicho de otro modo: la decisión de “usar API Gateway o usar Function URL” afecta al coste total casi tanto como la diferencia estructural de fondo entre facturar por CPU o por wall-clock.
La razón por la que Lambda sigue ganando en el escenario B (ligado a CPU) es sencilla. Con una configuración de memoria baja como 256 MB (0,25 GB), la tarifa por GB-segundo es tan pequeña (0,2 s × 0,25 GB × 0,0000166667 $ ≈ 0,00000083 $ por petición) que termina saliendo más barata que la tarifa de Workers por ms de CPU (180 ms × 0,02 $/millón de ms ≈ 0,0000036 $ por petición). Pero este resultado depende fuertemente del supuesto de 256 MB de memoria. Si se invierte la misma fórmula, en cargas que necesitan subir la memoria a aproximadamente 1,1-1,4 GB o más (algo habitual en el redimensionado de imágenes con librerías como sharp, donde suele usarse entre 512 MB y 1.769 MB para conseguir suficiente potencia de CPU), esta ventaja se diluye o desaparece, y a medida que crece el tráfico la balanza vuelve a inclinarse hacia Workers. Por eso, antes de asumir que “si es una carga ligada a CPU, Lambda gana seguro”, conviene sustituir en la fórmula la configuración de memoria real que vayas a desplegar.
Costes adicionales fáciles de pasar por alto: el límite de subpeticiones y la tarifa de transferencia de datos
Un servidor de envío de push suele llamar varias veces a APIs externas como FCM o APNs dentro de una misma petición. Cloudflare no factura esto por separado como “subpeticiones” (solo cuenta como petición la petición entrante única), pero sí existe un límite al número de subpeticiones que pueden salir de forma concurrente. Según la documentación oficial, el plan Free permite 50 por petición, y el plan Paid 1.000 por petición por defecto (tras el cambio de febrero de 2026, el valor por defecto subió hasta un máximo de 10.000, ampliable por configuración hasta 10 millones). Si tu arquitectura hace fan-out enviando peticiones individuales a cientos de tokens de dispositivo, conviene revisar este límite de antemano.
Otra partida que se olvida con frecuencia en la práctica es el coste de transferencia de datos (egress). AWS cobra 0,09 $ por GB, aparte, por el tráfico de respuesta que sale de la región (una tarifa general de transferencia de datos de AWS que aplica tanto a API Gateway como a Lambda). En el esquema de precios de Cloudflare Workers no existe esta partida de egress de respuesta como concepto separado. En casos de uso como webhooks o push, donde el payload de respuesta no suele ser grande, la diferencia es mínima; pero en un servidor de API que devuelve JSON voluminoso, esta partida también se va acumulando a medida que crece el tráfico.
Conclusión: qué usar para el servidor de push y el manejador de webhooks de una app Flutter
- Volumen inicial a mediano, hasta 1 millón de peticiones al mes: Lambda + Function URL prácticamente sale a 0 $ (tanto las peticiones como el tiempo de ejecución caben en el nivel gratuito permanente). Workers implica un coste fijo mínimo de 5 $ del plan de pago, así que en este tramo Lambda es más ventajoso. Ahora bien, si tu lógica es realmente ligera y el uso real de CPU no supera los 10 ms por invocación, el plan Free de Workers (gratis hasta unos 3 millones de peticiones al mes) también puede mantenerse en 0 $.
- Tramo entre 5 y 11 millones de peticiones al mes (según los supuestos de este artículo): el ganador depende del método de enrutado. Si añades API Gateway, Workers ya se adelanta desde este tramo; si te basta con un único endpoint mediante Function URL, Lambda sigue siendo ligeramente más ventajoso hasta los 11 millones.
- Escala superior a 10 millones de peticiones al mes (grandes campañas de push periódicas, fan-out masivo de webhooks): para cargas ligadas a E/S, Workers gana casi siempre. El motivo es que un esquema que solo cobra tiempo de CPU favorece intrínsecamente a las cargas con tiempos de espera largos.
- Funciones realmente intensivas en CPU, como el redimensionado de imágenes: con configuraciones de memoria baja (256-512 MB), Lambda suele ser más ventajoso en cualquier escala. Sin embargo, si necesitas subir la memoria por encima de 1,1 GB para conseguir suficiente potencia de CPU, esta ventaja se diluye.
- Revisa primero, sin falta, la capa de enrutado. El simple hecho de comprobar si puedes exponer Lambda mediante Function URL en lugar de API Gateway desplaza el punto de equilibrio casi al doble (de unos 5,5 millones a unos 11 millones de peticiones). Es la palanca de ahorro más fácil de aplicar de inmediato, incluso antes que la diferencia estructural entre cobrar por CPU o por wall-clock.
En definitiva, no hay una respuesta única a “Cloudflare Workers vs AWS Lambda, comparativa de costes”. El volumen de tráfico, la proporción entre tiempo de espera y tiempo de CPU por petición, y la elección de la capa de enrutado —estas tres variables, sustituidas directamente en las fórmulas de este artículo, son la única respuesta realmente precisa.