Saltar a contenido

Capítulo 11. Cloudflare Workers

Programando en el Edge sin administrar servidores

Objetivo

El propósito de este capítulo es que el lector comprenda qué es Cloudflare Workers, cómo funciona la computación en el edge y de qué manera puede construir APIs, middleware, automatizaciones y servicios web distribuidos sin administrar servidores tradicionales. Cloudflare describe Workers como un entorno de ejecución que permite crear aplicaciones o ampliar aplicaciones existentes sin configurar ni mantener infraestructura, y esa idea resume muy bien la propuesta del producto: ejecutar lógica cerca del usuario, con despliegue global y una experiencia operativa muy distinta a la de un VPS o un backend tradicional.[web:35][page:1]

Al finalizar el capítulo, el lector será capaz de crear un Worker, desplegarlo con Wrangler, exponer endpoints HTTP, manejar Request y Response, usar variables de entorno y conectar el código con servicios del ecosistema de Cloudflare como KV, D1, R2 y Queues. También podrá identificar cuándo Workers es una excelente opción y cuándo conviene evaluar otras plataformas como AWS Lambda, Google Cloud Functions o Firebase Functions.[web:35][web:39][web:42]

¿Qué aprenderás?

Este capítulo enseña cinco ideas fundamentales. La primera es conceptual: entender qué significa ejecutar código en el edge y por qué esa idea cambió la forma en que se diseñan APIs, proxies, middleware y funciones distribuidas. La segunda es práctica: aprender a desarrollar y desplegar un Worker moderno usando JavaScript o TypeScript, Wrangler y el modelo de fetch basado en Web Standards.[web:35][web:42]

La tercera es arquitectónica: comprender cómo un Worker se relaciona con bindings, almacenamiento y servicios externos. La cuarta es operativa: conocer límites, costos, seguridad y buenas prácticas. La quinta es estratégica: saber comparar Workers con otras soluciones serverless y reconocer casos reales donde su enfoque distribuido aporta una ventaja clara.[web:35][web:39]

Introducción

Imagina una cadena de sucursales repartidas por todo el mundo. En el modelo tradicional, cada cliente debe enviar cualquier solicitud a la oficina central, aunque solo quiera una operación pequeña: validar un token, redirigir un enlace, transformar una respuesta o consultar un dato rápido. La oficina central termina recibiendo todo, se vuelve un punto de concentración y además obliga a que la solicitud viaje más lejos de lo necesario.

Cloudflare Workers propone otra idea: colocar pequeños mostradores inteligentes en muchas sucursales globales. Cuando el usuario llega, no siempre hace falta enviarlo a la oficina central. A veces el propio mostrador puede responder, redirigir, autenticar, cachear, transformar o consultar un servicio cercano y devolver el resultado inmediatamente. Ese mostrador distribuido es el Worker ejecutándose en la red de Cloudflare.[web:35][page:2]

La clave del capítulo es esta: Workers no es solo “otro hosting de funciones”. Es una manera distinta de pensar la ubicación del código, la latencia, la seguridad y el diseño de servicios ligeros. Para comprenderlo bien, primero hay que entender qué es exactamente y qué problema resuelve.

¿Qué es Cloudflare Workers?

Cloudflare Workers es la plataforma de ejecución serverless de Cloudflare para correr código en su red global. La documentación oficial la presenta como una forma de crear aplicaciones nuevas o extender aplicaciones existentes sin configurar ni mantener infraestructura, y además integra el modelo de bindings para conectarse con recursos del propio ecosistema de la plataforma, como KV, R2, D1, Queues o Rate Limiting.[web:35][web:39]

Dicho en lenguaje de arquitectura, Workers es un entorno de cómputo distribuido orientado a eventos HTTP y otros disparadores, donde el desarrollador entrega código y configuración, mientras Cloudflare se encarga del despliegue global, aislamiento, escalado y ejecución. El desarrollador no provisiona VMs, no instala Nginx, no gestiona procesos Node permanentes ni configura balanceadores como paso inicial.[web:35][page:1]

Historia

Workers nace dentro del contexto más amplio de Cloudflare como red global especializada en proxy inverso, CDN, seguridad, DNS y aceleración de tráfico. Esa posición en la ruta de las peticiones hizo natural la evolución hacia ejecutar lógica directamente sobre los puntos de presencia de la red, en lugar de limitarse a cachear o filtrar tráfico. Aunque este capítulo no necesita una cronología exhaustiva de versiones, sí conviene entender que Workers surge como una extensión lógica de la infraestructura edge de Cloudflare.[page:2][web:33]

Eso es importante porque explica su ADN. Workers no fue diseñado primero como “clon de un servidor” y luego distribuido. Fue concebido para ejecutarse en la propia red global de Cloudflare, lo que condiciona sus decisiones de runtime, seguridad, límites y APIs disponibles.[page:1][page:2]

Filosofía

La filosofía de Workers puede resumirse en cuatro ideas: código pequeño, despliegue inmediato, cercanía al usuario y fuerte integración con servicios de plataforma. La documentación de bindings incluso describe un binding como una mezcla entre permiso y API, subrayando que la experiencia está pensada para que el código use capacidades de la plataforma sin exponer credenciales directamente dentro del Worker.[web:35]

Esa filosofía cambia el tono del desarrollo. En lugar de pensar primero en un servidor generalista donde luego se instala una aplicación, aquí se piensa primero en un manejador de eventos y en sus recursos asociados. El centro de gravedad no es el servidor; es la función distribuida y sus bindings.[web:35]

Serverless

Workers es serverless porque el desarrollador no administra servidores subyacentes. Eso no significa que no existan máquinas físicas; significa que la responsabilidad de aprovisionamiento, mantenimiento, escalado, aislamiento y disponibilidad recae en la plataforma. El usuario sube código y configura bindings, rutas, dominios y variables; Cloudflare se encarga del resto.[web:35][web:39]

Es importante corregir una idea común: serverless no significa “sin backend”. Significa “sin administrar servidores como unidad operativa principal”. Puedes tener APIs complejas, middleware, pipelines, colas y almacenamiento; simplemente no partes de una VM o un contenedor administrado manualmente.[web:35][web:39]

Edge Computing

Edge computing consiste en ejecutar lógica cerca del punto donde llega la solicitud, en lugar de obligar a que todo viaje a una única región central. La documentación de rutas explica que el Worker se ejecuta cuando una petición coincide con un patrón URL en la red de Cloudflare, lo que refleja justamente ese enfoque: la lógica se inserta en el camino de la petición antes de llegar al origen o incluso sin necesidad de origen.[page:2]

La ventaja práctica es clara. Un Worker puede autenticar, transformar o responder a una solicitud desde una ubicación de Cloudflare próxima al usuario. En algunos casos todavía habrá que consultar un origen o una API externa, pero muchas operaciones se resuelven más cerca del cliente que en una arquitectura centralizada clásica.[page:2][web:35]

Runtime V8

Cloudflare Workers se ejecuta sobre isolates basados en el motor V8. La propia documentación de límites habla de isolates y explica que cada isolate puede manejar múltiples solicitudes concurrentes, con un límite de memoria por isolate de 128 MB.[page:1]

Esto es importante porque el modelo no es el mismo que un proceso Node clásico ejecutándose de forma persistente bajo tu control. El runtime aísla, reutiliza y crea isolates según necesidades de la plataforma. El desarrollador programa sobre un entorno de ejecución moderno, pero no administra directamente el proceso host.[page:1][web:35]

Diferencias con Node.js

La diferencia más importante con Node.js está en el modelo de APIs y de entorno. Workers prioriza Web Standards y expone objetos como Request, Response, fetch, Headers y streams, mientras que Node históricamente se apoyó en APIs propias y en un ecosistema de módulos ligados al servidor tradicional. Cloudflare enfatiza justamente que los bindings viven en env y que el runtime usa APIs alineadas con el modelo web, no con el de un servidor Unix clásico.[web:35][web:42]

Otra diferencia importante es operativa. En Node.js sobre un servidor administrado, tú decides procesos, puertos, reinicios, reverse proxy, sistema operativo, límites de memoria y persistencia local. En Workers no controlas ese nivel de infraestructura; trabajas dentro de límites definidos por la plataforma, como memoria por isolate, tamaño del bundle, CPU time, subrequests y variables por Worker.[page:1]

La tercera diferencia es cultural. Un proyecto Node puede asumir filesystem local, sockets arbitrarios, dependencias pesadas y procesos duraderos. Un Worker obliga a pensar en código más pequeño, en bindings explícitos y en una arquitectura distribuida. Esa restricción no es un defecto: es parte de la especialización del producto.

Casos de uso

Workers encaja muy bien en middleware HTTP, autenticación, validación de tokens, proxies, redirecciones inteligentes, APIs ligeras, webhooks, normalización de respuestas, rate limiting, transformación de contenido y frontends con lógica distribuida. La propia documentación de rutas está orientada a poner Workers “delante” de una aplicación existente, y la documentación de bindings muestra que el Worker puede interactuar con almacenamiento, colas, servicios internos y limitadores sin salir del ecosistema de Cloudflare.[page:2][web:35][web:32]

También es útil para aplicaciones completas de complejidad moderada cuando el modelo de Web Standards, almacenamiento externo y ejecución distribuida encaja con las necesidades del producto. No reemplaza automáticamente a cualquier backend tradicional, pero sí elimina gran parte del trabajo operativo para una categoría muy amplia de servicios web modernos.

¿Qué problema resuelve?

Para entender el valor real de Workers, conviene empezar por el problema que intenta resolver. La mayor parte del software web nació sobre la idea de un servidor central: una máquina o conjunto de máquinas en una región, atendiendo peticiones y exponiendo un backend. Ese modelo sigue siendo válido, pero arrastra costos de operación, latencia geográfica y complejidad de escalado que hoy no siempre son necesarios.

Workers responde a ese problema acercando el código a la red, simplificando despliegue y eliminando parte del costo mental y operativo de los servidores tradicionales. La pregunta correcta ya no es “¿puedo correrlo en Workers?”, sino “¿tiene sentido seguir levantando un servidor completo para esta pieza de lógica?”.

Servidores tradicionales

En un servidor tradicional, aunque uses una nube moderna, todavía suele haber decisiones como sistema operativo, puertos, arranque de procesos, balanceadores, certificados, observabilidad, reinicios, despliegues, firewall, capacidad base y topología de red. Incluso cuando plataformas como AWS o Google abstraen parte de ese trabajo, el modelo general sigue orbitando alrededor de un origen central o de funciones atadas a regiones específicas.

Workers reduce radicalmente ese espacio de decisión para muchos casos. Subes código, defines rutas o dominio, declaras bindings y despliegas. No hay que montar un Nginx previo para una API sencilla, ni mantener una instancia viva solo para redirecciones, validaciones o proxies pequeños.[page:2][web:35]

Latencia

La latencia es una de las razones más poderosas para usar Workers. Si el usuario está en México y tu backend central vive en una sola región lejana, cada operación pequeña paga el costo de ese viaje. En cambio, un Worker puede ejecutarse cuando la petición entra en la red de Cloudflare sobre la URL coincidente, lo que permite resolver parte de la lógica más cerca del usuario.[page:2]

No toda la latencia desaparece, por supuesto. Si el Worker luego consulta una API externa en otra región, esa parte del trayecto seguirá existiendo. Pero sí puedes evitar que operaciones ligeras recorran siempre la misma ruta larga hacia un origen central, y eso cambia mucho la experiencia en autenticación, redirects, filtros, headers, normalización y respuestas rápidas.

Escalabilidad

Cloudflare indica que Workers escala automáticamente en su red global y que no existe un límite general de requests por segundo como regla global de la plataforma. En el plan gratuito sí existe un límite diario de 100,000 requests, pero la plataforma no se presenta como un modelo de “agrega más servidores” gestionado manualmente por el usuario.[page:1]

Eso hace que el escalado sea más cercano al de una capacidad distribuida administrada por la plataforma. Para el desarrollador, la pregunta deja de ser cuántas instancias necesita levantar y pasa a ser si el diseño del código, los subrequests y el almacenamiento elegido se ajustan a los límites y patrones recomendados.

Costos

Workers también resuelve un problema de costo, pero no siempre del mismo modo. Si mantienes servidores encendidos 24/7 para operaciones pequeñas o tráfico irregular, Workers puede reducir costos fijos al eliminar infraestructura dedicada. La documentación de límites muestra que el plan gratuito incluye 100,000 requests diarios, mientras que el plan de pago elimina ese límite general y amplía capacidades como subrequests, CPU y número de variables.[page:1]

Eso lo vuelve especialmente atractivo para proyectos con carga variable, servicios periféricos o componentes pequeños de una arquitectura mayor. Sin embargo, si haces cómputo intensivo, mueves demasiados subrequests o necesitas patrones de ejecución fuera del ajuste natural de Workers, los costos operativos y de complejidad pueden moverse hacia otros componentes como D1, R2, APIs externas o servicios complementarios. Como en cualquier arquitectura, “más barato” depende de la carga real y del diseño.

Disponibilidad

Otra ventaja importante es la disponibilidad ligada a una red global madura. Al ejecutar el código dentro de la red de Cloudflare, la aplicación puede apoyarse en una plataforma ya diseñada para recibir tráfico distribuido, enrutarlo y operar sobre múltiples ubicaciones. La documentación de Workers y de rutas refleja precisamente esa inserción del código dentro del plano de tráfico de Cloudflare.[web:35][page:2]

Esto no elimina todos los riesgos. Si tu Worker depende completamente de un origen frágil o de una API externa con mala disponibilidad, el servicio final puede seguir cayendo. Pero sí mejora la resiliencia de muchas capas intermedias, especialmente aquellas que antes dependían de servidores propios para tareas ligeras.

Comparación: servidor tradicional vs Workers

Aspecto Servidor tradicional Cloudflare Workers
Unidad principal de operación Máquina, contenedor o proceso persistente Función distribuida en la red de Cloudflare [web:35]
Administración de infraestructura Alta o media, según plataforma Muy baja para el desarrollador [web:35]
Proximidad al usuario Depende de la región elegida Ejecuta lógica en el edge sobre la red de Cloudflare [page:2]
Escalado Normalmente explícito o mediado por la nube Automático en la plataforma [page:1]
APIs del runtime Frecuentemente Node.js o entorno servidor clásico Web Standards, fetch, Request, Response, streams [web:35][web:42]
Límite gratis Depende del proveedor 100,000 requests/día [page:1]
Memoria por unidad Definida por la instancia o función 128 MB por isolate [page:1]
Enfoque natural Backend generalista Middleware, APIs ligeras, edge logic, proxies, automatización HTTP

La tabla no significa que Workers sustituya cualquier backend. Significa que para muchas piezas de lógica web, especialmente aquellas pequeñas, distribuidas y cercanas a la red, ofrece un punto de partida más simple y más alineado con la web moderna.

Arquitectura de Workers

La mejor manera de entender Workers es visualizar el flujo completo. Una petición entra desde el usuario, llega a un edge de Cloudflare, activa un Worker asociado a una ruta o dominio, y desde ahí el código puede responder directamente o interactuar con otros recursos como R2, D1, KV, Queues o APIs externas. Finalmente, construye una Response y la devuelve al cliente.[page:2][web:35]

Diagrama ASCII: arquitectura general

[Usuario]
    |
    v
[Cloudflare Edge]
    |
    v
[Worker]
  / |  |  \
 v  v  v   v
[R2][D1][KV][API externa]
    |
    v
[Respuesta]

Este diagrama resume la idea, pero conviene recorrerlo con calma.

Usuario

Todo comienza con una solicitud HTTP normal: una página, una llamada a una API, un webhook o una redirección. Para el cliente no hay una diferencia esencial en la forma de hacer la petición. Sigue siendo una URL y un protocolo HTTP o HTTPS.

Cloudflare Edge

La petición entra a la red de Cloudflare. Si la URL coincide con un patrón configurado en Routes o con un dominio asociado al Worker, el código se ejecuta en ese punto de la red. La documentación de rutas explica exactamente eso: cuando una solicitud coincide con el patrón especificado, el Worker se ejecuta para esa ruta.[page:2]

Aquí aparece la primera gran diferencia frente a un backend centralizado. El punto de entrada ya no es solo “mi servidor en una región”, sino la red distribuida de Cloudflare. Por eso Workers es especialmente potente como capa intermedia o de lógica de borde.

Worker

El Worker es el cerebro inmediato de esa petición. Recibe un objeto Request, acceso a env con bindings y variables, y un contexto de ejecución. Con eso puede leer la URL, el método, los headers, el cuerpo, autenticar, enrutar y decidir si responde por sí mismo o si hace subrequests a otros servicios.[web:35][web:42][page:1]

R2

Si el Worker necesita archivos, objetos o contenido binario, puede conectarse a R2 mediante un binding. La documentación de bindings subraya que estos enlaces ofrecen mejor rendimiento y menos restricciones que usar REST APIs externas desde el Worker, precisamente porque la integración está diseñada como capacidad nativa de la plataforma.[web:35]

R2 es muy útil para almacenar imágenes, PDFs, archivos de QR, JSON grandes, assets generados o respaldos ligeros. En arquitectura, representa la capa de objetos.

D1

Si el Worker necesita consultas relacionales, puede usar D1 mediante su binding. En el mapa mental del capítulo, D1 representa la capa SQL ligera gestionada por Cloudflare. No es “un servidor de base de datos que tú administras”; es un recurso de plataforma accesible desde el Worker mediante bindings.[web:35]

KV

KV cubre el extremo opuesto: lecturas y escrituras tipo key-value, ideal para configuraciones, redirecciones, flags, pequeñas piezas de estado, cachés ligeras o tablas de equivalencia. Arquitectónicamente, KV es muy atractivo para servicios como short links, feature toggles o respuestas simples indexadas por clave.[web:35]

API externa

Un Worker también puede llamar APIs externas usando fetch(). Cada llamada de este tipo cuenta como subrequest, y la documentación de límites muestra que el plan gratuito permite 50 subrequests por invocación, mientras que el plan de pago permite 10,000 por invocación, con posibilidad de subir ese límite en ciertos contextos.[page:1]

Esto convierte al Worker en un excelente proxy, agregador o capa de normalización. Pero también obliga a pensar bien las dependencias externas, porque un Worker no deja de ser tan rápido como el servicio más lento del que dependa.

Respuesta

Al final, el Worker devuelve una Response. Puede ser texto, HTML, JSON, un redirect, un stream o un archivo. Esa respuesta vuelve al usuario desde la red de Cloudflare. Para el cliente, sigue siendo una respuesta HTTP normal; para la arquitectura, es el resultado de una pieza de lógica distribuida que ocurrió antes, o en lugar, de un origen tradicional.[web:42][page:2]

Runtime de Workers

El runtime de Workers merece atención especial porque define cómo se programa. Muchos desarrolladores llegan desde Node.js y esperan un servidor tradicional minimalista. En realidad, Workers se siente más cercano al modelo de la web moderna: objetos estándar, APIs del navegador adaptadas al servidor y un fuerte énfasis en fetch() y streams.

JavaScript

JavaScript es el lenguaje base más natural para empezar. El Worker puede exportar un manejador fetch que recibe request, env y ctx, y devuelve una Response. Esa forma no es un detalle cosmético; refleja la filosofía de Web Standards de la plataforma.[web:35][web:42]

Ejemplo mínimo funcional:

export default {
  async fetch(request, env, ctx) {
    return new Response('Hola desde Cloudflare Workers', {
      headers: {
        'content-type': 'text/plain; charset=UTF-8'
      }
    });
  }
};

Ese ejemplo ya resume tres ideas clave: entrada HTTP, uso de Response estándar y ausencia de un servidor explícito con listen() o puertos abiertos.

TypeScript

TypeScript es muy recomendable en proyectos reales porque mejora la experiencia con tipos, bindings y contratos de datos. Cloudflare mantiene documentación y tooling que integran tipos del entorno, y Wrangler ofrece opciones relacionadas con tipos de entorno y runtime en sus herramientas.[web:38]

Ejemplo básico en TypeScript:

interface Env {
  APP_NAME: string;
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    return Response.json({
      ok: true,
      app: env.APP_NAME,
      path: new URL(request.url).pathname
    });
  }
};

Web Standards

La compatibilidad con Web Standards es una de las señas de identidad de Workers. La plataforma gira alrededor de objetos familiares para quien conoce la web: Request, Response, Headers, URL, ReadableStream, fetch, entre otros. Esto reduce fricción conceptual cuando el desarrollador ya entiende cómo opera HTTP desde el lado del navegador o desde APIs web modernas.[web:35][web:42]

La consecuencia es importante: en Workers se escribe menos “código de infraestructura” y más lógica de protocolo. En vez de montar un framework solo para obtener acceso a request y response, ya se parte de esos objetos como base del runtime.

Fetch API

fetch() es central en Workers. Sirve tanto para responder a la petición entrante como para hacer subrequests a otros servicios. La documentación de límites deja claro que las llamadas fetch() cuentan como subrequests, y por tanto forman parte del diseño de costo y capacidad del Worker.[page:1]

Request

Request representa la solicitud entrante. Desde él se leen método, URL, headers, cuerpo y metadata de contexto. En términos pedagógicos, es la materia prima del Worker: todo lo que el cliente pidió viene encapsulado ahí.

Response

Response representa lo que el Worker devuelve. Puede construirse manualmente o mediante ayudas como Response.json(), y permite fijar status, headers y body con gran precisión. Eso convierte a Workers en una herramienta natural para APIs HTTP puras.

Streams

Los streams son relevantes porque permiten evitar cargar grandes payloads en memoria. La documentación de límites recomienda expresamente usar TransformStream o node:stream en lugar de bufferizar cuerpos completos cuando hay riesgo de exceder memoria, y también señala que el error Memory limit would be exceeded before EOF puede aparecer al intentar acumular cuerpos demasiado grandes.[page:1]

Dicho de otra forma: en Workers, transmitir incrementalmente no es solo una optimización elegante; en ciertos escenarios es parte de programar correctamente dentro de los límites del runtime.

Limitaciones

Toda plataforma especializada impone límites, y Workers no es la excepción. La documentación oficial enumera varios: memoria por isolate de 128 MB, bundle comprimido de 3 MB en Free y 10 MB en Paid, variables de entorno limitadas, startup time de 1 segundo, subrequests por invocación y CPU time por request según plan.[page:1]

Esas limitaciones no invalidan la plataforma; la definen. Un Worker no está pensado para ser un monolito pesado con muchas dependencias inútiles. Está pensado para lógica compacta, eficiente y claramente integrada con servicios externos o bindings nativos.

Compatibilidad

La compatibilidad debe evaluarse desde el prisma correcto. Si tu código depende de Web Standards y librerías compatibles con ese entorno, la experiencia suele ser muy buena. Si depende de APIs muy específicas del ecosistema Node clásico o de supuestos fuertes sobre filesystem local, procesos persistentes o librerías de sistema, habrá que revisar la adecuación con más cuidado.

En otras palabras, Workers no es “Node remoto”. Es un runtime web distribuido con compatibilidades crecientes y límites claros. Entender esa identidad evita frustraciones innecesarias.

Primer Worker

Llegó el momento de construir el primer Worker de forma completa y paso a paso. La meta de esta sección es eliminar la idea de que Workers es un producto abstracto. En realidad, el ciclo básico es muy directo: crear proyecto, autenticar Wrangler, escribir el manejador fetch, desplegar y probar.

1. Crear un Worker

El flujo moderno gira alrededor de Wrangler, el CLI oficial de Cloudflare para desarrollar, probar y desplegar Workers. Cloudflare dedica documentación específica a desarrollo y testing con Workers y a la API de Wrangler, subrayando que el CLI forma parte esencial de la experiencia de desarrollo.[web:42][web:38]

Un inicio típico es usar el generador del proyecto o crear la estructura base manualmente. Un ejemplo mínimo funcional de archivo principal sería este:

export default {
  async fetch(request) {
    const url = new URL(request.url);

    return Response.json({
      ok: true,
      message: 'Mi primer Worker',
      method: request.method,
      path: url.pathname,
      timestamp: new Date().toISOString()
    });
  }
};

2. Publicarlo

Una vez autenticado el CLI y configurado el proyecto, el despliegue se realiza con Wrangler. La documentación de límites incluso menciona npx wrangler@latest deploy como parte del flujo para medir startup time, lo que confirma que deploy forma parte del camino oficial de publicación.[page:1]

3. Ejecutarlo

Después del despliegue, el Worker puede ejecutarse en un subdominio workers.dev, en un Custom Domain o sobre Routes en una zona existente. La documentación de rutas distingue con claridad estos mecanismos de asociación, y enfatiza que las rutas se aplican a patrones URL dentro de una zona activa de Cloudflare.[page:2]

4. Probarlo

La prueba puede hacerse con navegador, curl, Postman o herramientas locales de desarrollo. Cloudflare mantiene documentación específica sobre development and testing, lo cual refuerza que el desarrollo local es parte oficial del flujo y no un añadido secundario.[web:42]

Ejemplo con curl:

curl -i https://mi-worker.ejemplo.workers.dev/

Si todo sale bien, la respuesta será un JSON con ok: true, método, path y timestamp.

Wrangler

Wrangler es la herramienta de línea de comandos oficial para Cloudflare Workers. Su papel es tan central que puede entenderse como el puente entre tu proyecto local y la plataforma: crea proyectos, ejecuta desarrollo local o remoto, gestiona configuración, despliega y ayuda a trabajar con tipos y bindings.[web:38][web:42]

Qué es

Wrangler es el CLI de Workers. La documentación oficial lo presenta mediante una sección completa de APIs y herramientas alrededor del desarrollo con Workers, y la documentación de límites lo menciona directamente en tareas como deploy y validación de startup time.[web:38][page:1]

Instalación

La forma más simple suele ser usar npm, ya sea como dependencia de desarrollo o mediante npx. Un patrón habitual es este:

npm install -D wrangler

O ejecutar la versión más reciente cuando haga falta:

npx wrangler@latest --version

Configuración

Wrangler lee configuración desde wrangler.toml o wrangler.jsonc, según el formato elegido. La documentación de rutas y de límites muestra ejemplos de configuración en ambos formatos, y la documentación de assets también explica cómo estos archivos controlan bindings y comportamiento del Worker.[page:2][page:1][web:41]

Autenticación

Para desplegar de manera real debes autenticar Wrangler con tu cuenta de Cloudflare. Ese paso vincula el proyecto local con tu cuenta y permisos. Operativamente, es el punto donde el CLI deja de ser una herramienta local y se convierte en un canal de despliegue hacia la red global.

Comandos principales

Los comandos básicos que conviene memorizar son estos:

  • wrangler dev, para desarrollo y pruebas locales o remotas.[web:42]
  • wrangler deploy, para desplegar a producción.[page:1]
  • wrangler tail, para observar logs en tiempo real, útil en debugging operativo.
  • wrangler secret put, para registrar secretos de forma segura.

Despliegue

El despliegue con Wrangler es uno de los rasgos más atractivos de la plataforma. No consiste en abrir una VM, subir archivos y reiniciar procesos. Consiste en empaquetar el Worker, validar límites y publicarlo sobre la infraestructura administrada de Cloudflare.[page:1]

Desarrollo local

Cloudflare mantiene una sección específica para development and testing, lo que deja claro que el desarrollo local es un flujo oficial y soportado. Esto permite probar rutas, requests y respuestas antes del despliegue definitivo.[web:42]

Estructura de un proyecto

Aunque cada proyecto puede variar, conviene trabajar con una estructura limpia y predecible. Lo mínimo suele incluir el código fuente, el archivo de configuración de Wrangler y el package.json del proyecto Node para gestionar scripts y dependencias.

src/

La carpeta src/ suele contener el archivo principal del Worker, por ejemplo src/index.ts o src/index.js. Mantener el código en src/ ayuda a separar claramente fuente, configuración y dependencias.

wrangler.toml

Este archivo define nombre del Worker, compatibilidad, rutas, variables, bindings y otras opciones. La documentación de rutas muestra cómo pueden declararse rutas con zone_name o zone_id, y la documentación de límites señala que varias capacidades ajustables se definen también desde la configuración del Worker.[page:2][page:1]

Ejemplo simple:

name = "nlink-worker"
main = "src/index.ts"
compatibility_date = "2026-06-28"

[vars]
APP_NAME = "NLink Edge API"

package.json

Aquí vives scripts útiles y dependencias del proyecto. Ejemplo:

{
  "name": "nlink-worker",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "dev": "wrangler dev",
    "deploy": "wrangler deploy"
  },
  "devDependencies": {
    "wrangler": "^4.0.0"
  }
}

Configuración

Un proyecto serio no debería dejar su configuración dispersa. wrangler.toml debe expresar claramente bindings, rutas, variables, ambientes y límites cuando aplique. Eso mejora trazabilidad y reduce errores de despliegue.

Variables

Cloudflare distingue variables de entorno y secrets dentro del modelo de bindings y límites. La documentación indica que hay un máximo de variables por Worker, incluyendo secrets y variables de texto, y que cada una tiene un límite de tamaño de 5 KB.[page:1]

Build

Workers no siempre requiere un proceso de build complejo, pero en proyectos TypeScript o con varias dependencias puede haber un empaquetado gestionado por Wrangler. El principio correcto es mantener el bundle pequeño y evitar dependencias innecesarias, porque el tamaño comprimido del Worker está limitado y además impacta el startup time.[page:1]

Request y Response

Esta sección es el corazón práctico del runtime. Si el lector comprende bien Request y Response, ya puede construir una gran cantidad de servicios útiles.

Request

Request representa la solicitud entrante. En él están el método HTTP, la URL, los headers y el cuerpo. Casi toda API en Workers empieza leyendo estos datos y tomando decisiones a partir de ellos.

Ejemplo:

export default {
  async fetch(request) {
    const url = new URL(request.url);

    return Response.json({
      method: request.method,
      pathname: url.pathname,
      search: url.search,
      userAgent: request.headers.get('user-agent')
    });
  }
};

Response

Response encapsula la salida del Worker. Puedes devolver texto, JSON, HTML o incluso redirecciones. Un ejemplo de texto simple:

return new Response('OK', {
  status: 200,
  headers: {
    'content-type': 'text/plain; charset=UTF-8'
  }
});

Headers

Los headers permiten controlar contenido, cacheo, autenticación, CORS y muchos otros aspectos. Son especialmente importantes cuando Workers funciona como API o middleware.

return Response.json(data, {
  headers: {
    'cache-control': 'no-store',
    'x-powered-by': 'cloudflare-workers'
  }
});

Body

El cuerpo puede leerse como texto, JSON, form data o stream, según el tipo de petición. En POST y PUT esto es esencial.

JSON

La forma más cómoda para APIs modernas suele ser JSON. Ejemplo:

const payload = await request.json();
return Response.json({ received: payload }, { status: 201 });

Texto

El texto sigue siendo útil para health checks, respuestas mínimas, debugging o endpoints muy simples.

const body = await request.text();
return new Response(`Recibido: ${body}`);

Streams

Cuando la respuesta o la entrada es grande, conviene evitar bufferizar. La documentación de límites insiste en usar streams para no disparar consumo de memoria de forma innecesaria.[page:1]

Status Codes

Una API profesional debe usar status codes de forma consistente. 200 para éxito estándar, 201 para creación, 204 para ausencia de contenido, 400 para entrada inválida, 401 para autenticación, 403 para autorización, 404 para recurso ausente, 409 para conflicto y 500 para error interno son patrones razonables y comprensibles.

Fetch API

En Workers, fetch() no es una comodidad opcional: es uno de los ejes del runtime. Sirve para llamar orígenes, APIs externas, otros servicios y, en algunos escenarios, recursos internos mediante bindings especializados.[web:35][page:1]

fetch()

Ejemplo simple:

const upstream = await fetch('https://api.example.com/data');
const data = await upstream.json();
return Response.json({ data });

GET

GET suele usarse para consulta y lectura:

const resp = await fetch('https://api.example.com/items');

POST

const resp = await fetch('https://api.example.com/items', {
  method: 'POST',
  headers: { 'content-type': 'application/json' },
  body: JSON.stringify({ name: 'Nuevo item' })
});

PUT

await fetch('https://api.example.com/items/123', {
  method: 'PUT',
  headers: { 'content-type': 'application/json' },
  body: JSON.stringify({ name: 'Actualizado' })
});

DELETE

await fetch('https://api.example.com/items/123', {
  method: 'DELETE'
});

PATCH

await fetch('https://api.example.com/items/123', {
  method: 'PATCH',
  headers: { 'content-type': 'application/json' },
  body: JSON.stringify({ active: false })
});

Timeout

No existe una línea mágica donde el timeout sea “resuelto por el desarrollador” como en todos los entornos, pero sí es una buena práctica diseñar tus llamadas para evitar bloqueos largos y dependencia innecesaria de servicios lentos. Recuerda además que el tiempo esperando red no cuenta como CPU time, pero sí afecta duración percibida y experiencia final.[page:1]

Errores

Toda llamada fetch() puede fallar por conectividad, status inesperados, DNS, TLS o disponibilidad del servicio remoto. Un Worker robusto no asume éxito; valida response.ok, controla excepciones y devuelve errores consistentes.

Routing

Routing es la manera en que el tráfico llega al Worker correcto. Aquí Cloudflare ofrece varias posibilidades: subdominios workers.dev, rutas dentro de zonas existentes y dominios personalizados o custom domains.[page:2]

Routes

Las Routes permiten mapear patrones URL a un Worker. La documentación oficial explica que cuando una solicitud coincide con el patrón configurado, el Worker se ejecuta sobre esa ruta.[page:2]

Eso es ideal cuando ya tienes una aplicación existente detrás de Cloudflare y quieres insertar lógica antes de llegar al origen: logging, autenticación, proxy selectivo, transformación, caché o seguridad.

workers.dev

workers.dev es útil para pruebas rápidas y despliegues iniciales. Permite tener una URL pública sin configurar inmediatamente una zona o dominio propio. Para aprendizaje y prototipos es excelente.

Dominios personalizados

Los custom domains permiten que el Worker responda en un dominio real de tu aplicación. Arquitectónicamente, esto importa mucho porque convierte al Worker en una pieza visible de tu sistema de producción, no solo en un subdominio técnico auxiliar.

Subdominios

También es común separar funciones por subdominio: api.ejemplo.com, links.ejemplo.com, hooks.ejemplo.com. Esto hace más legible la arquitectura y permite rutas o Workers especializados por responsabilidad.

Variables de entorno

Cloudflare trata variables y secrets como bindings del entorno. La documentación de bindings y límites deja claro que el acceso a estos datos forma parte del diseño oficial del runtime y que existen límites por cantidad y tamaño.[web:35][page:1]

Secrets

Los secrets son el lugar correcto para tokens, API keys y credenciales sensibles. Cloudflare destaca que con bindings no hace falta exponer claves en el código para acceder a recursos del propio ecosistema, y que los secretos subyacentes no quedan expuestos al Worker de la misma forma que un string hardcodeado.[web:35]

Environment Variables

Las variables de entorno de texto son útiles para configuración no sensible: nombre de la app, flags simples, URLs base, modo de ejecución o identificadores no confidenciales. El patrón correcto es diferenciarlas claramente de los secretos.

Configuración

Ejemplo en wrangler.toml:

[vars]
APP_NAME = "NLink API"
PUBLIC_BASE_URL = "https://links.ejemplo.com"

Seguridad

La regla más importante es simple: lo secreto va en secrets, no en variables de texto ni en el repositorio. En arquitecturas reales, muchas fugas de seguridad nacen de confundir configuración conveniente con información sensible.

Middleware

Uno de los mejores usos de Workers es como middleware distribuido. La documentación de rutas describe justamente el patrón de poner Workers delante de una aplicación existente y usar fetch() para continuar hacia el origen cuando haga falta.[page:2]

Qué es

Middleware es una capa intermedia que inspecciona o modifica una solicitud antes de que llegue al servicio final, o bien transforma la respuesta antes de devolverla al cliente. Puede autenticar, registrar, filtrar, añadir headers o redirigir.

Cómo funciona

Un Worker recibe la petición, ejecuta lógica previa y luego decide entre dos caminos: responder directamente o reenviar con fetch(request) hacia otro destino. Esa es la esencia de middleware en el edge.

Casos de uso

  • Verificación de tokens.
  • Rate limiting por ruta o por usuario.[web:32]
  • Normalización de headers.
  • CORS centralizado.
  • Logging y trazas.
  • Proxy hacia APIs externas.
  • Reescrituras y redirects.

Autenticación

Autenticar en el edge puede reducir carga sobre el origen y bloquear tráfico inválido antes de que entre a sistemas más costosos. Es especialmente útil en APIs, dashboards, herramientas internas y webhooks.

Logging

Workers permite emitir logs, pero hay que recordar que Cloudflare fija un límite de 256 KB de datos de logs por request. Después de superar ese umbral, no se registra más contexto para esa invocación.[page:1]

Validación

Validar datos temprano es una práctica excelente en Workers. Evita reenviar peticiones inválidas a orígenes o bases de datos y hace más predecibles las respuestas de la API.

APIs REST

Workers es una plataforma especialmente cómoda para APIs REST ligeras y medianas. La combinación de Request, Response, JSON y rutas por pathname hace que el código sea directo y legible.

Cómo construir una API

Una forma simple es inspeccionar método y pathname en el manejador fetch, y luego delegar a funciones internas. Ejemplo:

interface Env {
  APP_NAME: string;
}

function json(data: unknown, status = 200): Response {
  return Response.json(data, {
    status,
    headers: {
      'content-type': 'application/json; charset=UTF-8'
    }
  });
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const url = new URL(request.url);

    if (request.method === 'GET' && url.pathname === '/api/health') {
      return json({ ok: true, service: env.APP_NAME });
    }

    if (request.method === 'GET' && url.pathname === '/api/version') {
      return json({ version: 'v1' });
    }

    return json({ error: 'Not Found' }, 404);
  }
};

Endpoints

Los endpoints deben diseñarse con claridad semántica. /api/links/:code, /api/credentials/:id, /api/qr, /api/webhooks/telegram son ejemplos mucho mejores que rutas ambiguas o mezcladas sin criterio.

Versionado

Una práctica razonable es versionar bajo prefijo como /api/v1/.... Esto evita romper clientes cuando evoluciona el contrato.

Buenas prácticas

  • Mantener naming consistente.
  • Devolver JSON coherente.
  • Usar status codes correctos.
  • No mezclar errores internos con respuestas exitosas.
  • Validar entrada y documentar formato.
  • Reducir dependencia innecesaria de frameworks pesados.

JSON

JSON es el formato natural para la mayoría de APIs serverless modernas, especialmente en Workers, donde Response.json() simplifica mucho la salida.

Errores

La API debe devolver errores legibles y consistentes. Un error no debe ser un stack trace crudo al cliente, sino un objeto estructurado con mensaje, código y quizá detalles limitados.

Manejo de errores

Toda API profesional necesita una estrategia clara de errores. En Workers esto importa todavía más porque el código suele estar en la primera línea de contacto con el usuario o con sistemas externos.

try/catch

Patrón básico:

export default {
  async fetch(request) {
    try {
      const payload = await request.json();
      return Response.json({ ok: true, payload });
    } catch (error) {
      return Response.json({
        ok: false,
        error: 'Invalid request body'
      }, { status: 400 });
    }
  }
};

Errores HTTP

Distingue claramente entre errores del cliente y errores del servidor. Un JSON inválido no es un 500; suele ser un 400. Un recurso inexistente no es un 500; es un 404. Una credencial inválida no es un 500; es un 401 o 403 según el caso.

Logs

Registrar el error es importante, pero sin llenar el sistema de ruido y respetando el límite de logs por request. El objetivo del log es ayudar a diagnosticar, no duplicar toda la carga útil ciegamente.[page:1]

Debugging

El debugging mejora mucho cuando el Worker devuelve respuestas estructuradas y los logs incluyen identificadores útiles: ruta, método, request id y clase de error. También es útil diferenciar explícitamente entre errores de validación, errores de upstream y fallos internos.

Buenas prácticas

  • No esconder todos los errores detrás de un único 500.
  • No exponer secretos ni trazas sensibles al cliente.
  • Estructurar mensajes de error.
  • Registrar contexto mínimo suficiente.
  • Mantener consistencia entre endpoints.

Integración con otros servicios

Una de las mayores fortalezas de Workers es que no vive aislado. Su valor aumenta cuando se conecta con otros servicios del ecosistema o con plataformas externas.

Workers + R2

R2 es ideal para objetos: imágenes, archivos, respaldos, PDFs, QR generados o blobs de salida. Usar un binding evita tener que manejar credenciales manuales dentro del código, siguiendo el enfoque de bindings como permiso y API a la vez.[web:35]

Diagrama ASCII: Worker + R2

[Cliente]
   |
   v
[Worker]
   |
   v
[R2 Bucket]
   |
   v
[Archivo / Objeto]

Workers + D1

D1 es adecuado cuando el caso de uso exige consultas SQL y relaciones más estructuradas. Un Worker puede recibir una petición, validar datos, consultar D1 y devolver JSON sin necesidad de un servidor SQL administrado por separado desde la perspectiva del desarrollador.

Diagrama ASCII: Worker + D1

[Cliente]
   |
   v
[Worker]
   |
   v
[D1]
   |
   v
[Consulta SQL -> filas -> Response.json()]

Workers + KV

KV es excelente para mapas clave-valor: short links, configuración, flags, sesiones ligeras o metadata rápida. En muchos servicios tipo redirector, KV es la primera opción natural por simplicidad conceptual.[web:35]

Diagrama ASCII: Worker + KV

[Cliente]
   |
   v
[Worker]
   |
   v
[KV]
   |
   v
[clave -> valor -> respuesta]

Workers + Queues

Queues permite desacoplar trabajo que no debe ejecutarse sincrónicamente en la respuesta principal. Si una solicitud genera tareas posteriores, como registrar analítica, enviar eventos o procesar transformaciones secundarias, una cola evita que el usuario espere por trabajo no crítico.[web:35][page:1]

Workers + Pages

Pages y Workers pueden trabajar juntos. Cloudflare también documenta bindings para Pages Functions, mostrando que el ecosistema comparte muchas piezas y que KV, por ejemplo, también puede integrarse con Pages Functions.[web:34]

Diagrama ASCII: Worker + Pages

[Usuario]
   |
   v
[Cloudflare Pages]
   |
   v
[Worker / Function]
   |
   v
[Bindings / APIs / Storage]

Workers + Firebase

La combinación con Firebase es muy interesante para desarrolladores que ya usan Firestore, Auth o Hosting. Un Worker puede actuar como middleware edge, API pública, proxy de seguridad, capa de cacheo o webhook delante de servicios alojados en Firebase. La lógica de valor aquí no es reemplazar Firebase, sino complementarlo con una capa distribuida y cercana a la red.

Workers + AWS

Con AWS, Workers suele brillar como capa frontal: proxy, auth edge, normalización, redirects, caching inteligente o agregación de respuestas antes de tocar Lambda, API Gateway, S3 u otros servicios. Así se reduce carga sobre componentes centrales y se mejora la experiencia en el borde.

Límites

Hablar de Workers sin hablar de límites sería un error pedagógico. Las limitaciones no son notas al pie; son parte de la forma correcta de diseñar en esta plataforma.

CPU Time

Cloudflare diferencia claramente CPU time y duración total. El CPU time mide cuánto tiempo la CPU ejecuta tu código; esperar red, KV, D1 o fetch() no cuenta como CPU time. En Free, el CPU time por HTTP request es de 10 ms. En Paid, el valor por defecto es 30 segundos y puede elevarse hasta 5 minutos.[page:1]

Memoria

La memoria por isolate es de 128 MB. Si se excede, el runtime permite que solicitudes en curso terminen y crea un nuevo isolate para solicitudes futuras; bajo carga extrema incluso puede cancelar algunas solicitudes entrantes para mantener estabilidad.[page:1]

Tiempo de ejecución

Cloudflare distingue aquí duración real y CPU. Para solicitudes HTTP no hay un límite duro de duración mientras el cliente siga conectado y la respuesta continúe. Además, ctx.waitUntil() puede extender trabajo por hasta 30 segundos después de enviar la respuesta o de una desconexión del cliente.[page:1]

Requests

El plan Free incluye 100,000 requests por día. El plan Paid elimina ese límite general de requests diarios, aunque otras capacidades siguen dependiendo del diseño del Worker y sus recursos.[page:1]

Costos

En la práctica, el momento de preocuparse por costos llega cuando el servicio deja de ser un experimento y empieza a recibir tráfico sostenido o a depender fuertemente de subrequests, D1, R2, Queues o APIs externas. Workers puede ser muy económico para lógica ligera, pero el diseño arquitectónico completo determina el costo real del sistema.

Cuándo pasar al plan de pago

Hay varias señales claras:

  • Superas 100,000 requests por día.[page:1]
  • Necesitas más de 50 subrequests por invocación.[page:1]
  • Requieres más variables, más bundle o más Workers por cuenta.[page:1]
  • Tu carga necesita más CPU time del disponible en Free.[page:1]
  • Estás operando un servicio real donde fallar abierto por límite diario ya no es aceptable.[page:1]

Seguridad

Workers participa en la capa de entrada del sistema, así que la seguridad no es un extra. Debe formar parte del diseño desde el principio.

Secrets

Los secrets son la forma adecuada de almacenar tokens y credenciales sensibles. El modelo de bindings de Cloudflare está diseñado para reducir exposición de secretos dentro del código y mejorar la seguridad del acceso a recursos de la plataforma.[web:35]

API Keys

Las API keys nunca deben hardcodearse. Deben leerse desde secrets y validarse con cuidado. También conviene limitar su uso por ruta, por cliente o por binding específico cuando sea posible.

Tokens

Cuando el Worker autentica JWT, bearer tokens u otros artefactos, debe validar formato, expiración y contexto. El edge es un excelente lugar para esa validación temprana.

Validación

Validar entradas reduce superficie de ataque. No aceptes métodos inesperados, cuerpos arbitrarios ni headers peligrosos solo porque el runtime los permite.

CORS

Si la API será usada desde navegadores, CORS debe definirse explícitamente. Workers es un lugar excelente para centralizar políticas CORS coherentes, en lugar de repartirlas en múltiples orígenes.

Rate Limiting

Cloudflare ofrece Rate Limiting bindings para usar límites directamente desde el Worker. La documentación oficial destaca que puedes aplicar límites por ruta, por tipo de usuario o por recurso, y recomienda usar claves estables como API keys, user IDs o rutas, evitando IPs cuando puedan agrupar usuarios válidos de forma indeseada.[web:32]

Buenas prácticas

  • Guardar secretos fuera del código.[web:35]
  • Validar método, ruta y payload.
  • Limitar tráfico sensible.
  • No filtrar mensajes internos al cliente.
  • Aplicar CORS con intención explícita.
  • Registrar solo lo necesario.
  • Diseñar con el supuesto de que el endpoint público será explorado y atacado.

Comparativa

Ninguna plataforma existe en el vacío. Para decidir bien, conviene comparar Workers con otras opciones populares.

Plataforma Fortaleza principal Debilidad principal
Cloudflare Workers Ejecución edge integrada en la red de Cloudflare, modelo web nativo, excelente para middleware y APIs ligeras [web:35][page:2] Límites y modelo menos natural para cargas pesadas o supuestos clásicos de servidor [page:1]
AWS Lambda Ecosistema inmenso y gran integración con AWS Mayor complejidad de configuración y experiencia regional más típica
Google Cloud Functions Integración con GCP y flujos serverless conocidos Menos orientado al edge como idea central
Firebase Functions Muy cómodo para ecosistemas Firebase y backend rápido para apps Menos centrado en edge global, con enfoque fuerte en ecosistema Firebase
Azure Functions Buena integración con servicios Microsoft Menor ubicuidad cultural en proyectos web independientes
Vercel Functions Muy fuerte en frontends y apps web modernas Dependencia fuerte del ecosistema Vercel y patrón más acoplado a su plataforma
Netlify Functions Accesible y simple para sitios JAMstack Menos potente como plataforma edge general comparada con Workers

Cloudflare Workers

Ventajas: excelente como capa edge, buen modelo de fetch, bindings integrados, despliegue rápido, rutas potentes, gran afinidad con middleware, proxies y APIs ligeras. Desventajas: requiere pensar diferente a un backend Node clásico; no es el entorno ideal para cualquier librería pesada o patrón heredado.[web:35][page:1]

AWS Lambda

Lambda ofrece una integración gigantesca con el universo AWS y una madurez enorme para cargas empresariales. A cambio, muchas arquitecturas terminan más acopladas a servicios complementarios como API Gateway, IAM, VPC y otros componentes cuya complejidad puede ser superior para proyectos pequeños o medianos.

Google Cloud Functions

Cloud Functions encaja bien en ecosistemas GCP y automatizaciones conectadas a otros servicios del proveedor. Sin embargo, su narrativa principal no gira tanto alrededor del edge distribuido como en Workers.

Firebase Functions

Firebase Functions es extremadamente atractivo para apps rápidas conectadas con Firebase Auth, Firestore y Hosting. Para desarrolladores ya inmersos en Firebase, la curva operativa suele ser muy agradable. Workers, en cambio, suele ganar cuando la prioridad es una capa edge global, middleware o lógica cercana a la red antes del backend.

Azure Functions

Azure Functions es sólido en entornos empresariales y organizaciones ya alineadas con Microsoft. Su decisión suele venir más por estrategia de plataforma que por superioridad intrínseca para edge.

Vercel Functions

Vercel brilla cuando el frontend y el despliegue están muy ligados a su ecosistema, especialmente en proyectos con fuerte énfasis en DX para frameworks modernos. Workers suele sentirse más generalista a nivel de red y más cercano a la idea de “programar el edge”.

Netlify Functions

Netlify Functions es una puerta de entrada cómoda para funciones ligadas a sitios modernos. En comparación, Workers ofrece una historia más potente en red, bindings y control del tráfico en el borde.

Casos reales

La mejor prueba de una plataforma no es lo bien que suena en teoría, sino los sistemas concretos que puedes construir con ella. A continuación se desarrollan varios casos especialmente relevantes para el tipo de lector de este libro.

Un acortador de enlaces es casi un caso de manual para Workers. El usuario solicita /abc123, el Worker busca el destino asociado a esa clave y responde con una redirección HTTP. Este patrón aprovecha muy bien un runtime edge porque la operación es ligera, el beneficio de latencia es real y el modelo clave-valor encaja perfectamente con KV.[web:35]

Además, es un sistema donde el edge aporta mucho valor práctico: redirects rápidos, personalización por región o agente, logging, expiración y eventual integración con analytics. Para NLink, Workers es una excelente opción porque resuelve el caso simple con muy poca infraestructura y deja un camino de crecimiento natural hacia KV, D1 y analítica.

API de Credenciales Digitales

Una API que valida o entrega credenciales digitales puede usar Workers como capa pública de autenticación, validación y formato de respuesta, mientras delega almacenamiento persistente a D1, R2 o un backend complementario. El edge es muy útil aquí para verificar tokens, proteger rutas y responder rápidamente consultas de lectura o verificación.

Generador de QR

Un Worker puede recibir datos, validarlos, delegar generación a una librería compatible o a un servicio interno y devolver la imagen o metadatos. Si además se guardan imágenes en R2, la arquitectura queda especialmente limpia: Worker para entrada y control, R2 para almacenamiento de salida.[web:35]

Redirecciones inteligentes

Redirigir según país, device, idioma, campaña o disponibilidad de backend es un caso edge clásico. No quieres enviar siempre esas decisiones a un servidor central. Quieres tomarlas lo antes posible en la ruta de la petición. Workers es excelente precisamente para eso.[page:2]

API para IA El Profe

Si existe una API pública o semipública que recibe prompts, valida cuotas, firma peticiones o enruta hacia modelos externos, Workers puede servir como puerta de entrada segura. Puede validar tokens, aplicar rate limiting, registrar métricas y normalizar respuestas antes de tocar proveedores externos.[web:32]

Webhook de Telegram

Los webhooks son otro caso natural. Telegram envía una petición HTTP, el Worker valida origen, procesa payload, desencadena lógica posterior y responde rápido. Si parte del procesamiento es costoso, una Queue puede desacoplar el trabajo y dejar que la respuesta al webhook sea inmediata.[web:35][page:1]

Proxy para APIs externas

Workers es particularmente fuerte como proxy: añade auth, normaliza headers, oculta claves, aplica caché, controla CORS y estandariza errores. Todo eso sin necesidad de abrir un servidor dedicado solo para actuar de intermediario.

Diagramas ASCII

Arquitectura de Workers

[Cliente]
   |
   v
[Route / Custom Domain / workers.dev]
   |
   v
[Cloudflare Edge]
   |
   v
[Worker]
  /  |   |   \
 v   v   v    v
KV  D1  R2  API externa
  \  |   |   /
     v   v  v
      [Response]

Request -> Worker -> Response

HTTP Request
    |
    v
[Worker fetch handler]
    |
    +--> valida método
    +--> lee URL
    +--> autentica
    +--> consulta bindings o upstream
    |
    v
HTTP Response

Worker + R2

[Usuario] -> [Worker] -> [R2 Bucket] -> [Objeto] -> [Response]

Worker + D1

[Usuario] -> [Worker] -> [SQL en D1] -> [Filas] -> [JSON]

Worker + KV

[Usuario] -> [Worker] -> [KV: code => url] -> [301/302 Redirect]

Worker + Pages

[Browser] -> [Pages] -> [Worker Function] -> [Bindings / APIs] -> [HTML o JSON]

Flujo completo de una API

[Cliente]
   |
   v
GET /api/v1/links/abc123
   |
   v
[Cloudflare Edge]
   |
   v
[Worker]
   |
   +--> valida método y ruta
   +--> lee variables/env
   +--> consulta KV o D1
   +--> maneja errores
   |
   v
[JSON / Redirect / Error]
   |
   v
[Cliente]

Buenas prácticas

  • Mantener Workers pequeños y enfocados, porque el tamaño del bundle y el startup time importan.[page:1]
  • Evitar trabajo costoso en el global scope, ya que Cloudflare exige que el código de arranque se ejecute dentro del límite de startup time.[page:1]
  • Usar bindings en lugar de credenciales hardcodeadas cuando la plataforma lo permita.[web:35]
  • Validar pronto y responder temprano.
  • Usar streams cuando el payload pueda crecer mucho.[page:1]
  • Diseñar subrequests con intención, porque tienen límites y costo.[page:1]
  • Separar responsabilidades: edge logic, storage, cola y origen.
  • Tratar el Worker como una capa de arquitectura, no como una carpeta donde meter cualquier cosa.

Errores comunes

  • Querer portar sin adaptación un backend Node clásico completo.
  • Usar demasiadas dependencias para resolver tareas pequeñas.
  • Ignorar límites de subrequests, memoria o bundle.[page:1]
  • Hardcodear secretos o mezclar secretos con variables públicas.[web:35][page:1]
  • Tratar todos los errores como 500.
  • No distinguir entre lógica edge y origen real.
  • Hacer logging excesivo sin estrategia, chocando con límites por request.[page:1]
  • No pensar en rate limiting y CORS desde el inicio.[web:32]

Curiosidades

Una de las curiosidades más interesantes es que Cloudflare diferencia claramente CPU time y duración. Puedes esperar por red sin que eso consuma CPU time, aunque sí afecte la duración total percibida.[page:1]

Otra es que una sola isolate puede atender muchas solicitudes concurrentes, lo que muestra que la unidad real de ejecución en Workers no debe imaginarse como “un proceso por request” al estilo más ingenuo.[page:1]

También es notable que Cloudflare no imponga un límite duro de duración para requests HTTP mientras el cliente siga conectado, lo que abre posibilidades interesantes de streaming y respuestas prolongadas, siempre dentro del diseño adecuado.[page:1]

Resumen

Cloudflare Workers es una plataforma serverless orientada al edge que permite ejecutar lógica distribuida en la red global de Cloudflare sin administrar servidores. Su propuesta técnica combina runtime moderno basado en Web Standards, bindings nativos a servicios del ecosistema y despliegue simple mediante Wrangler.[web:35][web:42]

Workers resuelve problemas reales de latencia, operación y simplicidad arquitectónica, especialmente en middleware, proxies, redirects, APIs ligeras, autenticación, webhooks y automatizaciones HTTP. No reemplaza automáticamente a cualquier backend, pero sí redefine el punto de partida para muchas piezas del software web moderno.[page:2][page:1]

Su modelo exige pensar con claridad: bundles pequeños, validación temprana, uso cuidadoso de subrequests, secretos bien manejados, respuestas consistentes y separación entre lógica edge y almacenamiento. Cuando ese modelo encaja, el resultado es una arquitectura más cercana al usuario, más simple de operar y más elegante desde la perspectiva de infraestructura.[page:1][web:35]

Glosario

Binding

Mecanismo que permite a un Worker interactuar con recursos de la plataforma, actuando como permiso y API integrada a la vez.[web:35]

CPU time

Tiempo efectivo de CPU consumido por el código del Worker, distinto del tiempo total de espera por red o I/O.[page:1]

D1

Servicio de base de datos relacional de Cloudflare accesible desde Workers mediante bindings.[web:35]

Edge Computing

Modelo de cómputo donde la lógica se ejecuta cerca del punto de entrada de la petición en la red, en lugar de depender siempre de un origen central.[page:2]

env

Objeto del runtime donde el Worker recibe bindings, variables y secrets configurados.[web:35]

Isolate

Unidad de ejecución aislada basada en V8 usada por Workers; cada isolate puede manejar múltiples solicitudes y tiene límites de memoria propios.[page:1]

KV

Servicio de almacenamiento clave-valor de Cloudflare, útil para configuraciones, short links y datos simples indexados por clave.[web:35]

R2

Almacenamiento de objetos de Cloudflare, adecuado para archivos y blobs.[web:35]

Route

Patrón URL dentro de una zona de Cloudflare que activa la ejecución de un Worker cuando coincide una solicitud.[page:2]

Serverless

Modelo donde el desarrollador no administra servidores como unidad operativa principal, aunque la ejecución siga ocurriendo sobre infraestructura real.[web:35]

Stream

Flujo de datos procesado de manera incremental, útil para evitar cargar cuerpos completos en memoria.[page:1]

Subrequest

Solicitud realizada por un Worker mediante fetch() o contra ciertos servicios de Cloudflare como KV, R2 o D1, sujeta a límites por invocación.[page:1]

Workers.dev

Subdominio gestionado por Cloudflare para exponer Workers públicamente sin necesidad inmediata de un dominio propio.

Wrangler

CLI oficial para desarrollar, probar y desplegar Cloudflare Workers.[web:38][web:42]

20 preguntas de autoevaluación

  1. ¿Qué significa que Cloudflare Workers sea una plataforma serverless y edge al mismo tiempo?[web:35][page:2]
  2. ¿Por qué Workers no debe entenderse como “Node.js remoto” sino como un runtime basado en Web Standards?[web:35][web:42]
  3. ¿Qué problema de latencia intenta resolver la computación edge?[page:2]
  4. ¿Qué ventajas operativas ofrece Workers frente a un servidor tradicional?[web:35][page:1]
  5. ¿Qué papel cumple Wrangler en el flujo de desarrollo y despliegue?[web:38][web:42]
  6. ¿Qué diferencias existen entre variables de entorno y secrets?[web:35][page:1]
  7. ¿Qué significa que un binding sea una mezcla entre permiso y API?[web:35]
  8. ¿Qué ocurre cuando una URL coincide con una Route configurada?[page:2]
  9. ¿Qué límites principales deben vigilarse en Workers?[page:1]
  10. ¿Qué diferencia hay entre CPU time y duración total?[page:1]
  11. ¿Por qué los streams son importantes en Workers?[page:1]
  12. ¿Cuándo es mejor usar KV y cuándo D1?
  13. ¿Por qué un acortador de enlaces encaja tan bien en Workers?
  14. ¿Qué ventajas tiene usar Workers como middleware delante de un origen?[page:2]
  15. ¿Cómo puede Workers integrarse con R2, D1 y Queues?[web:35]
  16. ¿Qué riesgos hay al depender demasiado de APIs externas desde un Worker?[page:1]
  17. ¿Cuándo conviene pasar del plan Free al Paid?[page:1]
  18. ¿Cómo ayuda Rate Limiting en un Worker público?[web:32]
  19. ¿Qué ventajas estratégicas diferencian a Workers de plataformas como Lambda o Firebase Functions?
  20. ¿Qué buenas prácticas reducen errores de bundle, memoria, seguridad y observabilidad?[page:1][web:35]

Proyecto práctico

El proyecto de esta sección construirá una API REST mínima pero realista con Cloudflare Workers, centrada en un servicio tipo NLink: dado un código corto, el sistema responderá con una redirección HTTP hacia la URL correspondiente. Además, se añadirán endpoints JSON para consulta y pruebas, validación de datos, manejo consistente de errores, variables de entorno y flujo de despliegue.

Objetivo del proyecto

Construir un servicio edge con estas capacidades:

  • Endpoint GET /:code para redirigir por código corto.
  • Endpoint GET /api/health para verificar estado.
  • Endpoint GET /api/links/:code para devolver metadata en JSON.
  • Endpoint POST /api/links/resolve para recibir un código y resolverlo.
  • Validación de datos de entrada.
  • Manejo uniforme de errores.
  • Variables de entorno para configuración.
  • Despliegue con Wrangler.
  • Pruebas con curl y Postman.

1. Configuración del entorno

Estructura recomendada:

nlink-worker/
├── src/
│   └── index.ts
├── package.json
└── wrangler.toml

package.json:

{
  "name": "nlink-worker",
  "version": "1.0.0",
  "type": "module",
  "scripts": {
    "dev": "wrangler dev",
    "deploy": "wrangler deploy"
  },
  "devDependencies": {
    "wrangler": "^4.0.0"
  }
}

wrangler.toml:

name = "nlink-worker"
main = "src/index.ts"
compatibility_date = "2026-06-28"

[vars]
APP_NAME = "NLink Edge API"
DEFAULT_REDIRECT_STATUS = "302"

2. Creación del Worker

Archivo src/index.ts completo y funcional:

interface Env {
  APP_NAME: string;
  DEFAULT_REDIRECT_STATUS: string;
}

type LinkRecord = {
  code: string;
  url: string;
  active: boolean;
  description?: string;
};

const links: Record<string, LinkRecord> = {
  js: {
    code: 'js',
    url: 'https://developer.mozilla.org/',
    active: true,
    description: 'Documentación web'
  },
  cf: {
    code: 'cf',
    url: 'https://developers.cloudflare.com/',
    active: true,
    description: 'Documentación oficial de Cloudflare'
  },
  profe: {
    code: 'profe',
    url: 'https://elprofe.org/',
    active: true,
    description: 'Sitio principal'
  }
};

function json(data: unknown, status = 200, extraHeaders: HeadersInit = {}): Response {
  return new Response(JSON.stringify(data, null, 2), {
    status,
    headers: {
      'content-type': 'application/json; charset=UTF-8',
      'cache-control': 'no-store',
      ...extraHeaders
    }
  });
}

function badRequest(message: string, details?: unknown): Response {
  return json({ ok: false, error: 'bad_request', message, details }, 400);
}

function notFound(message = 'Recurso no encontrado'): Response {
  return json({ ok: false, error: 'not_found', message }, 404);
}

function methodNotAllowed(allowed: string[]): Response {
  return json(
    {
      ok: false,
      error: 'method_not_allowed',
      message: 'Método HTTP no permitido',
      allowed
    },
    405,
    { allow: allowed.join(', ') }
  );
}

function getRedirectStatus(raw: string): 301 | 302 {
  return raw === '301' ? 301 : 302;
}

function findLink(code: string): LinkRecord | null {
  const normalized = code.trim().toLowerCase();
  return links[normalized] ?? null;
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    try {
      const url = new URL(request.url);
      const pathname = url.pathname.replace(/\/+$/, '') || '/';

      if (request.method === 'GET' && pathname === '/api/health') {
        return json({
          ok: true,
          service: env.APP_NAME,
          time: new Date().toISOString()
        });
      }

      if (request.method === 'GET' && pathname.startsWith('/api/links/')) {
        const code = pathname.split('/').pop() ?? '';
        if (!code) return badRequest('Debes enviar un código');

        const link = findLink(code);
        if (!link || !link.active) return notFound('Código no encontrado');

        return json({ ok: true, data: link });
      }

      if (pathname === '/api/links/resolve') {
        if (request.method !== 'POST') {
          return methodNotAllowed(['POST']);
        }

        let body: unknown;
        try {
          body = await request.json();
        } catch {
          return badRequest('El body debe ser JSON válido');
        }

        const code = typeof body === 'object' && body !== null && 'code' in body
          ? String((body as { code: unknown }).code ?? '').trim()
          : '';

        if (!code) {
          return badRequest('El campo code es obligatorio');
        }

        const link = findLink(code);
        if (!link || !link.active) {
          return notFound('Código no encontrado');
        }

        return json({ ok: true, data: link });
      }

      if (request.method === 'GET' && pathname !== '/' && !pathname.startsWith('/api/')) {
        const code = pathname.slice(1);
        const link = findLink(code);

        if (!link || !link.active) {
          return notFound('Código corto inexistente');
        }

        return Response.redirect(link.url, getRedirectStatus(env.DEFAULT_REDIRECT_STATUS));
      }

      if (request.method === 'GET' && pathname === '/') {
        return json({
          ok: true,
          service: env.APP_NAME,
          endpoints: {
            health: 'GET /api/health',
            getLink: 'GET /api/links/:code',
            resolve: 'POST /api/links/resolve',
            redirect: 'GET /:code'
          }
        });
      }

      return notFound();
    } catch (error) {
      console.error('Unhandled error', error);
      return json({
        ok: false,
        error: 'internal_error',
        message: 'Ocurrió un error interno'
      }, 500);
    }
  }
};

3. Uso de Wrangler

Desarrollo local:

npm install
npx wrangler dev

Despliegue:

npx wrangler deploy

Estos comandos encajan con el flujo oficial de desarrollo y despliegue de Workers mediante Wrangler.[web:42][page:1]

4. Variables de entorno

Ya se declararon variables de texto en wrangler.toml. Si más adelante el proyecto usa tokens de APIs externas, deberán almacenarse como secrets y no como texto visible en el repositorio.[web:35][page:1]

5. Endpoints GET

Ya existen dos GET de consulta y uno de redirección:

  • GET /api/health
  • GET /api/links/:code
  • GET /:code

6. Endpoints POST

El endpoint POST /api/links/resolve recibe un JSON como este:

{
  "code": "cf"
}

Y devuelve la URL asociada si el código existe.

7. Validación de datos

La validación implementada cubre varios puntos esenciales:

  • El body debe ser JSON válido.
  • El campo code es obligatorio.
  • El código debe existir y estar activo.
  • Los métodos inválidos reciben 405 cuando corresponde.

8. Manejo de errores

El proyecto incorpora helpers para 400, 404, 405 y 500, lo que mantiene coherencia y evita respuestas improvisadas. Esta consistencia es una de las mejores prácticas más importantes en APIs edge.

9. Respuestas JSON

La función json() centraliza headers y formato. Esto evita duplicación y facilita introducir políticas uniformes como cache-control: no-store.

10. Despliegue en producción

Una vez autenticado Wrangler, el proyecto puede desplegarse y publicarse en workers.dev o vincularse a un dominio o route según la arquitectura deseada. Cloudflare documenta claramente el uso de routes y dominios para conectar el Worker a tráfico real.[page:2]

11. Pruebas con Postman y curl

Health check:

curl -i https://tu-worker.tu-subdominio.workers.dev/api/health

Consulta JSON:

curl -i https://tu-worker.tu-subdominio.workers.dev/api/links/cf

Resolve por POST:

curl -i \
  -X POST https://tu-worker.tu-subdominio.workers.dev/api/links/resolve \
  -H "content-type: application/json" \
  -d '{"code":"cf"}'

Redirección:

curl -i https://tu-worker.tu-subdominio.workers.dev/cf

En Postman, la lógica es la misma: probar cada endpoint con método, path y body correctos, verificando status code, headers y cuerpo.

Evolución del proyecto

Este servicio NLink es deliberadamente simple, pero está diseñado para evolucionar muy bien.

Integrarlo con KV

El paso natural es reemplazar el objeto en memoria por un namespace KV, almacenando pares code -> url o incluso JSON serializado con metadata. Esto vuelve el sistema más flexible sin romper el contrato de la API.[web:35]

Integrarlo con D1

Si necesitas panel administrativo, auditoría, expiración compleja, usuarios, métricas o relaciones, D1 es la evolución lógica. El Worker seguiría en el edge, pero la capa de almacenamiento pasaría de key-value a relacional.[web:35]

Integrarlo con R2

R2 puede guardar recursos asociados a los enlaces: QR generados, previews, imágenes o exportaciones. De ese modo, el Worker se convierte en coordinador entre metadata, redirect y activos binarios.[web:35]

Integrarlo con Analytics

Otra evolución natural es registrar eventos por código, país, agente o fecha. Parte de ese trabajo puede ir a Queues o a otras herramientas analíticas del ecosistema, evitando que la respuesta principal pague el costo completo del registro.[web:35][page:1]

Cierre conceptual del capítulo

Cloudflare Workers obliga a cambiar de mentalidad de una manera sana. En lugar de comenzar pensando en una máquina donde instalar un backend, empiezas pensando en una petición, en una respuesta y en la mejor ubicación para ejecutar la lógica. Esa inversión conceptual es precisamente lo que hace tan poderosa a la computación edge.

Cuando el problema es HTTP, transformación, validación, autenticación, redirección, proxy o integración rápida con recursos distribuidos, Workers suele sentirse menos como una limitación y más como una herramienta quirúrgica. No es un martillo universal, pero sí una de las piezas más elegantes y pragmáticas de la arquitectura web moderna.[web:35][page:2][page:1]