“Binding” conviene dejarlo en inglés.
Traducirlo como “enchufe” puede sonar simpático y confunde. Un binding no es un cable ni un conector visual. En Cloudflare Workers es una conexión declarada entre tu Worker y un recurso.
Cloudflare lo describe como combinación de permiso y API. En la práctica:
configuras que un Worker puede usar un recurso, y en código lo recibes dentro de
env.
env.MY_BUCKET
env.EMAIL_QUEUE
env.COUNTERS
env.AI
Si vienes de Workers 101, esto es el siguiente paso: el Worker deja de ser “solo fetch” y se convierte en una puerta con capacidades.
El problema que resuelve
Sin bindings, muchas integraciones terminan así:
const bucketUrl = "https://...";
const apiKey = "abc...";
const queueName = "prod-email-queue";
Eso se vuelve frágil:
- secrets mezclados con código
- ambientes difíciles de separar
- preview tocando recursos de producción
- nombres duplicados
- dependencias invisibles
Con bindings, la dependencia queda declarada en la configuración del Worker. Tu código no inventa la conexión a mano para recursos de Cloudflare: usa la API que aparece en env.
No digas / Mejor
No digas:
“El binding es un enchufe seguro.”
Mejor:
“El binding es una capacidad declarada que el Worker recibe en
env.”
Ejemplo de arquitectura legible:
Worker "api" tiene:
- ASSETS_BUCKET
- EMAIL_QUEUE
- USER_COUNTERS
Si dibujas los bindings, empiezas a ver el sistema.
Ejemplo: signup → Queue
type SignupJob = {
email: string;
source: string;
};
export interface Env {
SIGNUP_QUEUE: Queue<SignupJob>;
}
export default {
async fetch(request, env): Promise<Response> {
const body = await request.json<SignupJob>();
await env.SIGNUP_QUEUE.send({
email: body.email,
source: body.source ?? "web",
});
return Response.json({ accepted: true }, { status: 202 });
},
} satisfies ExportedHandler<Env>;
La línea que importa:
await env.SIGNUP_QUEUE.send(...);
SIGNUP_QUEUE existe porque fue declarado como binding — no porque el código “descubrió” una cola mágica.
Ejemplo: R2
R2 es object storage. Si el bucket está bound, el Worker lo usa directo:
export interface Env {
ASSETS: R2Bucket;
}
export default {
async fetch(request, env): Promise<Response> {
if (request.method !== "PUT") {
return new Response("Use PUT", { status: 405 });
}
const key = new URL(request.url).pathname.slice(1);
await env.ASSETS.put(key, request.body);
return Response.json({ ok: true, key });
},
} satisfies ExportedHandler<Env>;
No estás inventando un cliente HTTP con tokens hardcodeados. Estás usando una capacidad configurada para ese Worker en ese ambiente.
Bindings como herramienta de diseño
Pregunta útil:
¿Qué capacidades necesita este Worker?
| App | Capacidades típicas |
|---|---|
| API de imágenes | R2 + Queue (thumbnails) + D1 (metadata) |
| Chat | Durable Object (sala) + Queue (analytics async) |
| Feature de IA | AI Gateway + R2 (resultados) + Queue (jobs largos) |
Si no puedes listar los bindings, probablemente hay arquitectura escondida.
Antipatrón: demasiados bindings en un solo Worker
API Worker:
- USERS_DB
- EMAIL_QUEUE
- IMAGE_BUCKET
- CRM_SECRET
- ANALYTICS_QUEUE
- CHAT_ROOM
- AI_GATEWAY
- BILLING_SERVICE
No siempre está mal. Pero pregunta:
¿Sigue siendo una responsabilidad clara?
Si no, separa. Un binding por recurso no justifica un god-Worker.
Ambientes: el binding mismo, el recurso no
El nombre en código puede ser EMAIL_QUEUE en todos lados. El recurso real debe cambiar por ambiente:
EMAIL_QUEUE → cola de prod
EMAIL_QUEUE → cola de staging
EMAIL_QUEUE → cola de preview
Tu staging no debería escribir en la cola de producción por accidente. Preview no debería tocar el bucket real de clientes.
Cómo nombrarlos
Buenos:
RECEIPT_QUEUE
PRODUCT_IMAGES
USER_COUNTERS
AI_GATEWAY
Flojos:
DATA
THING
BUCKET2
PROD_STUFF
El nombre del binding es documentación operativa. Trátalo como tal.
Checklist antes de publicar
- Cada binding tiene un nombre claro.
- Dev / staging / prod apuntan a recursos correctos.
- Los secrets no están hardcodeados.
- El Worker maneja fallos del recurso.
- Los logs dicen qué dependencia falló.
- El Worker no mezcla responsabilidades a lo bestia.
- El tipo
Envestá actualizado.
La frase para recordar
binding = permiso + API disponible en env
Y el loop mental:
fetch() recibe el request
env trae las capacidades configuradas
los bindings muestran qué recursos usa el Worker
Serie Cloudflare para builders: Workers · Bindings · Durable Objects · Queues
Docs: Bindings · Wrangler config · Environments · Queues · R2 desde Workers