Un cold start es la penalización de latencia que pagas cuando la plataforma serverless debe crear e inicializar un entorno nuevo antes de ejecutar tu código. No es un bug, es una factura: scale-to-zero significa que los entornos ociosos se reclaman para que lo ocioso no cueste nada — y la primera solicitud después de esa recolección paga el setup. Entender las fases, los números reales y la escalera de mitigación convierte los cold starts de un miedo difuso en una decisión de ingeniería con precio.
Puntos clave
| Pregunta | Respuesta |
|---|---|
| La causa | Scale-to-zero: sin costo ocioso ⇒ alguien inicializa bajo demanda |
| Las fases | Asignar → descargar el código → arrancar el runtime → correr el init → atender |
| Los números | ~100 ms–1 s+ típico; menos del 1% del tráfico constante, casi todo el tráfico esparso |
| El disparador olvidado | Scale-out de concurrencia — los warmers no lo arreglan |
| La escalera | Primero los arreglos gratuitos en el código; al final la capacidad paga siempre warm |
Las cinco fases, con el reloj corriendo
COLD START costo típico
1 Asignar un sandbox (micro-VM / contenedor) ~50–100 ms
2 Descargar tu paquete de deployment 50–500 ms ← escala con el tamaño del bundle
3 Arrancar el runtime del lenguaje 50–1.000 ms ← intérprete rápido, VM lenta
4 Correr TU init (imports, clientes de SDK, conexiones) 0 ms–segundos ← la mayor palanca que controlas
5 Invocar el handler el trabajo real
WARM START = solo el paso 5 (+ ~1–10 ms de descongelamiento). El entorno fue
congelado, no destruido — las conexiones y caches fuera del handler sobreviven,
y por eso la disciplina en el init paga renta en cada request posterior.
El contraste que vale la pena medir tú mismo — una función en un backend siempre en ejecución, donde la carrera nunca empieza:
// JavaScript / Node.js — Back4app JS SDK
// Cloud Code runs on an always-on backend — no scale-from-zero cold start
const t0 = Date.now();
const avg = await Parse.Cloud.run('averageStars', { movie: 'Arrival' });
console.log(`Round trip: ${Date.now() - t0} ms`); // consistent p50 ≈ p99
// The FaaS mitigations (warmers, provisioned capacity, bundle diets)
// don't apply here: the process serving this call was already running. // Flutter / Dart — Back4app Flutter SDK
// Cloud Code runs on an always-on backend — no scale-from-zero cold start
final t0 = DateTime.now();
final response = await ParseCloudFunction('averageStars')
.execute(parameters: {'movie': 'Arrival'});
print('Round trip: ${DateTime.now().difference(t0).inMilliseconds} ms');
// Consistent p50 ≈ p99: the process serving this call was already running. // iOS / Swift — Back4app Swift SDK
// Cloud Code runs on an always-on backend — no scale-from-zero cold start
let t0 = Date()
let avg: Double = try await Cloud.run(name: "averageStars",
parameters: ["movie": "Arrival"])
print("Round trip: \(Int(Date().timeIntervalSince(t0) * 1000)) ms")
// Consistent p50 ≈ p99: the process serving this call was already running. // Android / Kotlin — Back4app Android SDK
// Cloud Code runs on an always-on backend — no scale-from-zero cold start
val t0 = System.currentTimeMillis()
val avg = ParseCloud.callFunction<Double>(
"averageStars", mapOf("movie" to "Arrival"))
println("Round trip: ${System.currentTimeMillis() - t0} ms")
// Consistent p50 ≈ p99: the process serving this call was already running. Cold starts vs. warm starts
| Cold start | Warm start | |
|---|---|---|
| Entorno | Creado e inicializado ahora | Reutilizado, descongelado |
| Latencia añadida | ~100 ms a segundos | Milisegundos de un dígito |
| Cuándo | Primera llamada, post-deploy, post-ociosidad, scale-out | Tráfico constante dentro del pool warm |
| Código de init | Corre | Se salta — sus resultados persisten |
| Nota de cobro | En las grandes plataformas, la fase de init hoy se cobra como ejecución | Solo el tiempo del handler |
Cuánto duran, y con qué frecuencia — honestamente
La duración depende sobre todo del runtime y del bundle: los runtimes interpretados (JavaScript, Python) típicamente 200–400 ms; los compilados (Go, Rust) por debajo de ~100–300 ms; los basados en VM (JVM, .NET) de 500 ms a varios segundos, con snapshot-restore recortando dramáticamente la cifra de la JVM; los p99 corren a 2–3× la mediana, y árboles de dependencias inflados han sido medidos multiplicando el arranque varias veces sin importar el lenguaje. La frecuencia es donde la mayoría de los explicadores cuenta solo media historia. El tráfico de producción constante ve cold starts en menos del uno por ciento de las invocaciones — tranquilizador, y real. Pero la cuenta se invierte con tráfico esparso: la aritmética de Fowler — una función invocada una vez por hora hace cold start prácticamente siempre, y los entornos de desarrollo ven tasas frías del 30–90%. Y el disparador que todos olvidan: el scale-out de concurrencia — cuando llegan diez solicitudes y hay tres entornos warm, siete hacen cold start a la vez, en medio de tu pico de tráfico, que es exactamente cuando duele.
La escalera de mitigación, con precios
En orden de costo, lo más barato primero. Gratis, en el código: encoge el bundle de deployment y poda dependencias — la mayor palanca que la mayoría de los equipos aún no ha jalado; importa solo los submódulos del SDK que usas; carga bajo demanda los módulos pesados de rutas poco frecuentes; abre las conexiones a la base de datos en el scope de init para que los warm starts las reutilicen. Barato, en la configuración: sube la memoria (la CPU escala con ella, de forma material en runtimes de VM); habilita snapshot-restore donde la plataforma lo ofrezca. Frágil, remedio casero: pings de keep-warm — una request programada cada pocos minutos mantiene warm un entorno y no hace nada por el scale-out; estatus honesto: hack heredado. Pago, definitivo: capacidad pre-aprovisionada (“concurrencia aprovisionada”, “instancias mínimas”) — N entornos siempre inicializados, cold starts eliminados hasta N, a un precio siempre activo que cancela en parte el pago por uso. La ironía merece su propia frase: el arreglo para el problema insignia del serverless es recomprar el servidor que te prometieron que no tenías.
Isolates: cómo los runtimes de edge lo esquivan
Las plataformas de edge reportan cold starts cercanos a cero cambiando la arquitectura en lugar de calentarla: en vez de arrancar un contenedor o una micro-VM por tenant, corren miles de isolates de V8 — sandboxes al estilo de una pestaña de navegador — dentro de un solo proceso de larga duración. Crear un contexto de isolate cuesta milisegundos de un dígito y megabytes, no cientos de milisegundos y un arranque de runtime. El trade-off es el entorno: un subconjunto de APIs estándar de la web, límites estrictos de CPU, sin sistema de archivos — una herramienta distinta, no un upgrade gratis, cubierta con honestidad en la entrada de edge.
Casos de uso comunes donde los cold starts importan
- APIs interactivas — un humano está mirando el spinner; el p99 incluye la cola fría.
- Pagos y checkout — sensibles a la latencia y con precio en conversión.
- Login y emisión de sesión — la ruta de la primera impresión, a menudo tras periodos ociosos.
- Endpoints de tráfico esparso — herramientas de admin y APIs internas donde casi cada llamada es fría.
- Donde no importan: jobs en cola, webhooks, trabajo programado — lo asíncrono absorbe la cola de forma invisible.
¿Deberías optimizar los cold starts? Matriz de decisión
| Situación | Haz |
|---|---|
| Cargas asíncronas/en cola/programadas | Nada — aquí los cold starts son invisibles |
| Tráfico alto y constante, interactivo | Arreglos en el código; mide antes de pagar |
| Tráfico esparso, de cara al usuario | Instancias mínimas en esa ruta — o un backend siempre activo |
| Runtime de VM (JVM/.NET), sensible a latencia | Snapshot-restore + memoria primero |
| Tráfico con picos y p99 estricto | Capacidad aprovisionada dimensionada al pico |
| Lógica estilo gateway, usuarios globales | Runtimes de edge basados en isolates |
| La mayoría de los backends de app en un BaaS | Ya resuelto — no existe scale-from-zero |
Limitaciones y trade-offs
- Las mitigaciones cambian dinero por latencia. La capacidad precalentada es una factura permanente; decide por endpoint, no para toda la plataforma.
- Los warmers les mienten a los dashboards. Una función con pings se ve saludable mientras cada pico real de tráfico sigue haciendo cold start en el scale-out.
- La austeridad en el init tiene límites. El lazy-loading agresivo mueve la latencia de los cold starts a las rutas de primer uso — mide adónde la moviste.
- Los benchmarks envejecen rápido. Los rankings de runtimes y las cifras de plataformas cambian cada año; los números viejos (y penalizaciones de red corregidas hace mucho) siguen circulando — ponle fecha a tus datos.
- La métrica que importa es la tuya. Las estadísticas de porcentaje frío describen el tráfico de otra persona; solo tu p99 bajo carga parecida a producción justifica gastar.
Cold starts en Back4app
Back4app es una plataforma open-source de Backend as a Service (BaaS) que combina base de datos gestionada, APIs REST y GraphQL generadas automáticamente, autenticación, almacenamiento de archivos y funciones serverless con Cloud Code. La historia de cold start aquí es ausencia arquitectónica: Cloud Code corre dentro de un backend siempre en ejecución, así que no existe el momento de scale-from-zero — sin carrera de init, sin pool warm que gestionar, sin línea de capacidad aprovisionada en la factura — y la medición de los code tabs muestra lo que eso compra: p50 y p99 a un grito de distancia entre sí, en la primera solicitud del día y en la millonésima. El trade-off es el que nombra BaaS vs. serverless: renuncias a la granularidad de cobro por invocación a cambio de latencia consistente y una base de datos adjunta — que, para backends de apps de cara al usuario, suele ser el lado del trato que los usuarios sí pueden sentir.
Preguntas frecuentes
¿Qué es un cold start en serverless?
Es la latencia extra que aparece cuando la plataforma serverless debe construir un entorno de ejecución desde cero antes de correr tu función: asignar una instancia, descargar tu código, arrancar el runtime, ejecutar tu código de inicialización — y solo entonces atender la request. Un warm start salta directo al último paso, porque reutiliza un entorno que ya pasó por todo lo anterior.
¿Cuánto dura un cold start?
Típicamente de cien milisegundos a más de un segundo. Los runtimes interpretados (JavaScript, Python) rondan los 200–400 ms; los compilados (Go, Rust) pueden bajar de 100 ms; los basados en VM (JVM, .NET) van de 500 ms a varios segundos, con los setups cargados de frameworks en el peor extremo. Las latencias de cola suelen ser dos a tres veces la mediana.
¿Cuál es la diferencia entre cold start y warm start?
Un warm start reutiliza un entorno congelado pero ya inicializado: la plataforma lo descongela y llama a tu handler, sumando milisegundos de un solo dígito. Todo lo que vive fuera del handler — conexiones, caches, módulos cargados — sobrevive entre invocaciones, y por eso la disciplina en la inicialización rinde en cada warm start posterior.
¿Con qué frecuencia ocurren los cold starts?
Ambas respuestas son ciertas: menos del uno por ciento de las invocaciones con tráfico de producción constante — y la inmensa mayoría con tráfico esparso, ya que una función llamada una vez por hora hace cold start casi siempre. Las ráfagas agregan más: cada solicitud concurrente por encima del pool warm dispara su propio cold start.
¿Cómo reducir los cold starts?
Sube la escalera de lo gratis a lo pago: encoge el bundle de deployment y poda dependencias (la mayor ganancia gratuita), carga bajo demanda los imports poco usados, elige un runtime más rápido, sube la memoria (la CPU escala con ella), usa snapshot-restore donde la plataforma lo ofrezca — y solo entonces paga por capacidad precalentada.
¿Qué es la concurrencia aprovisionada?
La solución paga, también vendida como instancias mínimas: la plataforma mantiene N entornos inicializados antes de la demanda, eliminando los cold starts para tráfico hasta N. La ironía viene incluida en el precio — reintroduces costo siempre activo en un modelo de pago por uso, y por eso pertenece solo a las rutas críticas de latencia.
¿Funcionan los pings de keep-warm?
Parcialmente, y de forma frágil: un ping programado mantiene warm un solo entorno, pero no hace nada cuando la concurrencia escala — la décima request simultánea hace cold start sin importar qué tan warm esté el primer entorno. Los warmers son el hack heredado; las instancias mínimas son la respuesta que las plataformas soportan.
¿Los cold starts realmente importan para mi app?
Solo donde hay un humano esperando: rutas síncronas de cara al usuario, como APIs interactivas y pagos. Las colas, los webhooks, los jobs programados y el resto del trabajo asíncrono absorben los cold starts de forma invisible. Mide la latencia de cola bajo tráfico parecido al de producción antes de gastar dinero en el problema.