vars: configuración en texto plano
Las variables de configuración de un Worker: el mapa `vars` de `wrangler.jsonc`, valores en texto plano que se versionan con el código, cómo aterrizan en el objeto `env`, y por qué solo deben contener lo no sensible.
Todo Worker acaba necesitando datos que cambian entre un despliegue y otro sin ser parte de la lógica: la URL de una API, el nombre del entorno, un umbral numérico, una bandera de funcionalidad. Cloudflare llama a esas piezas vars, y su promesa es simple y peligrosa a partes iguales: viven en texto plano dentro de tu manifiesto, versionadas junto al código, y llegan al Worker por el mismo objeto env que los secretos. Entender qué son —y sobre todo qué nunca deben ser— es el primer ladrillo de una configuración sana en el edge.
- Declarar variables de configuración con el mapa
varsenwrangler.jsonc. - Entender que su valor viaja en texto plano y se versiona con el código.
- Leerlas dentro del Worker a través del objeto
envcon tipos generados. - Distinguir con precisión qué valores son aptos para
varsy cuáles jamás.
El manifiesto declara la configuración
Un Worker no tiene un entorno de proceso ambiente como un servidor tradicional. No existe un process.env global del que colgar la configuración: en el edge, todo lo que el código necesita del exterior llega por un único canal, el objeto env, que el runtime entrega como segundo argumento del handler fetch. Las vars son la forma declarativa de poblar ese objeto con valores estáticos, escritos a mano en el manifiesto del Worker.
Ese manifiesto es wrangler.jsonc —o su equivalente wrangler.toml—, y vars es una clave de nivel superior: un mapa de nombres a valores.
{
"name": "tienda-api",
"main": "src/index.ts",
"compatibility_date": "2026-01-01",
"vars": {
"ENTORNO": "produccion",
"API_BASE": "https://api.tienda.example",
"NIVEL_LOG": "info",
"MAX_ITEMS": 50
}
}
Al ejecutar wrangler deploy, esos pares se suben como parte de la configuración del Worker y quedan disponibles en env en cada invocación. Los valores suelen ser cadenas, pero vars admite también JSON nativo —números, booleanos, objetos o arrays—, y el runtime te los entrega con esa misma forma. Dentro del código, leerlos es trivial:
export default {
async fetch(request, env, ctx) {
const base = env.API_BASE; // "https://api.tienda.example"
const limite = env.MAX_ITEMS; // 50, ya como numero
return new Response(`entorno: ${env.ENTORNO}`);
},
} satisfies ExportedHandler<Env>;
Conviene subrayar el contraste con un servidor clásico. Allí, process.env es un cajón que puede rellenarse desde mil sitios —el shell, un .env, el sistema de init, un orquestador— y cuyo contenido en ejecución cuesta auditar. En un Worker no hay tal cajón: env se construye a partir de lo que declaras de forma explícita en el manifiesto y en el almacén de secretos, ni una clave de más. Esa explicitud es una ganancia de claridad que no conviene desperdiciar metiendo en vars cosas que no deberían estar a la vista.
Hay además una consecuencia temporal que define su carácter: como las vars se fijan en el momento del despliegue, son estáticas durante toda la vida de esa versión del Worker. Cambiar una var exige un wrangler deploy nuevo, que publica una versión nueva y deja la anterior disponible para un rollback. Eso es deseable —tu configuración queda atada a una versión concreta del código, reproducible y reversible—, pero implica que vars no sirve para valores que deban cambiar en caliente sin redeployar; para eso existe un almacén como KV.
Un matiz operativo lo confirma: si cambias una sola var y vuelves a desplegar, Cloudflare publica una versión nueva y entera del Worker, no un parche de esa variable. Encaja con el modelo de versiones inmutables —cada despliegue es un artefacto identificable y reversible— y explica por qué vars sirve para configuración que cambia al ritmo del código, no al ritmo del tráfico.
Por eso, cuando alguien propone usar una var como interruptor que se cambia muchas veces al día, la respuesta correcta suele ser otra pieza: una bandera en KV, leída en runtime, evita redeployar por cada ajuste y deja vars para lo que de verdad acompaña a una versión concreta del código.
Texto plano significa texto plano
Aquí está la propiedad que define a una var y que debes grabar antes que ninguna otra: su valor no está cifrado en ningún punto de su vida. Está escrito en wrangler.jsonc, un archivo que confirmas y subes a tu repositorio. Aparece tal cual en el panel de Cloudflare, legible para cualquier miembro de la cuenta. Se imprime en la salida de wrangler deploy y puede acabar en los registros de tu CI. Una var, en la práctica, es información pública dentro de tu equipo y semipública en tu tooling.
De ahí se deriva la única regla que importa: si la filtración de ese valor causara algún daño —por pequeño que sea—, ese valor no es una var. El nombre de tu entorno, la URL pública de una API, el tamaño de un lote: perfectos. Una clave de API, la contraseña de una base de datos, un token de firma: jamás. Para eso existen los secretos, que son la lección siguiente y viven en un almacén cifrado precisamente porque vars no lo es.
Es tentador pensar en vars como variables de entorno al estilo de un servidor y colar ahí una credencial de desarrollo por comodidad. No lo hagas ni una vez. A diferencia de un .env local que se queda en tu máquina, una var se versiona: en cuanto la confirmas, su valor queda en el historial de git para siempre, replicado en cada clon del repositorio y en cada copia de seguridad. Borrarla del último commit no la borra del pasado. El daño de un secreto en vars no es que alguien lo vea hoy, sino que ya no puedes garantizar que nadie lo vio nunca.
Merece la pena enumerar dónde queda expuesta exactamente una var, porque la lista sorprende: en el archivo del repositorio y todo su historial; en el panel del navegador, para cualquiera con acceso de lectura a la cuenta; en la configuración de la versión desplegada, que Wrangler puede volcar; y, con frecuencia, en los registros de la tubería de CI que ejecutó el despliegue. Cuatro superficies, ninguna cifrada. Cuando decides que un dato es una var, estás aceptando esas cuatro exposiciones a la vez.
Este no es un consejo paranoico sino la lección que muchos equipos aprenden por las malas: la mayoría de las credenciales filtradas en la industria no salieron por un ataque ingenioso, sino por un valor sensible confirmado en un repositorio que un día se hizo público o se compartió con quien no debía. Tratar vars como una vitrina, no como un cajón, es lo que evita engrosar esa estadística.
En local existe un orden de precedencia que conviene conocer: los valores de .dev.vars y los pasados por la línea de comandos a wrangler dev prevalecen sobre las vars del manifiesto. Así puedes desarrollar apuntando a un endpoint de pruebas sin editar wrangler.jsonc. En producción no hay esa capa local: manda lo declarado en el manifiesto y en el almacén de secretos, y punto. Tener claro qué fuente gana en cada máquina evita el desconcierto de ver un valor en dev y otro distinto tras deploy.
Nombres, tipos y el override local
Como vars y los secretos pueblan el mismo objeto env, comparten un único espacio de nombres: un binding no puede llamarse igual que otro sin que uno ensombrezca al otro. Mantén los nombres distintos y en mayúsculas por convención, para que al leer env.ALGO sea evidente de dónde sale.
Para no programar a ciegas contra env, Wrangler genera los tipos por ti. El comando wrangler types produce un worker-configuration.d.ts con una interfaz Env que refleja exactamente tus vars, secretos y bindings declarados, de modo que el editor te autocompleta env.API_BASE y te avisa si escribes un nombre que no existe. En un proyecto sano, ese archivo se regenera en cada cambio de configuración y el compilador se vuelve tu primera línea de defensa contra un env.TYPO silencioso.
En desarrollo, además, puedes sobreescribir cualquier var sin tocar el manifiesto: un archivo .dev.vars en la raíz del proyecto —ignorado por git— alimenta a wrangler dev con valores locales. Es el sitio natural para apuntar API_BASE a un servidor de pruebas mientras trabajas, sin arriesgarte a confirmar ese cambio.
Una advertencia de diseño cierra el apartado: que vars acepte JSON no es una invitación a meter ahí estructuras grandes. Una var es más útil cuanto más atómica —un valor, un propósito—. Si te descubres serializando un objeto de configuración complejo en una var, esa complejidad probablemente pertenece al código, a un asset versionado, o a un almacén con estructura propia. Reserva vars para las pocas palancas que de verdad cambian entre despliegues.
Conviene recordar, además, que las vars no son secretas ni siquiera frente a tu propio equipo ampliado: colaboradores, contratistas y cualquier integración con acceso de lectura a la cuenta las ven. Si un valor solo debería conocerlo un subconjunto de tu equipo, ya no es una var aunque no sea técnicamente una credencial; la visibilidad, y no solo el daño potencial, es un criterio válido para mandar algo al almacén cifrado.
Trata la lista de vars como la declaración pública de las dependencias de configuración de tu Worker. Nombres claros y en mayúsculas —API_BASE, NIVEL_LOG, MAX_ITEMS— convierten el manifiesto en documentación: quien lo lee sabe, sin abrir el código, qué palancas gobiernan el comportamiento. Evita nombres genéricos como CONFIG o VALOR que no dicen nada, y agrupa por prefijo cuando tenga sentido con familias como STRIPE_ o DB_, para que la relación entre variables salte a la vista.
Un último apunte sobre tipos: lo generado refleja lo que declaraste, no lo que de verdad llega en runtime. Si despliegas con una var mal escrita o ausente, el tipo dirá que existe y el código accederá a un valor indefinido sin quejarse en compilación. Los tipos te protegen de errar el nombre, no de olvidar el valor; para eso está probar el Worker desplegado, no solo compilarlo.
El viaje completo de una var, desde que la escribes hasta que la lees, cabe en un diagrama:
flowchart LR CFG[wrangler jsonc mapa vars] --> DEP[wrangler deploy] DEP --> META[config del worker en texto plano] META --> RT[runtime del edge] RT --> ENV[objeto env en cada peticion] ENV --> CODE[el codigo lee env] style CFG fill:#89b4fa,color:#11111b style ENV fill:#a6e3a1,color:#11111b style CODE fill:#f9e2af,color:#11111b
Elegir bien: var, secreto, binding o KV
Antes de escribir cualquier dato de configuración, conviene ubicarlo en el mapa de las cuatro piezas que pueblan o rodean a env. Confundirlas es la causa raíz de casi todos los errores de este nivel: meter un secreto en una var, o un dato dinámico donde solo caben valores estáticos.
Cada una de estas cuatro piezas existe porque resuelve un problema que las otras no: vars da transparencia, el secreto da confidencialidad, el binding da acceso gobernado a un recurso, y el almacén da dinamismo y volumen. Meter un dato en la pieza equivocada no es solo desordenado: sacrifica justo la propiedad que ese dato necesitaba.
var
Configuración no sensible en texto plano, versionada con el código. Nombre de entorno, URL pública, umbrales y flags. Estática hasta el próximo deploy.
secreto
Un valor sensible cifrado y fuera del repositorio. Claves, tokens, contraseñas. Se lee igual que una var, pero vive en el almacén cifrado.
binding
No un valor escalar, sino una capacidad: acceso a D1, R2, KV u otro Worker. Llega por env como un objeto con métodos, no como una cadena.
KV u otro almacén
Datos que cambian en caliente o son demasiado grandes para el manifiesto. Se leen en runtime, no se fijan en el deploy.
La regla de decisión es una cascada de preguntas: ¿es sensible? Entonces es un secreto. ¿Es una conexión a un recurso? Entonces es un binding. ¿Cambia sin redeployar o es voluminoso? Entonces vive en un almacén. Solo lo que sobrevive a las tres preguntas —no sensible, escalar, estático— merece ser una var. Esa disciplina mantiene tu manifiesto legible y tu superficie de exposición mínima.
Aunque ambos llegan por env, no los confundas. Una var es un valor escalar que puedes imprimir; un binding es un objeto con métodos que representa una capacidad —hablar con D1, con R2, con otro Worker—. Cuando en el nivel de bindings viste que un Worker accede a los recursos por capacidades y no por cadenas de conexión, vars quedó como el hueco humilde para los pocos datos que la lógica necesita saber de memoria, no para las conexiones, que siempre viajan como bindings.
Hay una virtud profunda en que las vars vivan en texto plano dentro del manifiesto, y conviene verla antes de despreciarlas por inseguras. Una var es configuración declarada: viaja con el código, se revisa en el mismo pull request, se versiona con la misma historia y se despliega de forma reproducible. Cualquiera que abra wrangler.jsonc entiende de un vistazo de qué palancas depende el Worker y con qué valores corre en producción. Esa transparencia es exactamente lo que la hace inservible para un secreto y valiosísima para todo lo demás. El error del principiante es tratar la seguridad como una propiedad binaria del mecanismo —las vars inseguras, los secretos seguros— cuando la verdad es que cada mecanismo codifica una intención distinta: vars dice que esto es parte del contrato público de mi Worker y quiero que se vea, y el secreto dice que esto no debe verse jamás. Elegir mal no es un fallo técnico sino una confesión de que no tienes claro qué información es sensible. La disciplina que se te pide aquí es clasificar cada dato antes de escribirlo: si su lugar natural es un diff que revisará tu equipo, es una var; si su lugar natural es una caja fuerte de la que solo sale hacia el runtime, es un secreto. Esa clasificación, hecha con honestidad, es la mitad de la seguridad de tu configuración.
- Crea un Worker con tres
varsenwrangler.jsonc: un nombre de entorno, una URL base y un límite numérico. Despliega y compruébalas devolviéndolas desdeenven la respuesta. - Ejecuta
wrangler typesy confirma que tu editor autocompleta y tipa correctamenteenv.API_BASEy el límite como número. - Añade un
.dev.varsque sobreescriba la URL base para local, verifica quewrangler devusa ese valor, y comprueba que el archivo está en.gitignore. - Toma cinco datos de un proyecto tuyo y pásalos por la cascada de decisión —sensible, conexión, dinámico— para clasificar cada uno como var, secreto, binding o almacén. Justifica cada veredicto en una frase.
- Abre el panel de Cloudflare tras desplegar y localiza tus
vars: verlas ahí, en claro y legibles, es la mejor vacuna contra la tentación de guardar un secreto en ellas.