wandres.dev
DIOS · Terminal · IA · Automatización

Multiplexores: tmux vs zellij

Divide tu terminal en paneles y sesiones persistentes. Compara tmux y zellij, y logra navegación transparente entre sus paneles y los splits de Neovim.

⏱ 17 min

Un multiplexor divide una terminal en paneles y ventanas, y mantiene tus sesiones vivas aunque cierres el terminal o se caiga la conexión. Combinado con Neovim, te da un espacio de trabajo persistente: editor, servidor, logs y tests, todo a la vez.

🎯 Al terminar esta lección sabrás
  • Qué aporta un multiplexor y cuándo usarlo.
  • tmux vs zellij: cuál elegir y por qué.
  • Navegación transparente entre paneles y splits de Neovim.
  • Sesiones y “sessionizers” para saltar entre proyectos.

¿Por qué un multiplexor?

🪟

Paneles y ventanas

Editor arriba, servidor y logs abajo, tests al lado. Todo en una sola terminal.

💾

Persistencia

Cierra el terminal, vuelve mañana y tu sesión sigue igual: procesos vivos, layout intacto.

🗂️

Sesiones por proyecto

Una sesión por proyecto. Saltas entre ellas al instante sin perder el contexto.

tmux vs zellij

🧩

tmux

El veterano. Basado en una tecla prefijo (Ctrl-b). Máxima potencia, scriptable, disponible en cualquier servidor. Curva más dura y config manual.

zellij

El moderno. Basado en modos, con una barra que muestra las acciones disponibles. Productivo en minutos, y sesiones y gestor de sesiones nativos.

💡
¿Cuál elijo?

Desarrollas en tu propia máquina y valoras descubribilidad → zellij. Trabajas mucho por SSH en servidores, quieres scripting y ubicuidad → tmux. Ambos son excelentes; aquí configuramos la navegación fluida con Neovim en los dos.

El problema: dentro de tmux/zellij, Ctrl-h/j/k/l debería moverte entre paneles; dentro de Neovim, entre splits. Sin integración, chocan. La solución hace que las mismas teclas funcionen sin pensar: si hay un split de Neovim en esa dirección, salta a él; si no, al panel del multiplexor.

Con tmux: vim-tmux-navigator

christoomey/vim-tmux-navigator
return {
  "christoomey/vim-tmux-navigator",
  cmd = {
    "TmuxNavigateLeft", "TmuxNavigateDown",
    "TmuxNavigateUp", "TmuxNavigateRight",
    "TmuxNavigatePrevious", "TmuxNavigatorProcessList",
  },
  keys = {
    { "<C-h>", "<cmd>TmuxNavigateLeft<cr>",  desc = "Nav izquierda" },
    { "<C-j>", "<cmd>TmuxNavigateDown<cr>",  desc = "Nav abajo" },
    { "<C-k>", "<cmd>TmuxNavigateUp<cr>",    desc = "Nav arriba" },
    { "<C-l>", "<cmd>TmuxNavigateRight<cr>", desc = "Nav derecha" },
  },
}
vim.pack.add({ { src = "https://github.com/christoomey/vim-tmux-navigator" } })

Es Vimscript y solo define cuatro comandos, así que da igual la vía. Lo que no puedes saltarte es la mitad de tmux: sin la config de abajo, las teclas no llegan a Neovim.

Con vim.pack no hay bloque keys donde declarar los atajos, pero es que tampoco hacen falta: el plugin crea él solo <C-h>, <C-j>, <C-k>, <C-l> y <C-\> al cargarse. Si prefieres otras teclas, pon vim.g.tmux_navigator_no_mappings = 1 antes del vim.pack.add y defínelas tú con los comandos TmuxNavigate*.

Y en tu ~/.tmux.conf, el lado de tmux (o simplemente set -g @plugin 'christoomey/vim-tmux-navigator' si usas TPM, que instala estas mismas reglas):

# Navegación consciente de Vim (christoomey/vim-tmux-navigator)
vim_pattern='(\S+/)?g?\.?(view|l?n?vim?x?|fzf)(diff)?(-wrapped)?'
is_vim="ps -o state= -o comm= -t '#{pane_tty}' \
    | grep -iqE '^[^TXZ ]+ +${vim_pattern}$'"
bind-key -n 'C-h' if-shell "$is_vim" 'send-keys C-h' 'select-pane -L'
bind-key -n 'C-j' if-shell "$is_vim" 'send-keys C-j' 'select-pane -D'
bind-key -n 'C-k' if-shell "$is_vim" 'send-keys C-k' 'select-pane -U'
bind-key -n 'C-l' if-shell "$is_vim" 'send-keys C-l' 'select-pane -R'

bind-key -T copy-mode-vi 'C-h' select-pane -L
bind-key -T copy-mode-vi 'C-j' select-pane -D
bind-key -T copy-mode-vi 'C-k' select-pane -U
bind-key -T copy-mode-vi 'C-l' select-pane -R

# Calidad de vida
set -g mouse on
set -g base-index 1
set -g renumber-windows on
setw -g mode-keys vi

Con zellij: zellij-nav + autolock

zellij intercepta las teclas con sus modos. La solución combina dos piezas: zellij-nav.nvim (el lado de Neovim) y zellij-autolock (un plugin de zellij que lo pone en modo Locked cuando el panel activo es Neovim, para que no robe las teclas).

swaits/zellij-nav.nvim
return {
  "swaits/zellij-nav.nvim",
  lazy = true,
  keys = {
    { "<C-h>", "<cmd>ZellijNavigateLeftTab<cr>", desc = "Nav izquierda" },
    { "<C-j>", "<cmd>ZellijNavigateDown<cr>", desc = "Nav abajo" },
    { "<C-k>", "<cmd>ZellijNavigateUp<cr>", desc = "Nav arriba" },
    { "<C-l>", "<cmd>ZellijNavigateRightTab<cr>", desc = "Nav derecha" },
  },
  opts = {},
}
vim.pack.add({ { src = "https://github.com/swaits/zellij-nav.nvim" } })

require("zellij-nav").setup()

local map = vim.keymap.set
map("n", "<C-h>", "<cmd>ZellijNavigateLeftTab<cr>",  { desc = "Nav izquierda" })
map("n", "<C-j>", "<cmd>ZellijNavigateDown<cr>",     { desc = "Nav abajo" })
map("n", "<C-k>", "<cmd>ZellijNavigateUp<cr>",       { desc = "Nav arriba" })
map("n", "<C-l>", "<cmd>ZellijNavigateRightTab<cr>", { desc = "Nav derecha" })

Como solo hace falta al pulsar las teclas, con lazy.nvim ni se carga hasta entonces. Es la mitad del truco: sin el autolock del lado de zellij, las teclas no llegan.

ℹ️
El truco del autolock

Añade a tu configuración de zellij el plugin zellij-autolock (fresh2dev/zellij-autolock): detecta cuándo el panel activo ejecuta Neovim y pone zellij en modo Locked, para que Ctrl-h/j/k/l lleguen al editor en vez de moverte de panel. Se configura con una lista de programas que disparan el bloqueo. Y para que zellij vuelva a modo Normal al cerrar Neovim, añade esto a tu config:

vim.api.nvim_create_autocmd("VimLeave", {
  pattern = "*",
  command = "silent !zellij action switch-mode normal",
})

Sessionizers: saltar entre proyectos

El flujo estrella de los pros: un atajo que abre un selector difuso de proyectos y te crea/abre una sesión para el que elijas.

En tmux, el clásico tmux-sessionizer (script de ThePrimeagen) con fzf:

#!/usr/bin/env bash
selected=$(find ~/dev ~/work -mindepth 1 -maxdepth 1 -type d | fzf)
[ -z "$selected" ] && exit 0
name=$(basename "$selected" | tr . _)
tmux new-session -ds "$name" -c "$selected" 2>/dev/null
tmux switch-client -t "$name" 2>/dev/null || tmux attach -t "$name"

En zellij, las sesiones son nativas: zellij attach --create nombre desde el terminal, y dentro de zellij el modo Session (Ctrl-o) más w abre el gestor de sesiones integrado.

El espacio de trabajo definitivo

Multiplexor + Neovim + sessionizer = cambias de proyecto en una tecla, cada uno con su layout (editor + servidor + tests) intacto y persistente. Navegas entre el editor y los logs con las mismas Ctrl-h/j/k/l sin pensar dónde acaba Neovim y empieza el terminal. Es la sensación de un IDE, pero infinitamente más rápido y tuyo.

⚔️ Tu espacio persistente
  1. Instala tmux o zellij y configura la navegación transparente.
  2. Divide en paneles: editor + terminal. Salta entre ellos con Ctrl-h/j/k/l desde dentro de Neovim.
  3. Crea una sesión, ciérrala (detach) y vuelve a entrar (attach): sigue viva.
  4. Monta un sessionizer y salta entre dos proyectos con un solo atajo.