Back

Por qué zsh es lento al iniciar (y cómo solucionarlo)

Por qué zsh es lento al iniciar (y cómo solucionarlo)

Abres una nueva pestaña de terminal. Esperas. Pasa un segundo, luego dos, quizás tres. Tu prompt de zsh finalmente aparece. Este frustrante retraso no es culpa del shell—casi siempre es tu configuración.

Una instalación vanilla de zsh inicia en aproximadamente 50–100 milisegundos. Cuando el inicio se infla a varios segundos, los culpables son predecibles: sobrecarga del sistema de completado, carga sincrónica de plugins, temas pesados y gestores de versiones de lenguajes como nvm o pyenv. Esta guía te muestra cómo identificar qué es realmente lento y solucionarlo sin reescribir toda tu configuración.

Puntos clave

  • Un zsh estándar inicia en 50–100ms. Los retrasos de varios segundos provienen de tu .zshrc, no del shell en sí.
  • Usa zsh/zprof y /usr/bin/time zsh -i -c exit para identificar los cuellos de botella reales antes de cambiar cualquier cosa.
  • Los gestores de versiones de lenguajes (nvm, pyenv, conda) son los causantes más comunes—cárgalos de forma diferida para ganancias inmediatas.
  • Llama a compinit exactamente una vez, elimina plugins no utilizados y usa un tema ligero para reducir aún más el tiempo de inicio.

Perfilar antes de optimizar

Adivinar es perder tiempo. Zsh incluye un perfilador integrado que revela exactamente dónde se va tu tiempo de inicio.

Agrega esto en la primera línea de tu ~/.zshrc:

zmodload zsh/zprof

Agrega esto en la última línea:

zprof

Abre un nuevo terminal. Verás una salida como esta:

num  calls    time           self           name
1)   1        442.05  84.53%  254.54  48.68%  nvm_auto
2)   2        187.51  35.86%   91.66  17.53%  nvm
3)   1         75.70  14.48%   64.37  12.31%  nvm_ensure_version_installed

La columna self muestra el tiempo empleado en cada función excluyendo las llamadas a otras funciones perfiladas. Apunta primero a los números más grandes.

Para medición de tiempo real, usa:

/usr/bin/time zsh -i -c exit

Ejecuta esto varias veces—la primera invocación puede incluir efectos de caché fría.

Los cuellos de botella más comunes

Gestores de versiones de lenguajes (nvm, pyenv, conda)

Estos son la causa más importante de inicio lento de zsh. La inicialización predeterminada de nvm por sí sola puede agregar 300–500ms.

La solución: carga diferida. No inicialices estas herramientas hasta que realmente las llames.

Para nvm, reemplaza el bloque de inicialización estándar con:

export NVM_DIR="$HOME/.nvm"

nvm() {
  unfunction nvm
  [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
  nvm "$@"
}

Usar una función wrapper en lugar de un alias es más robusto aquí. Un enfoque basado en alias puede fallar cuando nvm se invoca indirectamente (por ejemplo, por un script u otra función), porque los alias solo se expanden en posiciones de comando de nivel superior interactivas. Una función, por otro lado, se comporta como un comando real en cualquier contexto.

Si usas Oh-My-Zsh, habilita el plugin nvm con carga diferida:

zstyle ':omz:plugins:nvm' lazy yes
plugins=(git nvm)

Este enfoque redujo el inicio de un usuario de 430ms a 140ms—una mejora del 70%.

compinit llamado múltiples veces

La función compinit inicializa el sistema de completado de zsh. Es costosa, y los frameworks a menudo la llaman más de una vez por accidente.

Mejor práctica: Llama a compinit exactamente una vez, después de que todas las modificaciones de $fpath estén completas.

# Agrega a fpath PRIMERO
fpath=($ZSH_CUSTOM/plugins/zsh-completions/src $fpath)

# LUEGO inicializa los completados
autoload -Uz compinit && compinit

Si tu archivo .zcompdump está obsoleto o corrupto, regénéralo:

rm -f ~/.zcompdump
compinit

Usar compinit -C omite las verificaciones de seguridad y es más rápido, pero entiende el compromiso antes de habilitarlo: no te advertirá si un archivo de completado ha sido manipulado o es propiedad de otro usuario.

Demasiados plugins

Cada plugin carga archivos de forma sincrónica durante el inicio. Audita tu lista de plugins sin piedad.

Verifica qué plugins usas realmente. Los plugins github y brew son notoriamente lentos. Elimina cualquier cosa que no uses semanalmente.

Temas pesados

Los temas complejos que consultan el estado de git, verifican recursos de red o ejecutan subprocesos agregan latencia notable.

Si usas Powerlevel9k, cambia a Powerlevel10k. Es un reemplazo directo que renderiza prompts 10–100 veces más rápido. Habilita su función Instant Prompt para un inicio percibido como instantáneo.

Verificaciones de actualización automática de Oh-My-Zsh

La verificación de actualización de Oh-My-Zsh se ejecuta en cada lanzamiento del shell y puede dominar el tiempo de inicio. Desactívala:

DISABLE_AUTO_UPDATE="true"

Aún puedes ejecutar omz update manualmente cuando quieras.

Victorias rápidas para un inicio más rápido

  1. Reduce el número de plugins – Elimina plugins no utilizados de tu configuración.
  2. Carga diferida de gestores de versiones – nvm, pyenv y conda deben cargarse bajo demanda.
  3. Llama a compinit una vez – Después de que todas las modificaciones de fpath estén hechas.
  4. Usa un tema ligero – O habilita Instant Prompt de Powerlevel10k.
  5. Desactiva actualizaciones automáticas – Verifica actualizaciones manualmente en su lugar.

Cómo se ve realmente “rápido”

Una configuración de zsh bien optimizada con Oh-My-Zsh debería iniciar en 150–300ms. Sin un framework, 50–100ms es alcanzable. Si estás por encima de 500ms, algo específico está mal—y zprof te mostrará qué es.

Conclusión

No optimices a ciegas. Perfila tu inicio, identifica los cuellos de botella reales y aplica correcciones específicas. La mayoría de los desarrolladores pueden reducir su tiempo de inicio de zsh en un 50–80% en menos de diez minutos cargando de forma diferida un gestor de versiones y eliminando algunos plugins no utilizados.

Recuerda eliminar las líneas de zprof de tu .zshrc cuando termines de medir.

Preguntas frecuentes

No. Una instalación básica de zsh inicia tan rápido como bash, típicamente en menos de 100 milisegundos. La lentitud percibida casi siempre proviene de lo que tu .zshrc carga al inicio, como plugins, temas y gestores de versiones, no del shell en sí.

No en la práctica. La carga diferida significa que nvm y su versión gestionada de Node se cargan la primera vez que ejecutas nvm, node, npm o npx en una sesión. Después de esa llamada inicial, todo funciona exactamente como antes. La única diferencia es que el shell inicia más rápido.

Ejecuta zsh con perfilado habilitado agregando zmodload zsh/zprof al principio y zprof al final de tu .zshrc. En la salida, busca múltiples llamadas junto a compinit o compdump. Si la columna calls muestra un número mayor que uno, tu configuración está inicializando completados de forma redundante.

No necesariamente. Oh-My-Zsh en sí agrega una sobrecarga modesta. Las ralentizaciones provienen de plugins y temas específicos cargados a través de él. Recortar tu lista de plugins, cargar gestores de versiones de forma diferida y cambiar a un tema rápido como Powerlevel10k generalmente llevan el inicio muy por debajo de 300 milisegundos sin abandonar el framework.

Understand every bug

Uncover frustrations, understand bugs and fix slowdowns like never before with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay