Nikita Zdvijkov
Software & Electrical Engineer
Houston & Remote
Blog / Feb 20, 2023

Automatic windowed terminal setup with tmux

This is about writing a script to automate your development environment.

A common problem: you want multiple programs to run concurrently, e.g. simultaneously running your unit tests and bundling your frontend, both in watch mode.

One straightforward solution: the concurrently package on NPM.

But this solution has a notable limit: the programs are no longer interactive, i.e. they cannot respond to key presses. For example, you wouldn’t be able to use Jest’s interactive snapshot mode.

How do you overcome this? Nominally, you would resort to manually launching each program in a separate terminal window, pane, or tab, but this can be automated with tmux the terminal multiplexer!

This post assumes familiarity with tmux. Check out my blog post on tmux basics.

Demo

Terminal Screencast: tmux dev

GIF loops every 14 seconds

Code

#!/usr/bin/env bash

# The next set of commands creates 6 panes

tmux split-window -h # `-h` for horizontal split
tmux split-window -v -l '33%' # `-v` for vertical split, `-l '33%'` for 
tmux select-pane -t 1 # switch the active pane (use command `tmux display-panes` for debugging)
tmux split-window -v
tmux select-pane -t 0
tmux split-window -v
tmux split-window -v
tmux select-pane -t 0
tmux split-window -v

# The following code block issues commands to the 6 panes

tmux send-keys -t 1 'npm run dev' Enter
tmux send-keys -t 2 'npm run test' Enter
tmux send-keys -t 3 'npm run lint' Enter
tmux send-keys -t 4 'npm run psql' Enter
tmux send-keys -t 5 'npm run tailwind' Enter
tmux send-keys -t 6 'npm run storybook' Enter

Use the command tmux display-panes (or the equivalent shortcut C-b q) to show the pane numbers for prototyping.

Usage

First, run tmux. Then, from inside tmux, run the script: . ./scripts/dev.sh.

Another helpful tip…

Automatically restart long-running processes every x minutes to remedy resource leaks

Example:

while true; do timeout 10m npm run tsc --watch; done

The timeout 10m <command> wrapper kills the process if it runs for more than 10 minutes.

The infinite while loop restarts the process when it exits or crashes.

I originally developed this technique because Tailwind CSS would occasionally slow down my computer.