El deploy salió verde y el sitio mentía sobre tus fotos
En pocas palabras: Un deploy exitoso en Vercel no garantiza que el sitio cumpla lo que promete: un desarrollador bajó la retención de fotos de 30 a 7 días, pero la variable PHOTO_RETENTION_DAYS seguía en 30 y ?? solo aplica el default si falta. El sitio dijo algo falso unos diez minutos.
Con las variables de entorno de Vercel, un deploy exitoso no prueba que la app cumpla lo que dice su página. En un post del 13/10/2026, un desarrollador contó que pasó la retención de fotos de 30 a 7 días: el HTML decía 7 y la API seguía en 30.
Una variable de entorno es un valor de configuración que vive fuera del código y que el servidor lee al arrancar, por ejemplo process.env.PHOTO_RETENTION_DAYS en Node.js. En Vercel se cargan por proyecto y por entorno (Production, Preview, Development). Sirven para claves y parámetros que cambian sin tocar el código, y por eso mismo pueden contradecirlo sin que nadie lo note.
En este artículo:
- En 30 segundos
- ¿Por qué el operador ?? no usa el valor por defecto si la variable de entorno ya existe?
- ¿Qué pasa con las variables de entorno de Vercel cuando cambiás el código pero no el panel?
- ¿Cómo ver qué valor está usando realmente tu servidor?
- ¿Cómo evitar que una configuración contradiga lo que le prometés al usuario?
- ¿Cómo testear que la política de privacidad coincide con el código?
- ¿Qué no cubren estos tests? Límites y pendientes
- ¿Qué está confirmado y qué no?
- ¿Cómo verificar este problema en tu proyecto?
- Errores comunes con variables de entorno
- Preguntas Frecuentes
- Conclusión
- Fuentes
En 30 segundos
- El deploy salió exitoso, pero la API devolvía 30 días de retención de fotos y la página de privacidad decía 7.
- La causa fue
Number(process.env.PHOTO_RETENTION_DAYS ?? 7): la variable existía con valor 30 y??solo usa el default si la variable falta. - Según el autor, el sitio dijo algo falso durante unos diez minutos, sin ningún síntoma visible.
- Su arreglo: el plazo prometido es un techo (
PHOTO_TTL_DAYS_MAX = 7) y el endpoint de salud imprime el valor efectivo y el configurado. - Es el relato de un solo desarrollador sobre su producto (zombieai.info), sin verificación independiente.
¿Por qué el operador ?? no usa el valor por defecto si la variable de entorno ya existe?
El operador ?? de JavaScript devuelve el valor de la derecha solo cuando el de la izquierda es null o undefined. Si la variable de entorno existe, aunque guarde un número viejo, gana ella y el default nunca se evalúa.
Según el post del autor en dev.to, él cambió una línea: borrar las fotos subidas a los 7 días en vez de 30. Vercel reportó el deploy como exitoso. La página de privacidad es HTML estático, así que el número que lee el visitante viaja con el commit y decía 7. La API decía 30, porque el autor había definido esa variable cuando la app salió a producción y se olvidó de que existía.
Código nuevo, texto nuevo, comportamiento viejo.
Subís el cambio, el deploy sale verde, abrís la página y ves el texto nuevo. Nadie toca el panel y la variable vieja sigue ahí con su 30. Te enterás recién cuando alguien pregunta o cuando mirás un JSON por otra razón, que fue exactamente lo que le pasó al autor. Durante unos diez minutos el sitio le dijo a cualquiera algo que no era cierto. El autor lo resume con “Nothing looked wrong” (nada parecía andar mal). Esa es la parte incómoda: ni error, ni log rojo, ni alerta.
Vercel y JavaScript hicieron lo que tenían que hacer. Lo que falló es que tres lugares (código, configuración y texto) decían cosas distintas y nada los comparaba. Complementá con publicar un proyecto React con Vite.
¿Qué pasa con las variables de entorno de Vercel cuando cambiás el código pero no el panel?

Nada: el código viaja con el commit y las variables viven aparte, en la configuración del proyecto. Un deploy “exitoso” informa que el build terminó y la versión quedó publicada; no compara tus textos con tu configuración.
El camino habitual para cargarlas, como referencia general (el post no entra en estos pasos):
- Entrá al proyecto en Vercel. Las variables están en Settings, sección Environment Variables.
- Cargá nombre y valor. Elegí a qué entornos aplican: Production, Preview, Development.
- Redeployá. Como regla general, un cambio de valor llega a los deploys nuevos; confirmalo en la documentación de Vercel.
Si tu app corre en un VPS o un hosting tradicional, como los de donweb.com, el archivo .env cumple el mismo rol y el riesgo es idéntico.
¿Cómo ver qué valor está usando realmente tu servidor?
Hacé que tu endpoint de salud imprima dos números: el valor efectivo que va a aplicar el servidor y el valor que alguien configuró. Con una sola request sabés si el sitio guarda datos más tiempo del que promete, sin abrir ningún dashboard.
{
"ok": true,
...
"photoRetentionDays": 7,
"photoRetentionSetting": 30
}El autor lo descubrió de casualidad: una hora antes había sumado un campo al endpoint y quería ver cómo se renderizaba. El dashboard le habría mostrado 30 y él habría seguido creyéndole a la página (spoiler: el panel no iba a avisarle nada).
Una precaución mía, no del autor: publicá en ese endpoint solo números como plazos o límites, nunca claves ni tokens. En poner tu sitio online gratis en Vercel profundizamos sobre esto.
¿Cómo evitar que una configuración contradiga lo que le prometés al usuario?
Tratá la cifra prometida como techo y no como default. Un default se puede pisar hacia arriba o hacia abajo; una promesa solo admite cumplirse antes de lo dicho. Así la variable puede acortar un plazo, nunca alargarlo.
const PHOTO_TTL_DAYS_MAX = 7;
const setting = positiveInteger('PHOTO_RETENTION_DAYS', PHOTO_TTL_DAYS_MAX, env);
const days = Math.min(setting, PHOTO_TTL_DAYS_MAX);Con Math.min, la variable olvidada con 30 queda inofensiva, y la próxima que alguien setee por error también. El criterio sirve para cualquier número que un cliente use para decidir: retención, precio, cantidad de reintentos, vida de un link. Si algún día querés alargar el plazo de verdad, tocás código y texto en el mismo commit.
¿Cómo testear que la política de privacidad coincide con el código?
Escribí tests que lean el texto de la página y lo comparen con el número que aplica el código. El autor sumó cuatro chequeos al build, según su post:
- La página de privacidad contiene “currently 7 days”.
- La FAQ contiene “deleted within 7 days”.
- El código contiene
PHOTO_TTL_DAYS_MAX = 7. - Una variable en 30 se recorta: la app arranca con
PHOTO_RETENTION_DAYS=30y el endpoint devuelve 7.
El último chequeo prueba comportamiento, no aritmética. Y todos comparan contra el texto de la copy, no contra la constante de al lado, que era justo lo que coincidía “por suerte”.
Hay un gesto que me gustó: el autor volvió la copy a “30 days” a propósito para ver el gate en rojo y con exit code distinto de cero, porque no confía en un chequeo que nunca vio fallar. Es el paso que conviene no saltearse.
¿Qué no cubren estos tests? Límites y pendientes
Los tests cubren las reglas del propio proyecto, no el comportamiento del proveedor ni lo que nadie pensó en medir. El autor lo reconoce con tres ejemplos de su mismo código: Lo explicamos a fondo en comparar Vercel con AWS Amplify.
- Un fake local no prueba los nombres de campo del proveedor. El SDK devuelve
data.orderMetadata, el código leíadata.metadatay el stand-in también. El gate estaba verde con el flujo real roto. Hacen falta los tipos publicados y una request real. - Los videos no se borran. La limpieza solo recorre fotos. Los videos se descargan a storage propio (tope de 128 MB, unos 7,4 MB por clip) y la política dice que quedan “mientras la cuenta esté activa”. No miente, pero el almacenamiento crece sin límite. Quedó como ítem abierto.
- El reembolso automático se prueba sin proveedor de pagos. El test entrega el mismo evento ocho veces y espera un solo grant, con el claim atado al id de entrega y al id de orden. Eso sí, vale la salvedad del primer punto.
Lo de los videos es lo más honesto del post: el autor admite que hizo una promesa por no pensarla.
¿Qué está confirmado y qué no?
Confirmado, según el relato del autor: el cambio de 30 a 7 días, la página con 7 y la API con 30, la causa en el operador ??, los cuatro chequeos y los pendientes de videos.
Sin confirmar: los diez minutos son su estimación y no hay verificación independiente. El post tampoco dice si en ese lapso se conservó alguna foto más allá de los 7 días, ni cuánta gente leyó la página. Este artículo se basa solo en ese texto.
¿Cómo verificar este problema en tu proyecto?
Pedile a tu servidor el número que figura en tu texto y compará. Lo que sigue es una propuesta editorial de esta redacción: no es un procedimiento del autor ni algo que hayamos probado.
- Listá los números de tu copy que un cliente pueda usar para decidir: plazos, precios, reintentos.
- Exponé el valor efectivo de cada uno en el endpoint de salud.
- Arrancá la app en CI con una variable hostil, por ejemplo un valor mayor al prometido, y verificá que el endpoint devuelva el número del texto.
- Repetí la comparación contra producción después de cada deploy.
Con eso decidís si cada variable es un default o un techo. Lo que el post no permite concluir es qué tan frecuente es este problema en Vercel ni cuánto impacto tuvo en este caso. Para más detalles técnicos, mirá configurar tu dominio propio con DNS y SSL.
Si querés profundizar en esto, tenemos un artículo sobre un deploy exitoso pero comportamiento roto y cómo evitarlo.
Errores comunes con variables de entorno
- Creer que el default es una garantía. Con
??o||cualquier variable vieja lo pisa. Corrección: techo conMath.min. - Dar por bueno un deploy “exitoso”. Solo dice que el build y la publicación terminaron. Corrección: leer el valor efectivo en el endpoint.
- Testear solo el código. Los tests del autor pasaban porque el código era correcto; el texto estaba mal. Corrección: asertar contra la copy.
- Ignorar la variable vacía. Un string vacío no es
nullniundefined, así que??no cae al default, yNumber('')da 0. Corrección: validá que sea un entero positivo, como hace el autor conpositiveInteger(el post no muestra su código).
Preguntas Frecuentes
¿Por qué el deploy salió bien en Vercel pero la app se comporta distinto?
Porque un deploy exitoso solo informa que el build terminó y la versión quedó publicada. En el caso del post, el HTML nuevo decía 7 días, pero una variable de entorno vieja con valor 30 seguía mandando en la API.
¿Qué hace el operador ?? en JavaScript si la variable de entorno ya existe?
Usa el valor de la variable y descarta el default. El operador ?? solo recurre al valor de la derecha cuando el de la izquierda es null o undefined, es decir, cuando la variable falta.
¿Cómo ver qué valor de una variable de entorno está usando realmente mi servidor?
Agregá al endpoint de salud el valor efectivo y el configurado, como hizo el autor con photoRetentionDays y photoRetentionSetting. Una request alcanza y no depende de lo que muestre el panel.
¿Cómo testear que el texto de la política de privacidad coincide con el código?
Hacé que el build falle si el HTML no contiene la frase con el número que aplica el código, por ejemplo “currently 7 days”. Comparás contra el texto de la copy y no contra una constante, y ensayás el fallo cambiando el texto a propósito.
¿Se puede usar una variable de entorno para acortar un plazo pero nunca alargarlo?
Sí: definí el plazo prometido como constante en el código y aplicá Math.min(setting, MAX). La variable puede pedir borrar antes, pero nunca después de lo que dice tu política.
Conclusión
El caso es chico, pero la lección es general: cada número que un cliente pueda usar para decidir vive en varios lugares, y solo el texto público es una promesa. Con las variables de entorno de Vercel (o en cualquier otro hosting), conviene que ese número sea un techo en el código, que el servidor diga cuál aplica y que el build compare el texto con el comportamiento.
Lo que podés hacer hoy: elegí un número de tu copy, pedile a tu servidor qué cree que vale y fijate si coincide.






