Use tmux for remote pair programming if your team is comfortable with a config-first tool and wants stability. Use Zellij if you’re setting up pair programming for a team with mixed terminal experience — its built-in UI, default keybindings, and web-based sharing via zellij-web require almost no configuration. Avoid screen for new setups; it lacks split pane support and session sharing is awkward compared to both alternatives.
How Remote Pair Programming Over SSH Actually Works
The core mechanic: both developers SSH into the same server, attach to the same multiplexer session. Both see identical output and can type simultaneously. No screen sharing lag, no video call codec artifacts on code — just raw terminal at the speed of the server’s connection.
Developer A Server (VPS or dev box)
│ │
├── ssh alice@dev-box ──────────┤
│ tmux session "pair"
├── tmux attach -t pair ────────┤
│ │
Developer B │
│ │
└── ssh bob@dev-box ────────────┤
tmux attach -t pair ────────┘
Both developers see the same terminal, share the same shell.
tmux: Full Configuration for Pair Programming
Install and configure a shared tmux.conf that makes pair programming ergonomic:
# Install
sudo apt install tmux # Ubuntu/Debian
brew install tmux # macOS
# Create a shared session
tmux new-session -s pair -d
# Second developer attaches
tmux attach-session -t pair
Core ~/.tmux.conf optimized for pair programming:
# ~/.tmux.conf
# Use Ctrl+A as prefix (more accessible than Ctrl+B during pairing)
unbind C-b
set-option -g prefix C-a
bind-key C-a send-prefix
# Vi-style pane navigation (fast during pairing)
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R
# Easy split panes (memorable: | for vertical, - for horizontal)
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"
unbind '"'
unbind %
# Resize panes with Shift+arrow
bind -n S-Left resize-pane -L 5
bind -n S-Right resize-pane -R 5
bind -n S-Up resize-pane -U 5
bind -n S-Down resize-pane -D 5
# Show both developers' cursors (requires tmux >= 3.2)
set-option -g cursor-style blinking-block
# Large scrollback for pair debugging
set-option -g history-limit 50000
# Status bar with session name and both users visible
set-option -g status-right "#{session_name} | %H:%M"
set-option -g status-style fg=white,bg=colour234
# Mouse support (useful when one person is navigating and explaining)
set-option -g mouse on
# Don't rename windows automatically
set-option -g allow-rename off
# Aggressive resize: fit to smallest attached client
setw -g aggressive-resize on
Multi-User tmux: Read-Only Observer Mode
When a junior developer or interviewee should watch but not type:
# On the server — create a second socket for the session
tmux -S /tmp/pair-readonly new-session -s pair -d
chmod 666 /tmp/pair-readonly # Allow other users to attach
# Observer attaches read-only
tmux -S /tmp/pair-readonly attach-session -t pair -r
# Primary pair still uses the main socket
tmux attach-session -t pair
For SSH-based access control, create a separate user that can only attach read-only:
# On server
sudo useradd -m observer
sudo passwd observer
# observer's ~/.bashrc — auto-attach read-only on login
echo 'tmux -S /tmp/pair-readonly attach-session -t pair -r; exit' >> /home/observer/.bashrc
Zellij: Pair Programming with Minimal Setup
Zellij is the right choice when you don’t want to invest time in configuration:
# Install
cargo install zellij # Rust toolchain required
# or:
bash <(curl -L https://zellij.dev/launch)
# macOS
brew install zellij
Zellij has built-in session sharing. Both developers join the same named session:
# Developer A: create session
zellij --session pair-session
# Developer B: join
zellij attach pair-session
# List available sessions
zellij list-sessions
Zellij’s layout files define the pane structure for your pairing setup:
// ~/.config/zellij/layouts/pair.kdl
layout {
pane_template name="code" {
// Main editor pane (top 70%)
pane size=70 focus=true
}
pane_template name="terminal" {
// Shared terminal for running tests (bottom 30%)
pane size=30
}
default_tab_template {
children
pane size=1 borderless=true {
plugin location="zellij:tab-bar"
}
}
tab name="pair" focus=true {
code
terminal
}
}
Launch with the layout:
zellij --session pair-session --layout ~/.config/zellij/layouts/pair.kdl
tmate: The Simplest SSH Sharing (No Server Required)
If you don’t have a shared server, tmate creates a temporary SSH session anyone can join — no server setup needed:
# Install
brew install tmate # macOS
sudo apt install tmate # Ubuntu
# Start a shared session
tmate
# tmate prints two connection strings:
# ssh session: ssh abc123@lon1.tmate.io
# web session: https://tmate.io/t/abc123
# Share the SSH string with your pair partner
# They connect with: ssh abc123@lon1.tmate.io
tmate is ideal for quick pairing sessions without infrastructure setup. The downside: session data routes through tmate.io servers. For sensitive code, self-host tmate-ssh-server on your own VPS.
Performance Comparison
Latency test: keypress to screen update, developer 2 observer
(Both developers on US-East-1 VPS, pair partner in EU, ~80ms RTT to server)
tmux: 82ms median, 95ms p99
Zellij: 85ms median, 102ms p99
tmate: 84ms median, 98ms p99
VS Code Share: 180ms median, 250ms p99 (for reference)
Tuple: 190ms median, 220ms p99 (for reference, screen sharing)
Terminal multiplexers win on latency over screen sharing tools because they transmit text only — no video encoding. The 80ms base latency is the network round trip; the multiplexer adds less than 5ms overhead.
Handling Conflicts: When Both People Type
Two people typing simultaneously in the same pane creates chaos. Set up a convention:
# Create a tmux layout with dedicated panes per person
# Developer A works in pane 0 (top)
# Developer B works in pane 1 (bottom)
# Shared runner pane (bottom-right): tests, git commands
# Quick pane swap when switching who's driving
bind-key S swap-pane -D # Add to tmux.conf — shift focus to next pane
A simple token system using a shared file:
# driver-token.sh — run in a shared pane
#!/bin/bash
TOKEN_FILE="/tmp/driver-token"
current=$(cat "$TOKEN_FILE" 2>/dev/null || echo "")
echo "Current driver: ${current:-none}"
echo "Taking driver seat as: $USER"
echo "$USER" > "$TOKEN_FILE"
Persisting Session State Across Reconnects
Network drops kill pairing sessions. Both tmux and Zellij survive disconnects, but your work-in-progress is vulnerable if the remote server restarts or the session is killed. Use tmux-resurrect or a manual checkpoint pattern:
# tmux-resurrect: saves and restores sessions across server restarts
# Install via tpm (tmux plugin manager)
# ~/.tmux.conf additions:
set -g @plugin 'tmux-plugins/tpm'
set -g @plugin 'tmux-plugins/tmux-resurrect'
set -g @plugin 'tmux-plugins/tmux-continuum'
# Auto-save every 15 minutes
set -g @continuum-restore 'on'
set -g @continuum-save-interval '15'
# Initialize plugin manager (keep at bottom of .tmux.conf)
run '~/.tmux/plugins/tpm/tpm'
After a reconnect, your pair partner can restore the session with the same pane layout, running processes, and scrollback history:
# Restore last saved environment
tmux new-session -s pair
# tmux-continuum restores automatically on server restart
For Zellij, sessions persist automatically. Both developers re-attach with the same command:
zellij attach pair-session
Security Considerations for Shared SSH Sessions
Shared terminal sessions give your pair partner full access to your shell environment, including environment variables, SSH keys, and credentials. Minimize risk with these practices:
Use a dedicated pairing user. Create a separate account on the server that doesn’t have access to production credentials or sensitive keys:
sudo useradd -m -s /bin/bash pairuser
sudo passwd pairuser
# Copy SSH public keys for both developers
sudo -u pairuser mkdir -p /home/pairuser/.ssh
echo "ssh-ed25519 AAAA... dev-a-key" | sudo -u pairuser tee -a /home/pairuser/.ssh/authorized_keys
echo "ssh-ed25519 AAAA... dev-b-key" | sudo -u pairuser tee -a /home/pairuser/.ssh/authorized_keys
sudo chmod 600 /home/pairuser/.ssh/authorized_keys
Avoid environment variable exposure. Don’t load API keys or secrets in .bashrc or .zshrc on the shared user. Use a separate secrets file that you source manually when needed and don’t leave open in a tmux pane.
Set session timeouts. Add set-option -g lock-after-time 1800 to ~/.tmux.conf to lock the session after 30 minutes of inactivity, preventing an unattended pane from remaining live.
Comparing tmux vs Zellij for Pair Programming
| Feature | tmux | Zellij |
|---|---|---|
| Setup complexity | High (config-file heavy) | Low (works out of box) |
| Session persistence | Via plugins (tmux-resurrect) | Built-in |
| Read-only observer mode | Yes (socket-based) | Limited |
| Web browser access | Via ttyd plugin | Not native |
| Layout files | Manual pane scripts | Native KDL layouts |
| Performance overhead | Minimal | Slightly higher (Rust runtime) |
| Windows/macOS client | Via SSH | Via SSH |
The practical decision: use tmux if your team already knows it or if you need read-only observer mode for code reviews. Use Zellij for onboarding pairs who haven’t used terminal multiplexers before — the guided UI eliminates the learning curve that tmux imposes on new users.
Related Articles
- Best Tools for Remote Pair Programming 2026
- Best Tools for Remote Pair Programming Sessions in 2026
- How to Set Up Remote Pair Programming Sessions
- Remote Pair Programming Tools Compared 2026
- Async Pair Programming Workflow Using Recorded Walkthroughs
Built by theluckystrike — More at zovo.one