Objetivos de aprendizaje
Después de leer este artículo podrás:
- Ordenar las causas más probables de un fallo que solo aparece al desplegar
- Comparar tu entorno local y el de producción punto por punto
- Hacer que la aplicación falle pronto y con un mensaje claro, en lugar de en silencio
Ejecutaste la aplicación cien veces en tu máquina. La desplegaste y ahora se cae al arrancar, devuelve errores o arranca y no hace nada. El código no cambió entre esos dos momentos, así que rara vez el problema es el código.
Lo que cambió es todo lo que lo rodea: el sistema operativo, la versión del runtime, los archivos presentes, las variables de entorno, la red y la memoria disponible. Tu computadora acumula años de estado que ya ni notas. Un servidor empieza vacío y solo tiene lo que le diste.
¿Por dónde empezar?#
Lee el log desde el inicio de la ejecución, no desde el final. El primer error es la causa, y los siguientes suelen ser consecuencia. Si necesitas ayuda para leerlo, mira cómo leer los logs de la aplicación.
Después recorre las comprobaciones de abajo, en este orden. Van de la causa más común a la menos común, y cada una toma unos minutos.
¿Faltan variables de entorno?#
Es la causa número uno. Una aplicación al estilo twelve-factor guarda la configuración, como credenciales y URLs, en variables de entorno, separada del código (The Twelve-Factor App). En local probablemente las sacas de un archivo .env. Ese archivo está, y debe estar, en el .gitignore, así que un deploy desde Git nunca lo lleva.
Síntomas típicos:
TypeError: Cannot read properties of undefined (reading 'split')
DiscordjsError [TokenInvalid]: An invalid token was provided.
connect ECONNREFUSED 127.0.0.1:5432El último es un clásico: falta la URL de la base de datos, la biblioteca recurre a localhost y en el servidor no hay nada escuchando ahí.
Revisa tres cosas:
- ¿Producción tiene todas las variables? Lista los nombres que lee tu código y compáralos con los definidos en el servidor. Los nombres son exactos y distinguen mayúsculas de minúsculas.
- ¿Tu código carga el archivo?
process.envsolo ve aquello con lo que se inició el proceso. En las versiones recientes de Node.js, puedes arrancar connode --env-file=.env index.js(documentación de Node.js). Un simplenode index.jsno lee ningún archivo, y Python necesita un cargador comopython-dotenv. - ¿Los valores son strings? Las variables de entorno siempre son strings.
DEBUG=falsees el string"false", que es truthy en JavaScript. Node.js también convierte a string todo lo que asignas aprocess.env, así que asignarundefinedguarda el texto"undefined"(documentación de Node.js).
Falla pronto para que la próxima ausencia sea evidente:
const required = ["DISCORD_TOKEN", "DATABASE_URL"];
const missing = required.filter((name) => !process.env[name]);
if (missing.length > 0) {
throw new Error(`Missing environment variables: ${missing.join(", ")}`);
}Para la diferencia entre los valores que se leen al compilar y en tiempo de ejecución, mira variables de build y de runtime. Para lo básico, mira qué son las variables de entorno.
¿Coinciden las versiones del runtime y de los paquetes?#
Tu computadora puede usar una versión nueva de Node.js mientras el servidor usa por defecto una más antigua, o al revés. Una sintaxis o API que existe en una versión lanza SyntaxError o TypeError en otra. Lo mismo pasa con Python: una sentencia match o una función más nueva de la biblioteca estándar falla en un intérprete antiguo.
- Imprime la versión en los dos sitios:
node --version,python --version. - Declara la versión que necesita tu aplicación. En
package.json, el campoenginesindica con qué versiones de Node.js funciona el paquete, pero por defecto es solo orientativo (documentación de npm), así que no frena por sí solo una versión equivocada. Revisa también la configuración de runtime de tu hosting. - Haz commit del lockfile (
package-lock.json,poetry.locko unrequirements.txtfijado conpip freeze, mira la documentación de pip). Sin él, el servidor puede resolver versiones de dependencias más nuevas que las que probaste.
En el servidor, instala desde el lockfile en lugar de confiar en una carpeta copiada:
npm cinpm ci exige un lockfile, borra cualquier node_modules existente y falla si package.json y el lockfile no coinciden (documentación de npm). Ese fallo es útil, porque saca a la luz la diferencia al instalar y no en tiempo de ejecución.
¿Falta una dependencia o un archivo?#
Errores como Cannot find module 'express' o No module named 'discord' significan que el paquete nunca se instaló donde se ejecuta la aplicación. Motivos comunes: está en devDependencies pero se usa en tiempo de ejecución, lo instalaste de forma global en tu computadora o envías un node_modules armado en otro sistema operativo. La guía completa está en errores de Cannot find module.
Los archivos se comportan igual. Un archivo puede faltar porque:
- Está en el
.gitignoreo quedó fuera del ZIP que subiste (unconfig.json, una carpeta de datos, una fuente). - Lo genera un paso de build que ejecutaste en local pero nunca en el servidor. Las carpetas
dist/de TypeScript son el caso habitual. - Lo lees con una ruta absoluta como
C:\Users\yo\proyecto\data.json. Usa rutas relativas al archivo (path.join(__dirname, "data.json")) para que la aplicación no dependa de dónde está.
¿Una diferencia de mayúsculas o de ruta la rompe?#
Los sistemas de archivos de Windows y macOS normalmente no distinguen mayúsculas, así que require("./Utils") encuentra utils.js. Linux los trata como dos nombres distintos y lanza MODULE_NOT_FOUND. Los servidores son casi todos Linux, lo que convierte esto en el clásico fallo de "en mi Windows funciona".
Error: Cannot find module './Utils'Corrígelo haciendo que el import coincida exactamente con el nombre del archivo. Si Git ya registró el archivo con las mayúsculas equivocadas, renómbralo con git mv, porque un cambio de nombre normal puede pasar inadvertido para Git en un disco que no distingue mayúsculas. Algunas trampas relacionadas:
- Separadores de ruta: arma las rutas con
path.join, no concatenando"\\". - Los scripts de shell guardados con saltos de línea de Windows (CRLF) pueden fallar en Linux con errores de
bad interpreter. - Los módulos nativos (
sharp,bcrypt,better-sqlite3) incluyen binarios compilados. Un binario armado en tu sistema no funciona en otro. Instala en el servidor para que se descargue la versión correcta.
¿El puerto y el host están mal?#
La aplicación arranca, el log parece sano, pero la URL da timeout o devuelve un error de gateway. Dos causas:
- Puerto fijo en el código. Muchos hostings le dicen a tu aplicación qué puerto usar. Léelo del entorno y deja un valor por defecto para trabajar en local:
const port = process.env.PORT ?? 3000;. Revisa en la documentación de tu hosting cuál es la variable exacta. - Escuchar en la dirección equivocada. Escuchar solo en
localhosto127.0.0.1significa que solo los procesos dentro de la misma máquina o contenedor pueden conectarse. En Node.js,server.listen(port)sin host acepta conexiones en todas las interfaces (::o0.0.0.0) (documentación de Node.js); si pasas"localhost"de forma explícita, cámbialo por"0.0.0.0". Servidores de Python como el servidor de desarrollo de Flask (documentación de Flask) y uvicorn (documentación de uvicorn) escuchan en127.0.0.1por defecto, así que pasa--host 0.0.0.0.
Revisa también las URLs dentro de tu propio código. Un front-end que llama a http://localhost:4000/api funciona para ti y para nadie más. Convierte la URL base en una variable.
¿Se están agotando los recursos?#
Tu computadora puede tener 16 GB de RAM y una CPU rápida. Un plan pequeño de servidor tiene un techo de memoria estricto. Si el proceso muere sin stack trace, o el log termina con Killed o JavaScript heap out of memory, probablemente superaste el límite. Los picos de memoria al arrancar (cargar un dataset grande, construir cachés) son un motivo común. Mira errores de falta de memoria para confirmarlo y corregirlo.
El acceso a la red también cambia. Una base de datos que solo acepta conexiones desde tu IP, una clave de API restringida a localhost o una lista de permitidos que no incluye la dirección del servidor funcionan en casa y son rechazadas desde el servidor.
¿Cómo evitas que vuelva a pasar?#
Reduce la distancia entre los dos entornos:
- Mantén un
.env.examplecon todos los nombres de variables y ningún secreto, y valida al arrancar como se mostró arriba. - Fija las versiones del runtime y de las dependencias, e instala desde el lockfile.
- Prueba un clon limpio. Clona el repositorio en una carpeta nueva, instala desde cero, copia solo las variables que tiene producción y ejecútalo. Si se rompe, encontraste un archivo o una variable que faltaba en dos minutos.
- Usa un contenedor en local si la aplicación es compleja, para ejecutar el mismo sistema operativo y la misma imagen base (qué es Docker).
- Registra la configuración efectiva al arrancar (nombres y versiones, nunca valores secretos), para que las primeras líneas de cada log de deploy digan qué vio la aplicación.
Cómo hacerlo en Square Cloud#
Las comprobaciones de arriba valen en cualquier hosting. En Square Cloud, cada una tiene un lugar concreto donde revisarla.
Define las variables por aplicación en el panel, la API, la CLI o VS Code. El panel importa un archivo .env y exporta las variables como KEY=VALUE, y un cambio se aplica en el siguiente reinicio, sin rebuild. Así, la pregunta "¿está definida mi variable?" se responde en una página de ajustes, sin suposiciones.
Sigue el arranque en tiempo real desde el panel, la CLI o la extensión de VS Code, y lee el primer error. Cada aplicación se ejecuta en un contenedor aislado y solo ve lo que desplegaste y configuraste, como en la prueba del clon limpio.
Algunas reglas de la plataforma coinciden con las causas de este artículo. Al arrancar, ejecuta npm install cuando no existe node_modules, con NODE_ENV=production, así que las devDependencies se omiten. Una aplicación web debe escuchar en 0.0.0.0 en el puerto de la variable PORT. El archivo squarecloud.app es opcional: el panel lo genera al desplegar con el runtime, la memoria y el archivo principal, o puedes escribirlo tú en la raíz del proyecto. Como la memoria forma parte de esa configuración, un desbordamiento de memoria se corrige subiendo ese valor, dentro de la RAM de tu plan, y volviendo a iniciar la aplicación.
Mira cómo funcionan las variables en la página de variables de entorno.
Deploy
Sube desde GitHub, la CLI o un ZIP y publica en segundos
Preguntas frecuentes
¿Por qué mi aplicación funciona en localhost pero se cae después de desplegarla?
Al servidor le falta algo que tu computadora sí tiene: un archivo .env, un paquete instalado de forma global, la misma versión del runtime o un archivo cuyo nombre difiere en mayúsculas y minúsculas. El log de arranque casi siempre lo nombra, así que lee el primer error, no el último.
¿Por qué mi archivo .env no funciona en producción?
El archivo .env suele estar en el .gitignore, así que nunca llega al servidor. Producción necesita las mismas variables definidas en su propia configuración, o un cargador explícito que lea el archivo que envías.
¿Por qué funciona en Windows pero falla en Linux?
Los sistemas de archivos de Linux distinguen mayúsculas de minúsculas, así que ./Utils.js y ./utils.js son archivos distintos. Los separadores de ruta, los saltos de línea en scripts de shell y los binarios nativos compilados para otro sistema operativo causan el mismo tipo de fallo.
¿Cómo reproduzco en local un bug de producción?
Ejecuta la aplicación desde un clon limpio, con instalación nueva, la versión del runtime de producción y solo las variables que tiene producción. Ejecutarla en un contenedor con la misma imagen base elimina casi todas las diferencias restantes.
¿Es un bug del código o un problema del entorno?
Si el mismo commit funciona en una máquina y falla en otra, la diferencia es el entorno: versiones, variables, archivos, red o recursos. Compara los entornos antes de tocar el código.
Más en Deploy
Ver los 33 artículos- Qué son las variables de entornoLas variables de entorno son pares clave-valor que el sistema operativo entrega a un proceso al iniciar. Aprende a leerlas en Node.js y Python sin exponer tokens.
- Qué es un deploy o despliegueUn deploy o despliegue lleva una versión de tu código a un servidor, la prepara y la pone en marcha. Conoce las etapas, los métodos y cómo hacer rollback.
- ¿Cuánta RAM y CPU necesita mi aplicación?Dimensiona RAM y CPU midiendo el pico real de la aplicación y sumando un margen del 30%. Mira cómo medir en Node.js, Python y Java y qué hacer cuando falte.
- Deploy automático con GitHub ActionsEl deploy automático con GitHub Actions envía tu código al servidor en cada push. Mira el workflow paso a paso, los secrets, las pruebas y los errores comunes.