Living without workspaces
IDEs and richly-featured text editors - such as VS Code and Sublime Text - support many great features. One of these is the notion of projects or workspaces.
Such workspaces let you save your project’s development configuration to disk - things like the project directory, open files, editor layout, integrated terminal commands, and more. Often, each project can have its own workspace, too.
If you use workspaces then you don’t need to go through the tedious process of setting everything back up again each time you switch project, re-open your editor, or reboot your computer.
However, if, like me, you use the terminal as a primary development environment, things don’t work quite so nicely out of the box. For example, I use tmux as my primary development environment, and make use of multiple windows and panes for things like Vim, source control, logs, and running commands.
At any given time, I might have a handful of tmux sessions running (one for each project). A single small session project might consist of a web API service and a separate front-end - each comprising Vim editor panes, and a mix of other things. Context switching is super easy, as I can just detach from a session, and then re-attach to another one that tmux has kept running for me in the background.
However, the pain point comes when rebooting. Once the tmux server process terminates, all of the running sessions are lost. This means setting each session up again individually each time you want to begin working on a different project after rebooting.
It certainly feels like a blocker to performing system upgrades that require reboots, and is also extra friction that may prevent one from working on specific projects if the set-up is too painstaking. Both of these are clearly not good.
However, there is a solution: tmuxinator.
Tmuxinator
Tmuxinator is a program that partly aims to try and fix the workspace problem for tmux-based workflows, and my life is so much easier because of it.
The program does not interfere with the tmux server directly, and neither does it maintain individual explicit tmux session data - tmux sessions are still lost after reboot.
However, what it does do is make workspace session management so much easier by storing your project window and pane layout in a simple YAML file on disk.
For example, a simple API and separate web front-end project (as mentioned above) could be described as the following tmuxinator project:
name: cool-project
root: ~/project/my-cool-web-project
windows:
- api:
root: ~/project/my-cool-web-project/api
layout: main-vertical
panes:
- vim
- app:
- source .venv/bin/activate
- source .envfile
- flask run
- zsh
- frontend:
root: ~/project/my-cool-web-project/web
layout: main-vertical
panes:
- vim
- yarn start
- zsh
This project represents two tmux windows, each with three panes: an editor, a server (or watcher), and an empty shell pane that can be used for issuing commands (like git
). The inbuilt main-vertical
layout automatically provides a nice, big Vim window (in these cases) for editing, and then a vertically-split extra pair of panes.
Each window has a separate root directory, and the project as a whole has its own root directory too, to provide better automatic working directories in case new windows are later created when inside the session. Each session and window also gets its own name (e.g. api
and frontend
above) to make identification easier later on.
If this file is stored in ~/.config/tmuxinator/cool-project.yml
, one can simply run tmuxinator start cool-project
to get started. If the project is already running it will attach you to it as-is. If the project is not currently up and running, tmuxinator will go ahead and create all your windows and panes, run the commands you specify, and connect you to the new session.
Once inside the session, it’s just controlled by plain old tmux. To detach from the session, just use the usual tmux sequence (by default ctrl-B-D
). You can then connect back to the same session or another one.
Creating more project configurations
Tmuxinator comes with lots of other commands to make set-up easier. For example, running tmuxinator new <project name>
will open up your editor on a template YAML file for you to edit and then save.
If you have lots of similar types of projects with the same layouts then the copy command is useful for duplicating projects as a convenient start-point: tmuxinator cp <existing> <new>
. You can also list and delete projects in a similar way: tmuxinator ls
and tmuxinator rm <project name>
.
Definitely take a look through the documentation to learn more about these and other commands.
Installing tmuxinator
Many distributions include tmuxinator in their repos. On macOS it’s a simple brew install tmuxinator
.
Take a look at the installation instructions for more information.
Backing-up and syncing projects
Being able to recover tmux sessions is great, but what if you want to sync projects between devices, or back them up?
There are various approaches for this. I store my configuration files in my personal Nextcloud, which means I can hydrate any new devices with a simple link:
ln -s ~/Nextcloud/dotfiles/.config/tmuxinator ~/.config/tmuxinator
That way, if I use tmuxinator new
to create a new project configuration it will automatically get synced to my Nextcloud. This approach also works if you use software like Syncthing.
If you work in a team and want to share your setup through version control, you could also commit the project-specific YAML file to your repo. The tmuxinator start
command will look in ./.tmuxinator.yml
before anywhere else, and so this offers a nice way to get your whole team using a consistent setup. However, in my experience the workspace setup can be quite a personal thing!
If you have any other thoughts for maintaining terminal-based workspace sessions, then I’d love to hear them. Please let me know.