Skip to main content

Tmux Integration

Neovim inside tmux is one of the most powerful terminal development setups. This lesson covers seamless navigation between tmux panes and Neovim splits, clipboard sharing, and session persistence.

Core Idea

The goal is to make Ctrl+h/j/k/l move your focus transparently between Neovim windows AND tmux panes — without thinking about whether you're in Neovim or tmux.

vim-tmux-navigator​

This plugin makes Ctrl+h/j/k/l work across both Neovim splits and tmux panes seamlessly:

lua/plugins/editor.lua
{
"christoomey/vim-tmux-navigator",
cmd = {
"TmuxNavigateLeft", "TmuxNavigateDown",
"TmuxNavigateUp", "TmuxNavigateRight",
"TmuxNavigatePrevious",
},
keys = {
{ "<C-h>", "<cmd>TmuxNavigateLeft<cr>" },
{ "<C-j>", "<cmd>TmuxNavigateDown<cr>" },
{ "<C-k>", "<cmd>TmuxNavigateUp<cr>" },
{ "<C-l>", "<cmd>TmuxNavigateRight<cr>" },
{ "<C-\\>", "<cmd>TmuxNavigatePrevious<cr>" },
},
},

Corresponding tmux config:

~/.tmux.conf
# Smart pane switching with awareness of Neovim splits
is_vim="ps -o state= -o comm= -t '#{pane_tty}' \
| grep -iqE '^[^TXZ ]+ +(\\S+\\/)?g?(view|l?n?vim?x?|fzf)(diff)?$'"

bind-key -n 'C-h' if-shell "" 'send-keys C-h' 'select-pane -L'
bind-key -n 'C-j' if-shell "" 'send-keys C-j' 'select-pane -D'
bind-key -n 'C-k' if-shell "" 'send-keys C-k' 'select-pane -U'
bind-key -n 'C-l' if-shell "" '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

Clipboard Sharing​

By default, Neovim's yank and the tmux clipboard are separate. Bridge them:

lua/config/options.lua
-- Use system clipboard (shared with tmux via terminal clipboard)
vim.opt.clipboard = "unnamedplus"

On Linux servers, install xclip or use OSC52 for clipboard over SSH:

sudo apt install -y xclip

For SSH clipboard sharing, add to your Neovim config:

-- OSC52 clipboard (works over SSH without X11)
vim.g.clipboard = {
name = "OSC 52",
copy = {
["+"] = require("vim.ui.clipboard.osc52").copy("+"),
["*"] = require("vim.ui.clipboard.osc52").copy("*"),
},
paste = {
["+"] = require("vim.ui.clipboard.osc52").paste("+"),
["*"] = require("vim.ui.clipboard.osc52").paste("*"),
},
}
note

OSC52 requires your terminal emulator to support it (iTerm2, Kitty, WezTerm, etc.).

~/bin/dev.sh
#!/bin/bash
SESSION="dev"
PROJECT="/srv/myproject"

tmux has-session -t "$SESSION" 2>/dev/null && tmux attach -t "$SESSION" && exit

tmux new -s "$SESSION" -n "editor" -d
tmux send-keys -t "$SESSION:editor" "cd $PROJECT && nvim ." Enter

tmux new-window -t "$SESSION" -n "shell"
tmux send-keys -t "$SESSION:shell" "cd $PROJECT" Enter

tmux new-window -t "$SESSION" -n "logs"
tmux send-keys -t "$SESSION:logs" "tail -f /var/log/myapp.log" Enter

tmux select-window -t "$SESSION:editor"
tmux attach -t "$SESSION"

Color and True Color in Tmux + Neovim​

~/.tmux.conf
# Enable true color
set -g default-terminal "tmux-256color"
set -ga terminal-overrides ",*256col*:Tc"
~/.config/nvim/lua/config/options.lua
vim.opt.termguicolors = true
warning

Without Tc override in tmux, colors will look washed out in Neovim. This is one of the most common tmux + Neovim setup issues.

In LazyVim​

LazyVim Context

LazyVim does not include im-tmux-navigator by default to avoid interfering with default window mappings for non-tmux users. However, it can be added trivially by enabling the mux extra. Furthermore, LazyVim configures clipboard support and true color settings out of the box.

AspectVanilla NeovimLazyVim
Tmux NavigationManual im-tmux-navigator setupEnable via :LazyExtras (search for mux)
ClipboardNeeds unnamedplus & OSC52 setupHandled automatically in options.lua
True ColorsRequires ermguicolorsEnabled by default in LazyVim

Adding Tmux Navigation to LazyVim​

If you do not want to use :LazyExtras, you can manually add the plugin to LazyVim. Create a new file in your plugins directory:

lua/plugins/tmux.lua
return {
"christoomey/vim-tmux-navigator",
cmd = {
"TmuxNavigateLeft",
"TmuxNavigateDown",
"TmuxNavigateUp",
"TmuxNavigateRight",
"TmuxNavigatePrevious",
},
keys = {
{ "<c-h>", "<cmd><C-U>TmuxNavigateLeft<cr>" },
{ "<c-j>", "<cmd><C-U>TmuxNavigateDown<cr>" },
{ "<c-k>", "<cmd><C-U>TmuxNavigateUp<cr>" },
{ "<c-l>", "<cmd><C-U>TmuxNavigateRight<cr>" },
{ "<c-\\>", "<cmd><C-U>TmuxNavigatePrevious<cr>" },
},
}

LazyVim will merge this file and automatically override the default Neovim window navigation mappings so that your pane switching works flawlessly.

What's Next​