Variables de entorno: producción, preview y local
En qué se diferencian las variables de entorno de producción, preview y local en Vercel y Netlify, qué valor va en cada una y los errores que filtran claves.
Read in English →
Las variables de entorno de producción, de preview y locales son tres listas separadas: producción es lo que usa tu sitio en vivo, preview es lo que usan los builds de ramas y pull requests, y local vive en un archivo en tu computadora. Una variable cargada en una lista no existe en las otras, un cambio solo se aplica en el siguiente despliegue, y todo lo que lleva un prefijo público como VITE_ o NEXT_PUBLIC_ queda grabado en el código del navegador al compilar.
En esta guía te explicamos cómo funcionan los tres entornos en Vercel y Netlify, qué valores van en cada uno en una app típica con Supabase y Stripe, y cómo comprobar qué está usando de verdad un despliegue.
¿En qué se diferencian los tres entornos?
| Producción | Preview | Local | |
|---|---|---|---|
| Lo usa | Tu dominio en vivo | Los despliegues de ramas y pull requests | Tu computadora cuando corres el servidor de desarrollo |
| Nombre en Vercel | Production | Preview (todas las ramas o una en particular) | Development, se descarga con vercel env pull |
| Nombre en Netlify | Production | Deploy Previews y Branch deploys | Local development (Netlify CLI) |
| Dónde se guarda | Panel del hosting | Panel del hosting | Un archivo como .env.local que nunca se sube al repositorio |
| ¿Debe ver datos reales de clientes? | Sí | No | No |
Vercel también admite entornos personalizados, y las dos plataformas permiten sobrescribir un valor de preview para una rama concreta. En Vercel, el valor específico de una rama reemplaza al valor general de preview con el mismo nombre, así que solo agregas los que cambian.
¿Qué valor va en cada entorno?
En una configuración común (frontend en Vercel o Netlify, Supabase para datos e inicio de sesión, Stripe para pagos), un reparto sensato es este:
| Variable | Producción | Preview | Local |
|---|---|---|---|
VITE_SUPABASE_URL / NEXT_PUBLIC_SUPABASE_URL | Proyecto de producción | Proyecto de pruebas | Pruebas o una instancia local |
| Clave anon o publishable de Supabase | La de producción | La de pruebas | La de pruebas |
| Clave service role o secret de Supabase | Solo en funciones del servidor | La de pruebas, solo servidor | La de pruebas, solo servidor |
| Clave secreta de Stripe | Modo live (sk_live_…) | Modo de prueba (sk_test_…) | Modo de prueba |
| Secreto de firma del webhook de Stripe | El del endpoint live | El del endpoint de prueba | El que da la Stripe CLI |
| URL del sitio para correos y redirecciones | https://tuapp.com | La URL del preview o el dominio de pruebas | http://localhost:5173 o similar |
La idea central: los builds de preview nunca deberían tocar datos de producción ni cobrar tarjetas reales. Si todavía no tienes una base de datos de pruebas, la guía de entorno de pruebas (staging) muestra la forma más barata de sumarla.
¿Qué variables se ven en el navegador?
Los frameworks de frontend solo exponen las variables con prefijo público. En Vite es VITE_; en Next.js, NEXT_PUBLIC_. Se reemplazan por su valor literal al compilar la app, así que cualquiera puede leerlas en las herramientas de desarrollo del navegador. La documentación de Vite es clara: las variables VITE_ no deben contener información sensible como claves de API.
De ahí sale una regla simple:
- Pueden ser públicas: la URL de Supabase, la clave anon o publishable de Supabase (siempre que Row Level Security proteja tus tablas), la clave publicable de Stripe, los ID de analítica.
- Nunca públicas: la clave service role o secret de Supabase, las claves secretas de Stripe, las claves de OpenAI u otras APIs de IA, los secretos de webhooks, las contraseñas de bases de datos.
Si una herramienta de IA escribió VITE_OPENAI_API_KEY o NEXT_PUBLIC_STRIPE_SECRET_KEY, esa clave ya está expuesta en tu sitio en vivo. Mueve esa llamada a una función del servidor y rota la clave en el proveedor. Vercel permite marcar variables como Secret, que quedan de solo escritura después de guardarlas; eso protege el valor en el panel, pero no evita que tu código lo exponga con un prefijo público.
¿Por qué no se aplicó mi cambio?
Cuatro razones explican casi toda la confusión:
- No hubo despliegue nuevo. Vercel aclara que los cambios en variables de entorno solo aplican a despliegues nuevos. Cambiar el valor y recargar la página no hace nada; vuelve a desplegar.
- Entorno equivocado. Agregaste la variable en Production pero estás probando un preview, o al revés.
- Grabado al compilar. Las variables públicas se congelan dentro del bundle durante el build. Aunque la app renderice en el servidor, esas salen del build y no del panel en el momento de cada petición.
- Errores invisibles. Un espacio al final, comillas pegadas dentro del valor, o
SUPABASE_URLen el panel mientras el código leeVITE_SUPABASE_URL.
¿Cómo veo qué está usando realmente un despliegue?
- En Vercel, la variable de sistema
VERCEL_ENVvaleproduction,previewodevelopment, así que tu código sabe dónde está corriendo. Puedes mostrarla en el pie de página de los builds que no son de producción o registrarla en una función del servidor. - En el navegador, abre la pestaña Network y mira a qué URL de proyecto de Supabase van las peticiones. Eso te dice al instante si un preview está hablando con producción.
- Desde la CLI,
vercel env lslista lo configurado en cada entorno yvercel env pullescribe tus variables de Development en un archivo.envlocal. - Con los secretos, nunca imprimas el valor. Registra si existe (
Boolean(process.env.STRIPE_SECRET_KEY)) y, si hace falta, el prefijo, comosk_testfrente ask_live.
¿Cómo se ve una configuración local ordenada?
- Sube al repositorio un
.env.examplecon todos los nombres de variables y ningún valor real. - Guarda los valores reales en
.env.local, que las plantillas de Vite y Next.js ignoran en Git por defecto. Igual revisa tu.gitignore. - Apunta el entorno local a pruebas o a una instancia local de Supabase, nunca a producción.
- Si alguna vez subiste a GitHub un
.envcon claves reales, borrarlo no alcanza. Las claves quedan en el historial, así que rótalas.
Respuestas rápidas
¿Tengo que volver a desplegar después de cambiar una variable? Sí. Los despliegues existentes conservan los valores con los que se compilaron.
¿Un preview puede usar las variables de producción? Técnicamente sí, pero entonces las ramas de prueba escriben en datos reales y pueden cobrar tarjetas reales. Dale a los previews sus propios valores.
¿La clave anon de Supabase es secreta? No, está pensada para ser pública, pero solo Row Level Security la hace segura. Lo explicamos en la guía sobre si la clave anon de Supabase es segura.
¿Qué tamaño pueden tener las variables en Vercel? El total por despliegue es de 64 KB sumando todas, con un límite menor por variable en las funciones edge.
¿Quieres tus entornos bien separados?
Separar producción de todo lo demás es de las formas más baratas de evitar un mal día. Nuestros planes de mantenimiento de software incluyen configurar entornos y rotar claves filtradas, y el checklist de seguridad para apps hechas con IA cubre lo que conviene revisar después. También puedes pasar tu app por el chequeo gratuito para ver si algo sensible se ve desde afuera.


