You can create and manage tmux sessions and windows programmatically, which is surprisingly powerful for setting up complex development environments or automating repetitive tasks.

Here’s a tmux session with two windows, each split into two panes. The first window is running htop in one pane and tail -f /var/log/syslog in another. The second window is running a Python script in one pane and a shell in the other.

# Create a new session named "dev_env"
new-session -d -s dev_env

# Select the first window (index 0)
select-window -t dev_env:0

# Split the current pane vertically and select the new pane
split-window -h -t dev_env:0.0

# Send commands to the panes
send-keys -t dev_env:0.0 'htop' C-m
send-keys -t dev_env:0.1 'tail -f /var/log/syslog' C-m

# Create a new window named "scripting"
new-window -t dev_env:1 -n scripting

# Split the current pane vertically and select the new pane
split-window -h -t dev_env:1.0

# Send commands to the panes
send-keys -t dev_env:1.0 'python your_script.py' C-m
send-keys -t dev_env:1.1 'bash' C-m

This script uses a series of tmux commands to achieve the setup. Let’s break down how it works and what you can control.

The core idea is to treat tmux as a state machine you can directly manipulate. You’re not just telling tmux what to do; you’re commanding it to enter specific states: create a session, create a window within that session, split a pane in that window, and send keystrokes to a pane.

The commands are chained together. new-session -d -s dev_env creates a detached session named dev_env. -d means it runs in the background, so your current terminal isn’t attached to it. -s dev_env assigns the name.

select-window -t dev_env:0 then targets that session and selects its first window (tmux windows are zero-indexed). split-window -h -t dev_env:0.0 splits the currently active pane (pane 0 within window 0 of session dev_env) horizontally. The -h flag means horizontal split, creating two side-by-side panes. If you wanted a vertical split (top and bottom), you’d use -v.

send-keys -t dev_env:0.0 'htop' C-m is where the magic happens for running commands. It sends the string htop to pane 0 of window 0 in session dev_env, followed by C-m, which is tmux’s internal representation for the Enter key. This executes the command.

new-window -t dev_env:1 -n scripting creates a new window. -t dev_env:1 specifies the target session and the window index (this will be the second window, index 1). -n scripting names this new window.

You have fine-grained control over layout. You can specify a target pane with session:window.pane. For example, dev_env:0.1 refers to pane 1 in window 0 of the dev_env session. You can also target entire windows or sessions.

The real power comes from combining these commands. You can script entire development workflows: start your database, run your backend, open a frontend development server, and have a separate window for Git commits, all with a single command. You can also use these scripts within larger shell scripts or cron jobs.

A common misconception is that you need to manually attach to a session to interact with it after scripting. You don’t. If your script sends commands that keep running (like tail -f or a server), those processes will continue in the background. You can then tmux attach -t dev_env to see and interact with your pre-configured environment.

The display-message command is incredibly useful for debugging. You can use it to get information about the current tmux state, like tmux display-message -p '#{session_name}:#{window_index}.#{pane_index}' to print the identifier of the current pane.

Want structured learning?

Take the full Tmux course →