Su app funciona en local y falla en el servidor. Revise estas 7 cosas
Por Oleksii Skurikhin · Delivery Manager
- Publicado el
- Actualizado el
- 14 min de lectura
7 comprobaciones tras el primer despliegue de una app con IA que funciona en su portátil: variables, tiempos de espera, CORS, webhooks, migraciones, secretos y DNS, con comandos, ejemplos y una hoja.
Puntos clave
- Un servidor puede diferir de su portátil en 7 puntos: variables de entorno (ajustes leídos fuera del código), tiempos de espera, CORS, webhooks, migraciones, secretos y DNS.
- El primer paso seguro es una copia nueva del proyecto, sin claves de producción, sin cambios en producción y con un límite de 60 minutos; anote lo que todavía no sabe.
- La comprobación de variables de entorno compara los nombres que lee su código con los definidos en el hosting; compare solo nombres, nunca valores secretos.
- Una clave en una variable NEXT_PUBLIC_ o VITE_ acaba en el código compilado, y una clave en un commit queda en el historial de git; GitHub aconseja primero revocarla o rotarla.
- La hoja de comprobación del despliegue tiene 7 líneas, cada una marcada como OK, DESCONOCIDO o CON FALLO, y termina con un recuento de las líneas que no están OK.
Ha creado una aplicación con una herramienta de IA y funciona en su portátil. Esta página es para el día en que tenga que funcionar en un servidor. Hay 7 puntos en los que un servidor puede diferir de un portátil, y cada uno tiene abajo una comprobación, algunas de ellas sobre una copia de su proyecto.
Los 7 puntos son las variables de entorno (ajustes que su aplicación lee desde fuera de su código), los límites de tiempo, CORS (la regla del navegador que decide qué sitios pueden llamar a su API), los webhooks (llamadas a su aplicación desde servicios como los de pagos), las migraciones de base de datos (cambios registrados en la estructura de la base de datos), los secretos y el dominio con sus registros DNS. Una hoja al final recoge lo que haya encontrado.
Necesita el código del proyecto en su ordenador, un terminal y un acceso a su hosting. Algunas comprobaciones requieren además accesos a su proveedor de pagos y a su proveedor de DNS.
¿Por dónde empiezo sin arriesgar la producción?
Haga la primera comprobación sobre una copia nueva del proyecto y no ponga en ella claves de producción. Mientras comprueba, no cambie nada en producción: no edite los ajustes del hosting, los registros DNS, la base de datos ni el panel de un proveedor. Pare a los 60 minutos y anote lo que todavía no sabe en la hoja del final de esta página.
Haga la copia con estos 2 comandos, ejecutados en una carpeta fuera de su copia de trabajo. Sustituya YOUR-REPO-URL por la dirección de su repositorio.
git clone YOUR-REPO-URL deploy-check
cd deploy-checkLea cada comando de esta página antes de ejecutarlo y omita cualquier paso que modifique algo.
¿Cuáles son las 7 diferencias entre un portátil y un servidor?
Las 7 diferencias son las variables de entorno, los tiempos de espera, CORS, los webhooks, las migraciones de base de datos, los secretos y el dominio con sus registros DNS.

| Diferencia | Dónde mirar | Primera comprobación |
|---|---|---|
| Variables de entorno | Código, ajustes del hosting | Compare los nombres en ambos |
| Tiempos de espera | Documentación y registros del hosting | Compare su acción más lenta con el límite del hosting |
| CORS | Consola del navegador, cabeceras de respuesta | Lea el error de la consola, envíe una solicitud preflight |
| Webhooks | Panel del proveedor | Confirme que cada endpoint es su dirección HTTPS en producción |
| Migraciones de base de datos | Registro de despliegue, carpeta de migraciones | Busque el paso que aplica las migraciones |
| Secretos | Nombres destinados al navegador, historial de git | Lea los nombres, liste los commits que tocan archivos env |
| Dominio y DNS | Registros del proveedor de DNS | Ejecute dig y lea después el TTL en la tabla del proveedor |
Nuestro artículo sobre los controles de seguridad por niveles sitúa estas siete comprobaciones, hechas sobre la aplicación en producción, en el nivel 3, junto con la revisión de 60 minutos y una alerta que llegue a un teléfono que alguien lea.
¿Cómo compruebo cada una de las 7 diferencias?
Cuando una sección enlaza una página de documentación, su explicación se basa en esa página. Otros proveedores pueden diferir, así que consulte el mismo punto para su propio hosting.
Los resultados de abajo proceden de nuestra ejecución del 29 de octubre de 2026: las comprobaciones de código, sobre un proyecto de demostración creado para la ocasión y no de un cliente; la de DNS, sobre nuestro propio dominio; y la solicitud preflight, sobre una API pública. El archivo .env.local del proyecto de demostración contenía una dirección localhost y una clave de prueba de Stripe, incluidas en un commit y retiradas del seguimiento de git.
1. Variables de entorno: ¿coinciden los nombres del hosting con los del código?
Una variable de entorno es un ajuste con nombre que su aplicación lee desde fuera de su código, como una dirección web o una clave.
Next.js carga las variables desde archivos .env* en process.env, y su plantilla inicial predeterminada añade todos los archivos .env a .gitignore. La misma página dice que casi nunca querrá hacer commit de estos archivos (documentación de Next.js: Environment Variables). Así que no dé por hecho que el hosting los tiene. Compruebe que cuenta con su propio ajuste para cada nombre.
Liste los nombres de variable que lee el código y los nombres definidos en los ajustes del hosting. Anote todo nombre que esté en la primera lista y no en la segunda. Compare solo los nombres, nunca los valores secretos. Ejecute esto en la copia y cambie los nombres de las carpetas para que coincidan con su proyecto.
grep -rhoE "(process\.env|import\.meta\.env)\.[A-Za-z0-9_]+" app src pages lib 2>/dev/null | sort -uNuestra demostración mostró seis nombres, y el hosting debe tener un ajuste para cada uno.
process.env.DATABASE_URL
process.env.NEXT_PUBLIC_API_URL
process.env.NEXT_PUBLIC_STRIPE_SECRET_KEY
process.env.OPENAI_API_KEY
process.env.STRIPE_SECRET_KEY
process.env.STRIPE_WEBHOOK_SECRETLa demostración no tiene carpeta src ni pages, y el comando omitió ambas sin dar error.
Después lea en el hosting el valor de cada variable de URL y compruebe que ninguna sigue apuntando a localhost. En el .env.local de la demostración, NEXT_PUBLIC_API_URL era http://localhost:3000, el tipo de valor que esta comprobación busca en el hosting.
Algunos valores se fijan cuando se compila el proyecto, así que un ajuste correcto puede no servir de nada. Next.js incrusta los valores de NEXT_PUBLIC_ en el bundle de JavaScript durante la compilación, y la aplicación ya compilada deja de responder a los cambios en ellos (documentación de Next.js: Environment Variables).
Vite empaqueta los valores de VITE_ en el código fuente durante la compilación (documentación de Vite: Env Variables and Modes). Vuelva a compilar después de cambiar cualquiera de los dos tipos en el hosting.
2. Tiempos de espera: ¿cuánto tiempo espera el hosting una respuesta?
Es posible que su hosting fije un límite de tiempo para cada solicitud. Lea ese límite en la documentación del propio hosting y no suponga ninguno.
Anote lo más lento que puede iniciar un usuario, como una llamada a la IA o una exportación, y el límite documentado de su hosting para ello. Después busque en los registros del hosting una entrada de tiempo de espera agotado de su última ejecución.
El error habitual es comparar el límite con la carga rápida de una página. Compárelo con la acción más lenta que anotó.
3. CORS: ¿permite la API el origen de su sitio en producción?
Los navegadores restringen las solicitudes que los scripts de una página envían a otro origen, salvo que la respuesta incluya las cabeceras CORS adecuadas (MDN: Cross-Origin Resource Sharing). Un origen es distinto si cambia el dominio, el esquema o el puerto, así que una dirección localhost y su dominio en producción son orígenes diferentes. Compruebe por separado el dominio raíz y www.
Primero confirme que el ajuste de orígenes permitidos de la API nombra el origen de su sitio en producción, no solo localhost. Después abra el sitio en producción en una ventana privada con la consola abierta y repita la acción que falla, pero únicamente si es de solo lectura, como cargar una página. No repita un formulario, un pago ni una exportación. MDN dice que la consola es el único lugar donde se pueden leer los detalles de un fallo de CORS.
Envíe a mano la solicitud preflight, la pregunta que el navegador hace a la API antes de la solicitud real. Sustituya las partes en mayúsculas por la dirección de su API y el origen de su sitio.
curl -i -X OPTIONS https://YOUR-API/PATH -H "Origin: https://YOUR-SITE" -H "Access-Control-Request-Method: POST"Busque una cabecera Access-Control-Allow-Origin cuyo valor sea exactamente igual al origen de su sitio. MDN califica OPTIONS de método seguro, es decir, que no puede usarse para cambiar el recurso.
Nuestra ejecución envió la misma solicitud a una dirección pública de la API de GitHub desde el origen inventado https://example.com, y respondió con un comodín.
HTTP/2 204
access-control-allow-origin: *Una API pública que admite cualquier origen responde con *. Si la solicitud incluye una credencial, como una cookie, MDN dice que el navegador bloquea el acceso a una respuesta que lleve Access-Control-Allow-Origin: *. Así que en su propia API indique sus orígenes exactamente, incluidos https y www.
4. Webhooks: ¿llama el proveedor a su dirección en producción?
Un webhook es una llamada de otro servicio a su aplicación, como la confirmación de un pago. La documentación de Stripe dice que los endpoints de webhook registrados deben ser URL HTTPS de acceso público (documentación de Stripe: Webhooks).
En el panel del proveedor, liste todos los endpoints registrados y confirme que cada uno usa su dirección HTTPS en producción, no una dirección temporal de las pruebas. Abra el registro de entregas, si el proveedor lo conserva, y cuente los fallos. Confirme que el secreto de firma guardado en su hosting pertenece a ese endpoint.
Stripe genera un secreto único para cada endpoint, y un secreto distinto para el uso de prueba y el uso en producción del mismo endpoint.
Una dirección correcta no es todo el trabajo. Entre otros puntos, la misma página de Stripe describe 3 cosas que hay que gestionar en el endpoint.
- Responda rápido. El endpoint debe devolver un código de estado correcto (2xx) antes de cualquier lógica compleja que pueda provocar un tiempo de espera agotado.
- Conserve el cuerpo sin procesar. Stripe exige el cuerpo sin procesar de la solicitud para verificar la firma, y cualquier manipulación de este hace que la verificación falle.
- Espere repeticiones. Un endpoint podría recibir ocasionalmente el mismo evento más de una vez, así que registre los ID de los eventos que ya ha procesado y omita los eventos ya registrados.
5. Migraciones de base de datos: ¿tiene la base de datos del servidor los últimos cambios?
Una migración es un cambio registrado y repetible en la estructura de una base de datos, como una tabla nueva o una columna nueva. Cada base de datos, en el portátil o en el servidor, necesita que se le aplique la migración. Busque en la documentación de su herramienta qué comando aplica las migraciones a la base de datos de un servidor.
Empiece en la copia. Estos 2 comandos buscan una carpeta de migraciones y un paso de migración en package.json.
ls migrations prisma/migrations 2>/dev/null
grep -n -i "migrat" package.jsonDespués responda a las preguntas. ¿Hay una carpeta de migraciones en el repositorio? ¿Muestra el último registro de despliegue un paso que aplica las migraciones?
Para saber qué ha aplicado producción, use un comando de estado de la documentación de su herramienta solo si su página dice que no cambia nada. Ejecútelo en el hosting, donde ya está la conexión de producción, nunca poniendo claves de producción en la copia. De lo contrario, escriba DESCONOCIDO para esta diferencia en la hoja.
La copia no puede mostrar qué migraciones ha aplicado producción, y una carpeta de migraciones en el repositorio solo muestra lo que contiene el proyecto.
6. Secretos: ¿hay una clave en los archivos del navegador o en git?
Busque 2 tipos de fuga: una clave en una variable que se envía al navegador y una clave que se incluyó en un commit de git. Next.js incrusta los valores de NEXT_PUBLIC_ en cualquier JavaScript que se envía al navegador (documentación de Next.js: Environment Variables). Vite dice que las variables VITE_ no deberían contener información sensible, como claves de API (documentación de Vite: Env Variables and Modes).
Lea el nombre de cada variable destinada al navegador en el código y en el hosting, y anote todo nombre que suene a clave, secreto o token. Después busque en el historial de git. Ejecute esto en la copia y cambie los nombres de las carpetas para que coincidan con su proyecto.
grep -rhoE "(NEXT_PUBLIC|VITE)_[A-Za-z0-9_]+" app src pages lib 2>/dev/null | sort -u
git log --all --full-history --oneline -- '*.env*'En nuestra demostración el primer comando mostró dos nombres.
NEXT_PUBLIC_API_URL
NEXT_PUBLIC_STRIPE_SECRET_KEYEl segundo nombre dice SECRET_KEY y está destinado al navegador, que es justo lo que esta comprobación busca.
El segundo comando sirve para listar los commits que tocaron un archivo env. Abra cada commit que muestre y compruebe que el archivo no contenía claves reales. Una lista vacía significa que este comando no encontró ninguno, no que no exista ninguno. Nuestra ejecución mostró los dos commits.
798cd5f stop tracking env
353919a first versionLa clave está en el más antiguo, el commit que añadió el archivo. En nuestros repositorios de prueba, añadir .env a .gitignore después de un commit no hizo que git dejara de seguirlo, git rm --cached dejó el archivo en el disco y la clave permaneció en el historial. La revisión de solo lectura de 60 minutos profundiza en los secretos, el acceso a los datos, los inicios de sesión, las copias de seguridad y los límites de gasto.
Quitar la clave de git no es el primer paso. La guía de GitHub dice que, cuando el dato sensible es un secreto, el primer paso es revocarlo o rotarlo (documentación de GitHub: Removing sensitive data from a repository).
En el Mac que usamos, el grep del shell era un envoltorio de otra herramienta que omitía los archivos ocultos como .env, mientras que /usr/bin/grep, el grep del sistema, sí los mostraba. Si una búsqueda de claves no encuentra un archivo .env que usted sabe que existe, ejecute /usr/bin/grep con la ruta completa.
7. Dominio y DNS: ¿apunta el nombre adonde espera el hosting?
Un registro DNS asocia un nombre con un servidor. Su TTL (tiempo de vida) es el tiempo que el registro permanece en caché.
Pregunte al DNS por el dominio raíz y por www, y lea después el TTL de cada registro en la tabla de registros de su proveedor de DNS. Ejecute estos 2 comandos en un terminal.
dig +short YOUR-DOMAIN
dig +short www.YOUR-DOMAINEl comando dig pregunta a un servidor de nombres por los registros de un nombre y muestra las respuestas. Para nuestro propio dominio mostró esto.
$ dig +short cmlteam.com
209.182.238.60
$ dig +short www.cmlteam.com
cmlteam.com.
209.182.238.60El dominio raíz responde directamente con una dirección. El nombre www responde primero con otro nombre, cmlteam.com., porque es un alias (un registro CNAME) del dominio raíz. Compare cada respuesta con lo que le pide establecer la página de dominios de su hosting. Si su sitio usa los dos nombres, compruebe ambos.
Un TTL largo puede ralentizar un cambio. Cuando llegue a planificar uno, baje primero el TTL y espere a que expire el TTL antiguo (esto edita un registro DNS, así que no forma parte de la comprobación). Cambie el dominio en último lugar, cuando las variables de entorno, los orígenes CORS y las URL de los webhooks ya nombren el dominio final.
¿Cuáles son los límites de estas comprobaciones?
Las afirmaciones sobre Next.js, Vite, MDN, Stripe y GitHub proceden de las páginas de documentación enumeradas en Fuentes, leídas el 10 de octubre de 2026; no se anotaron las versiones de Next.js, de Vite ni de la API de Stripe. Las definiciones sencillas, las comprobaciones, los consejos, la tabla, la hoja y el límite de tiempo son nuestros, y los resultados proceden de nuestra ejecución del 29 de octubre.
- Esta página no tiene datos sobre con qué frecuencia ocurre cada diferencia en las aplicaciones creadas con IA, así que el orden de las 7 es un orden de lectura, no una clasificación.
- Otros proveedores pueden diferir. Los webhooks se muestran con Stripe, y las variables de entorno con Next.js y Vite. Esta página no enlaza documentación sobre límites de tiempo, migraciones ni registros DNS, así que lea las páginas de su propio hosting y de sus herramientas para esos puntos, y vuelva a leer cualquier página antes de basarse en un comando o en una cifra.
- Los resultados de código de arriba proceden de nuestro proyecto de demostración, ejecutado el 29 de octubre de 2026 en macOS con git 2.50.1; los resultados de dig y de la solicitud preflight son del mismo día. Su proyecto y sus herramientas pueden mostrar otras líneas.
- La comprobación de secretos cubre los nombres destinados al navegador y los archivos env del historial de git, no los archivos del servidor, así que un OK en ese punto no es prueba de que no haya ninguna fuga.
¿Qué puedo comprobar hoy?
Dedique 60 minutos a las comprobaciones y rellene la hoja de comprobación del despliegue de abajo, con una línea por diferencia y cada una terminada en OK, DESCONOCIDO o CON FALLO. El resultado visible son 7 líneas y un número: cuántas no están OK.
¿Qué aspecto tiene la hoja de comprobación del despliegue?
Pegue una copia de la hoja por proyecto en un archivo de texto o en un documento.
HOJA DE COMPROBACIÓN DEL DESPLIEGUE (trabaje sobre una copia, no cambie nada en producción, pare a los 60 minutos)
PROYECTO:
URL EN PRODUCCIÓN:
HOSTING:
REVISADO POR Y FECHA:
1 VARIABLES DE ENTORNO: NOMBRES EN EL CÓDIGO QUE NO ESTÁN EN EL HOSTING: ____ | VARIABLE DE URL AÚN EN LOCALHOST: SÍ / NO | ESTADO: OK / DESCONOCIDO / CON FALLO
2 TIEMPOS DE ESPERA: ACCIÓN DE USUARIO MÁS LENTA: ____ | LÍMITE DEL HOSTING SEGÚN SU DOCUMENTACIÓN: ____ | ENTRADAS DE TIEMPO AGOTADO EN LOS REGISTROS DEL HOSTING: SÍ / NO | ESTADO:
3 CORS: ORIGEN PERMITIDO PARA EL SITIO EN PRODUCCIÓN: ____ | COINCIDENCIA EXACTA (HTTPS, WWW): SÍ / NO | ESTADO:
4 WEBHOOKS: EL ENDPOINT ES LA DIRECCIÓN HTTPS EN PRODUCCIÓN: SÍ / NO | ENTREGAS FALLIDAS: ____ | EL SECRETO PERTENECE A ESTE ENDPOINT: SÍ / NO | ESTADO:
5 MIGRACIONES: CARPETA DE MIGRACIONES EN EL REPOSITORIO: SÍ / NO | PASO DE MIGRACIÓN EN EL REGISTRO DE DESPLIEGUE: SÍ / NO | PENDIENTES EN PRODUCCIÓN: ____ | ESTADO:
6 SECRETOS: NOMBRES DESTINADOS AL NAVEGADOR QUE PARECEN CLAVES: ____ | ARCHIVOS ENV EN EL HISTORIAL DE GIT: SÍ / NO | ARCHIVO ENV AÚN SEGUIDO POR GIT (git ls-files): SÍ / NO | ESTADO:
7 DOMINIO Y DNS: RESPUESTA DEL DOMINIO RAÍZ: ____ | RESPUESTA DE WWW: ____ | COINCIDE CON LAS INSTRUCCIONES DEL HOSTING: SÍ / NO | TTL: ____ | ESTADO:
RECUENTO DE LÍNEAS QUE NO ESTÁN OK: ____
NOTAS: CADA LÍNEA EN DESCONOCIDO O CON FALLO, CON LO QUE VIOPara la línea 6, git ls-files .env muestra .env mientras git siga el archivo, y nada cuando ya no lo sigue.
Siguiente paso
Fuentes
Comprobadas el 10 de octubre de 2026.
Sobre el autor

Categoría:Desarrollo de softwarePublicación y despliegue
Volver al blog

