Simplify Version Management: Switching from NVM and Pyenv to Proto
Context
When you are working on just one project, you probably don't need to worry about installing different versions of languages and tools on your machine. But if you are working on multiple projects, some of them might require different versions, especially for languages that frequently update.
I mostly work with node.js
and python
. Some projects I handle require different versions of these technologies. This includes creating new projects and maintaining older ones. Switching between projects also means switching between different versions of the technologies.
With node.js
, I have always used nvm
to change the version of node
when necessary. For python
, I found that pyenv
was helpful. However, it was sometimes problematic to install different tools and versions, and to remember to switch between them.
Automating this process is possible but requires a few extra steps. With nvm
, we can create a script that runs with the cd
command to check for an .nvmrc
file or use a shell plugin. With the correct setup, pyenv
will automatically choose the right python
version.
So, we can easily manage those versions, right? Right. For each language, there is a tool to manage multiple versions installed on the system. We can find the right tool, learn how to use it, and apply it. But can we simplify and standardize this solution across different languages?
Proto
Lately, I discovered a tool called proto
- "proto is a pluggable version manager, a unified toolchain." This is quote from the tool documentation that can be found here:
Basically, it is a tool to manage versions for different programming languages and other tools. It supports multiple languages, detects versions based on context, and verifies checksums to ensure the source is trusted. It is also cross-platform and allows for custom tooling through plugins.
Since it supports node.js
, npm
, pnpm
, yarn
, and python
(this one is still as "experimental"), I decided to give it a try.
Installation
Before installation, there are a few requirements. You need to have git
, unzip
, gzip
, and xz
installed. These tools are used to fetch versions and work with archives. You can easily install them using system package managers like brew
or apt
.
To install proto
, the authors provide a script:
curl -fsSL https://moonrepo.dev/install/proto.sh | bash
It will check if the requirements are met and then install proto
.
That's it, now proto
is installed. It will also automatically add the necessary paths to your shell profile, like this:
export PROTO_HOME="$HOME/.proto"
export PATH="$PROTO_HOME/shims:$PROTO_HOME/bin:$PATH"
Since everything will be stored in ~/.proto/
, it will be easy to uninstall by deleting that directory and removing those exports from your profile.
Version detection
Now, when we go to our project, proto
needs to detect which versions of tools we are using. It can find this information from the tool's ecosystem files, like .nvmrc
or package.json
. Alternatively, it can be specified in a .prototools
file. The file structure is simple; it just contains tool = version
.
An example .prototools
file might look like this:
node = "22.1.0"
pnpm = "9.1.1"
python = "3.8"
There are also other ways to specify versions.
Command line:
proto run node 22.1.0
Environment variable:
PROTO_NODE_VERSION=22.1.0 proto run node
Or global versions that are stored at ~/.proto/.prototools
.
If the version cannot be detected or found, it will show an error.
Version pin
The .prototools
file can be modified manually, but you can also use the proto pin
command to save versions to the file. For example:
proto pin node 19
Will save:
node = "~19"
Using flag --global
will pin
the version globally in ~/.proto/.prototools
.
Auto Install and settings
By default, it will not automatically install all tools. You can do it manually using the command:
proto use
This will download and install all the tools and plugins specified in the .prototools
file.
However, you can enable automatic installation by changing the settings in .prototools
.
[settings]
auto-install = true
telemetry = false
Or with the environment variable PROTO_AUTO_INSTALL
.
This way, if a required tool is specified but not available on the system, it will be installed automatically.
There are more settings available, such as detect-strategy
, which lets you choose how to detect versions, and telemetry
, which collects anonymous usage data (the default is true, but you can turn it off by setting it to false). Other settings are listed in the documentation.
Installing tools manually
To manually install, we can use the proto install
command with the tool and version as arguments:
proto install python 3.11.9
But what versions are available to install? To check that, use the command proto list-remote
with the tool as an argument:
proto list-remote python
This will list all available versions to install. To list all installed versions, use a similar command proto list
with the tool as an argument.
This is problematic for python
, which is supported (experimental). proto
installs only pre-built versions and python
doesn't support all of them. Building from source will be supported in the future, as stated on the plugin's GitHub
page.
In the python
plugin repository on GitHub, I found a list of available versions:
https://raw.githubusercontent.com/moonrepo/python-plugin/master/releases.json
To make it easier to use, if you have installed jq
, you can use it:
curl https://raw.githubusercontent.com/moonrepo/python-plugin/master/releases.json | jq 'keys'
This command will list all the versions that can be downloaded.
Plugin installation with gojq example
If you don't have jq
installed, you can use .proto
to install gojq
(a go
implementation of jq
).
proto plugin add gojq "source:https://raw.githubusercontent.com/stk0vrfl0w/proto-toml-plugins/main/plugins/gojq.toml"
--global
This will add the globally available plugin for gojq
, and now you can install it:
proto install gojq --pin --global
This will install gojq
globally and pin its version in ~/.proto/.prototools
.
Now, you can use the previous command to list all python
versions that can be installed with proto
using gojq
instead of jq
.
curl https://raw.githubusercontent.com/moonrepo/python-plugin/master/releases.json | gojq 'keys'
Supported tools
Besides node.js
, npm
, pnpm
, yarn
, and experimental python
, there are more supported tools. Built-in support is also available for bun
, deno
, go
, and rust
. Additionally, many more tools are available as third-party plugins (like the example of gojq
above). You can find a complete list in the documentation here:
https://moonrepo.dev/docs/proto/tools
So, if I want to try another language like go
or rust
, I will use proto
to install it.
Summary
Managing multiple versions of programming languages and tools can be challenging, especially when working on various projects that require different versions. While tools like nvm for Node.js and pyenv for Python help, they can be cumbersome to manage. Proto offers a unified solution for version management across multiple languages and tools, including Node.js, npm, pnpm, yarn, and experimental support for Python. It automates version detection and installation, supports custom tooling through plugins, and simplifies the process with a single configuration file. This guide covers the installation, configuration, and usage of Proto to streamline your development workflow.
Subscribe to my newsletter
Read articles from Artur Bednarczyk directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Artur Bednarczyk
Artur Bednarczyk
I am software developer from Poland. Working mostly with Typescript and Python.