Перейти к основному содержимому

Менеджеры версий языков — nvm, pyenv, rustup и другие

Разработчику Инженеру

Задача менеджера версий

На одном компьютере часто нужны разные версии одного языка программирования (runtime или компилятора):

  • legacy-проект на Node 18, новый — на Node 22;
  • Python 3.10 в production, 3.12 для экспериментов;
  • стабильный и nightly Rust;
  • Java 17 для одного сервиса, Java 21 — для другого.

Менеджер версий переключает бинарники (исполняемые файлы) и переменную окружения PATH без переустановки всей операционной системы. Он управляет самим компилятором или runtime. Пакетный менеджер (npm install lodash, pip install requests) ставит библиотеки — это другой уровень абстракции.

ШагТемаЗачем
1Глоссарий и принципыТермины PATH, shim, default
2Node.js — fnm и nvmСамый частый кейс
3Python — pyenvНесколько интерпретаторов
4Rust — rustupКаналы stable/beta/nightly
5Java — sdkman, jabbaJVM-дистрибутивы
6asdf — универсальныйОдин workflow для всех
7Windows и корпоративные PCОсобенности платформы
8CI и командаТе же файлы, что локально
9Troubleshooting и FAQТипичные сбои
МатериалЗачем
Пакетные менеджерыnpm, pip, cargo — следующий слой
Первая программа на Node.jsПроверка node -v после fnm
Первая программа на Pythonvenv после pyenv
WebAssembly (WASM)rustup + wasm32 target
Терминал — о разделеShell, PATH, профили
ОС — о разделеПеременные окружения
Один источник истины

Не смешивайте системный apt install nodejs и fnm на одной машине — в PATH окажутся два node, и половина команд "не видит" нужную версию. Выберите менеджер версий и удалите/conflict package из системного менеджера пакетов ОС.


Глоссарий

ТерминРасшифровка
PATHСписок каталогов, где shell ищет исполняемые файлы по имени (node, python)
RuntimeСреда выполнения — программа, которая запускает ваш код (Node, Python interpreter)
ToolchainКомпилятор + стандартная библиотека + утилиты (Rust: rustc + cargo)
ShimТонкая обёртка в PATH, которая перенаправляет на нужную версию
Global defaultВерсия по умолчанию для новых терминалов
Local overrideВерсия для конкретной папки проекта (файл .nvmrc, .python-version)
LTSLong Term Support — ветка с длительной поддержкой (Node 20, 22)
ChannelКанал обновлений Rust — stable, beta, nightly

Сводная таблица инструментов

Язык / стекИнструментУстановка (типично)Файл в репозитории
Node.jsfnm / nvmwinget / curl script.node-version, .nvmrc
Pythonpyenvpyenv.run / pyenv-win.python-version
Rustrustuprustup.rsrust-toolchain.toml
Java / Kotlin / Scalasdkmanget.sdkman.io.sdkmanrc
Java (JVM)jabbaGitHub releases.jabbarc
Rubyrbenv / rvmgit clone / installer.ruby-version
Gogo install + asdfasdf plugin.tool-versions
Универсальныйasdfgit clone asdf-vm.tool-versions

Node.js — fnm (рекомендация)

fnm (Fast Node Manager) — быстрый, кроссплатформенный менеджер версий Node.js. Написан на Rust; стартует быстрее классического nvm.

Шаг 1 — установка на Windows (PowerShell)

winget install Schniz.fnm

Закройте и откройте терминал. Проверка:

fnm --version

Если команда не найдена — добавьте fnm в PATH вручную или перезапустите VS Code целиком (IDE кэширует окружение при старте).

Шаг 2 — инициализация shell (Windows)

В PowerShell профиль ($PROFILE):

fnm env --use-on-cd | Out-String | Invoke-Expression

Флаг --use-on-cd автоматически переключает версию при входе в каталог с .node-version.

Шаг 3 — установка версий Node

fnm install 22
fnm install 20
fnm install --lts
fnm list

Разбор команд:

  • install 22 — скачивает последний патч Node 22.x;
  • install --lts — текущая LTS-ветка;
  • list — установленные версии и активная (отмечена).

Шаг 4 — переключение

fnm use 22
node -v
npm -v

node -v должен показать v22.x.x. npm идёт в комплекте с Node — отдельно ставить не нужно. Пакеты проекта — через npm.

Шаг 5 — default для новых терминалов

fnm default 22

Шаг 6 — файл проекта

В корне репозитория создайте .node-version:

20

или .nvmrc (fnm понимает оба):

20.18.0
cd my-project
fnm use
node -v
Точная и major-версия

Строка 20 — последний патч ветки 20.x. Строка 20.18.0 — pin на конкретный релиз. Для CI и команды предпочтительнее pin полной версии после проверки совместимости.

fnm на Linux и macOS

curl -fsSL https://fnm.vercel.app/install | bash

Добавьте в ~/.bashrc или ~/.zshrc (скрипт установки выведет строки):

eval "$(fnm env --use-on-cd)"
fnm install --lts
fnm use lts-latest
node -v

Подробнее о первом проекте Node — статья 262.


Node.js — nvm (классика)

nvm (Node Version Manager) — исторический стандарт на Linux и macOS. На Windows используйте nvm-windows — это отдельный форк, не bash-скрипт nvm.

Linux / macOS — установка

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
source ~/.bashrc # или ~/.zshrc
nvm --version

Базовые команды nvm

nvm install 22
nvm install 20
nvm use 22
nvm alias default 22
nvm current
nvm ls

Разбор:

  • install — скачивает и собирает/распаковывает бинарник Node;
  • use — меняет PATH только в текущей shell-сессии;
  • alias default — версия для новых терминалов;
  • current — что активно сейчас;
  • ls — список установленных.

Автопереключение по .nvmrc

cd my-project # в корне лежит .nvmrc с "20"
nvm use

Для автоматического nvm use при cd добавьте hook в zsh/bash (см. wiki nvm-sh).

nvm-windows

Скачайте installer с github.com/coreybutler/nvm-windows/releases.

nvm install 22.11.0
nvm use 22.11.0
node -v

Пути установки на Windows отличаются от Unix-nvm; не копируйте инструкции с macOS без адаптации.


Python — pyenv

pyenv управляет несколькими интерпретаторами Python (разные минорные версии 3.x). Виртуальные окружения проекта — отдельно через venv или poetry; см. пакетные менеджеры.

Шаг 1 — зависимости сборки (Ubuntu/Debian)

Python из pyenv часто собирается из исходников:

sudo apt update
sudo apt install -y build-essential libssl-dev zlib1g-dev \
libbz2-dev libreadline-dev libsqlite3-dev curl \
libncursesw5-dev xz-utils tk-dev libxml2-dev \
libxmlsec1-dev libffi-dev liblzma-dev

Без dev-пакетов pyenv install падает на этапе _ssl или sqlite.

Шаг 2 — установка pyenv

curl https://pyenv.run | bash

Добавьте в ~/.bashrc:

export PYENV_ROOT="$HOME/.pyenv"
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init - bash)"

Перезапустите shell:

exec "$SHELL"
pyenv --version

Шаг 3 — установка версий Python

pyenv install --list | grep " 3.12"
pyenv install 3.12.4
pyenv install 3.10.14
pyenv versions

Первая установка может занять несколько минут — идёт компиляция.

Шаг 4 — global и local

pyenv global 3.12.4
python --version
which python

Локально для проекта:

cd ~/projects/legacy-app
pyenv local 3.10.14
python --version
cat .python-version

Файл .python-version коммитят в Git — команда получает ту же версию.

Шаг 5 — venv после pyenv

cd ~/projects/myapp
pyenv local 3.12.4
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

Windows: pyenv-wingithub.com/pyenv-win/pyenv-win. Альтернатива — официальный installer с python.org + venv без pyenv.

Старт с Python — Первая программа на Python.

pyenv и system python

На Linux не удаляйте системный /usr/bin/python3 — им пользуются скрипты ОС. pyenv добавляет shims раньше в PATH; ваш python — из pyenv, системный остаётся для apt.


Rust — rustup

rustup — официальный установщик Rust toolchain: rustc (компилятор), cargo (пакетный менеджер), rustfmt, clippy.

Шаг 1 — установка

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

На Windows — скачайте rustup-init.exe с rustup.rs.

Выберите default stable (вариант 1).

Шаг 2 — активация PATH

source "$HOME/.cargo/env"
rustc --version
cargo --version

Добавьте source "$HOME/.cargo/env" в ~/.bashrc, иначе после нового терминала cargo "пропадёт".

Шаг 3 — каналы и переключение

rustup default stable
rustup install beta
rustup install nightly
rustup run nightly rustc --version
rustup update
КаналНазначение
stableProduction, обучение
betaПредстоящий stable
nightlyЭкспериментальные фичи

Шаг 4 — targets (кросс-компиляция)

rustup target add wasm32-unknown-unknown
rustup target list --installed

Нужно для WebAssembly.

Шаг 5 — rust-toolchain.toml в проекте

[toolchain]
channel = "1.82.0"
components = ["rustfmt", "clippy"]
targets = ["wasm32-unknown-unknown"]

Файл коммитят — CI и коллеги получают ту же версию через rustup автоматически при cargo build.

Шаг 6 — override на каталог

cd my-rust-app
rustup override set 1.81.0

Раздел Rust.


Java — sdkman и jabba

sdkman (Linux, macOS, WSL)

SDKMAN ставит JDK, Kotlin, Gradle, Maven и другие SDK.

curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"
sdk version

Установка Java:

sdk list java
sdk install java 21.0.3-tem
sdk install java 17.0.11-tem
sdk default java 21.0.3-tem
java -version

Kotlin и инструменты:

sdk install kotlin
sdk install gradle
sdk use java 17.0.11-tem

Файл .sdkmanrc в корне проекта:

java=21.0.3-tem
kotlin=2.0.0
sdk env install
sdk env

См. Java — о разделе.

jabba — кроссплатформенный JVM switcher

# установка — см. github.com/shyiko/jabba
jabba install temurin@21
jabba install graalvm@21
jabba use temurin@21
java -version

Удобно при нескольких дистрибутивах JVM (Eclipse Temurin, GraalVM, Amazon Corretto).


Ruby — rbenv и rvm

rbenv (минималистичный)

git clone https://github.com/rbenv/rbenv.git ~/.rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init - bash)"' >> ~/.bashrc
exec "$SHELL"
rbenv install 3.3.5
rbenv global 3.3.5
ruby -v

.ruby-version в проекте:

3.3.5

Ruby — о разделе.


asdf — один менеджер для многих языков

asdf — plugin-based менеджер: Node, Python, Ruby, Erlang, Terraform и десятки других через единый CLI.

Шаг 1 — установка

git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.14.1

Добавьте в ~/.bashrc:

. "$HOME/.asdf/asdf.sh"
. "$HOME/.asdf/completions/asdf.bash"

Шаг 2 — plugins

asdf plugin add nodejs
asdf plugin add python
asdf plugin add rust
asdf plugin list

Для nodejs-plugin нужен ~/.asdf/plugins/nodejs/bin/import-release-team-keyring (см. доку plugin).

Шаг 3 — install и local

asdf install nodejs 22.11.0
asdf install python 3.12.4
asdf local nodejs 22.11.0
asdf local python 3.12.4

Файл .tool-versions

nodejs 22.11.0
python 3.12.4
rust 1.82.0

Плюсы asdf

  • один workflow для всей команды;
  • один файл .tool-versions в монорепо.

Минусы

  • plugins обновляются независимо;
  • nodejs plugin медленнее fnm на больших CI.

Сравнение fnm и nvm

Критерийfnmnvm
Скоростьочень быстрыймедленнее
Windows nativenvm-windows (форк)
macOS / Linux✓ классика
.nvmrc
Авто cd--use-on-cdhook вручную

Рекомендация для новых проектов — fnm; nvm оставьте, если команда уже стандартизировалась на нём.


Windows — особенности

ИнструментWindows nativeПримечание
fnmwinget, PowerShell
nvm-windowsне путать с Unix nvm
pyenv-winGitHub releases
rustuprustup-init.exe
sdkmanWSL / Git Bashне PowerShell native
asdfWSL рекомендуетсявозможен через Git Bash

PowerShell execution policy

Если скрипты установки блокируются:

Set-ExecutionPolicy -Scope CurrentUser RemoteSigned

Корпоративные PC без admin

  • portable fnm в %USERPROFILE%\bin;
  • rustup per-user;
  • asdf полностью в home directory;
  • избегайте установщиков, требующих UAC.
WSL2 для Linux-toolchain

На Windows 11 многие команды держат pyenv/sdkman в WSL2, а VS Code подключается через Remote-WSL. Версии в Windows и WSL — разные PATH; не смешивайте терминалы без понимания, где выполняется node.


IDE и редактор

ПроблемаРешение
VS Code показывает другую версию NodeПерезапустить VS Code после fnm use; проверить integrated terminal
Pyright/pylance не видит pyenv pythonpython.pythonPath или select interpreter → путь из pyenv which python
Rust Analyzerдолжен подхватить rust-toolchain.toml автоматически
JetBrains IDEsSettings → SDK → path from which java

IDE наследует окружение при старте. После смены default версии — полный перезапуск IDE, не только терминала.


CI — те же файлы, что локально

GitHub Actions — Node

- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'npm'

GitHub Actions — Python

- uses: actions/setup-python@v5
with:
python-version-file: '.python-version'

GitHub Actions — Rust

- uses: dtolnay/rust-toolchain@stable
with:
toolchain: 1.82.0
components: rustfmt, clippy

Или положите rust-toolchain.toml в репо — action подхватит channel.

GitLab CI — пример Node

image: node:22-alpine
before_script:
- node -v
- npm ci

Pin образа Docker должен совпадать с .nvmrc, иначе "works in CI, fails locally".


Практические правила команды

  1. Фиксируйте версию в репозитории.nvmrc, .python-version, rust-toolchain.toml, .tool-versions.
  2. Один источник — либо менеджер версий, либо системный пакет ОС; не оба для одного языка.
  3. CI читает те же файлыnode-version-file, python-version-file, Docker FROM node:22.
  4. Версия языка ≠ версии пакетов — Node 22 + старый lodash — см. 621.
  5. Документируйте onboarding — README блок "Prerequisites" с командами fnm install, pyenv install.
  6. Renovate/Dependabot — обновляет npm/pip; версию runtime обновляют осознанно через PR с тестами.

Пошаговый onboarding нового разработчика

День 1 — базовая машина

# 1. fnm + Node LTS
fnm install --lts && fnm default lts-latest

# 2. pyenv + Python проекта
pyenv install $(cat .python-version)
pyenv local $(cat .python-version)

# 3. rustup если Rust-репо
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup show

# 4. Клон репо и проверка
git clone ...
cd project
fnm use && node -v
python -v
cargo -v # если нужно

День 2 — пакеты

npm ci
python -m venv .venv && source .venv/bin/activate && pip install -r requirements.txt
cargo fetch

Подробно — пакетные менеджеры.


Troubleshooting

СимптомВероятная причинаРешение
node старая после nvm use / fnm usePATH не обновился; другой node раньше в PATHwhich node; удалить brew/apt node; перезапустить shell
command not found: fnmНе добавлен eval в профильfnm env | bash; прописать в .bashrc
pyenv: BUILD FAILEDНет libssl/zlib devУстановить build-essential пакеты (см. выше)
pyenv: version not installedЗабыли pyenv installpyenv install $(cat .python-version)
rustup не в PATHНе sourced .cargo/envsource $HOME/.cargo/env
cargo wrong versionoverride / toolchain filerustup show; проверить rust-toolchain.toml
Разные версии в IDE и терминалеIDE стартовал до fnmПолный restart VS Code
nvm-windows: access deniedНужны права admin для symlinkЗапуск installer от admin или portable fnm
asdf: plugin not foundОпечатка или устаревший pluginasdf plugin update --all
WSL vs Windows node mixedДва PATHЯвно выбрать терминал WSL или PowerShell
python opens Microsoft StoreWindows aliasSettings → App execution aliases → off для python

FAQ

Чем менеджер версий отличается от Docker?

Docker изолирует всю ОС-образ (OS + runtime + deps). Менеджер версий переключает бинарник на хосте. Docker — для deploy parity; fnm/pyenv — для ежедневной разработки на ноутбуке. Часто используют оба.

Нужен ли asdf, если уже есть fnm и pyenv?

Не обязательно. asdf удобен при 4+ языках в одном монорепо. Иначе специализированные инструменты проще.

Можно ли ставить Node через apt?

Можно, но версия отстаёт от LTS на nodejs.org и конфликтует с fnm. Для разработки — fnm; для сервера — Docker или официальный tarball.

Как обновить все установленные версии Rust?

rustup update

Где хранятся скачанные версии?

ToolКаталог (типично)
fnm~/.local/share/fnm
nvm~/.nvm
pyenv~/.pyenv/versions
rustup~/.rustup, binaries в ~/.cargo/bin

Очистка старых версий — команды fnm uninstall, nvm uninstall, pyenv uninstall, rustup toolchain uninstall.

Связь с WebAssembly?

Для WASM нужны rustup, target wasm32-unknown-unknown, часто Node для фронта — всё через менеджеры версий этой статьи.


Go — версии toolchain

Go поставляется одним архивом с go.dev/dl. Несколько версий — через asdf или ручные каталоги.

asdf plugin для Go

asdf plugin add golang
asdf list all golang | head
asdf install golang 1.23.2
asdf global golang 1.23.2
go version

Ручная установка двух версий (Linux)

curl -LO https://go.dev/dl/go1.22.8.linux-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.22.8.linux-amd64.tar.gz
sudo mv /usr/local/go /usr/local/go1.22
# Аналогично go1.23 в /usr/local/go1.23

Переключение alias в ~/.bashrc:

alias go122='GOROOT=/usr/local/go1.22 PATH=/usr/local/go1.22/bin:$PATH go'
alias go123='GOROOT=/usr/local/go1.23 PATH=/usr/local/go1.23/bin:$PATH go'

Пакеты проекта — go mod. См. Go — о разделе.


Elixir и Erlang — asdf

asdf plugin add erlang
asdf plugin add elixir
asdf install erlang 27.1.2
asdf install elixir 1.17.3-otp-27
asdf local erlang 27.1.2
asdf local elixir 1.17.3-otp-27
elixir -v

Сборка Erlang долгая — на CI кэшируйте ~/.asdf/downloads/erlang.

Elixir — о разделе.


Scala и Kotlin через SDKMAN

sdk install scala 3.5.2
sdk install sbt 1.10.2
sdk install kotlin 2.0.21
sdk use kotlin 2.0.21
kotlinc -version

Sscala — о разделе, Kotlin.


Политика версий для команды (шаблон README)

Вставьте в корень monorepo:

## Toolchain

| Tool | Version file | Install |
|------|--------------|---------|
| Node | .nvmrc | fnm install && fnm use |
| Python | .python-version | pyenv install -s |
| Rust | rust-toolchain.toml | rustup show |

После clone:
fnm use && npm ci
pyenv install -s && python -m venv .venv
cargo fetch

Ссылка на 621 для npm ci.


GitHub Actions — matrix нескольких версий

jobs:
test:
strategy:
matrix:
node: [20, 22]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- run: npm ci && npm test

Ловит несовместимость с Node 20 до merge в main.


Docker и менеджеры версий

В Docker не нужен fnm внутри образа — pin образа:

FROM node:22.11-alpine

Локально разработчик использует fnm; CI/CD — фиксированный tag. Расхождение minor допустимо; major — нет.


mise (альтернатива asdf)

mise (бывший rtx) — Rust-rewrite идей asdf:

curl https://mise.run | sh
mise use node@22
mise use python@3.12

Синтаксис .mise.toml:

[tools]
node = "22"
python = "3.12"

Подробный сценарий — Windows + VS Code

  1. winget install Schniz.fnm
  2. PowerShell: fnm env --use-on-cd | Out-String | Invoke-Expression в $PROFILE
  3. fnm install 22 && fnm default 22
  4. Перезапуск VS Code (не только терминала)
  5. Terminal → node -v
  6. Command Palette → "Node: Select" если расширение предлагает другой path

Для Python на Windows без WSL:

git clone https://github.com/pyenv-win/pyenv-win.git $HOME\.pyenv
# Добавить PYENV, PYENV_ROOT, PATH по README pyenv-win
pyenv install 3.12.4
pyenv global 3.12.4

Очистка диска

ToolКоманда
fnmfnm uninstall 18
nvmnvm uninstall 16
pyenvpyenv uninstall 3.9.18
rustuprustup toolchain uninstall nightly-2024-01-01
asdfудалить каталоги в ~/.asdf/installs/

Старые версии копят гигабайты — раз в квартал audit.


Дополнительный Troubleshooting

СимптомВероятная причинаРешение
fnm: version not installedНет fnm installfnm install $(cat .nvmrc)
pyenv: version `3.12.4' not installedТочная версия не скачанаpyenv install 3.12.4
M1 Mac: build failedRosetta / openssl pathPYTHON_CONFIGURE_OPTS env vars из wiki
Corporate proxycurl install blockedOffline tarball, internal mirror
Git Bash vs PowerShell PATHРазные профилиОдин shell для команды
rustup self update failedPermissionsRun without sudo in home
asdf nodejs: gpg failedKeys not importedRun import-release-team-keyring script

FAQ — дополнительно

Как проверить, откуда вызывается node?

which node # Unix
where.exe node # Windows
type -a node # все копии в PATH

Нужен ли Homebrew node на macOS?

Для разработки — нет, если есть fnm. Homebrew node часто конфликтует.

Как зафиксировать npm вместе с Node?

npm bundled с Node. Для override — npm install -g npm@10 внутри нужной версии fnm.

Связь с Docker Compose?

Compose не заменяет fnm; сервисы в compose pin образы, хост — fnm для локальной разработки.


pyenv-virtualenv — автомат venv

Плагин pyenv-virtualenv создаёт venv, привязанный к версии Python:

git clone https://github.com/pyenv/pyenv-virtualenv.git $(pyenv root)/plugins/pyenv-virtualenv
pyenv virtualenv 3.12.4 myapp-venv
pyenv local myapp-venv
python -m pip install -r requirements.txt

Каталог .python-version будет содержать имя venv. Удобно, когда несколько проектов на одной минорной версии Python.


Haskell — ghcup

curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh
ghcup install ghc 9.8.2
ghcup install cabal 3.10.3.0
ghcup set ghc 9.8.2
ghc --version

Haskell — о разделе. Пакеты — cabal/stack (621).


.NET — global.json

Для фиксации SDK без sdkman:

{
"sdk": {
"version": "8.0.403",
"rollForward": "latestFeature"
}
}
dotnet --version

Коммитят global.json рядом с solution.


Переменные окружения — шпаргалка

ПеременнаяИнструментСмысл
PYENV_ROOTpyenvКорень установки
NVM_DIRnvmКаталог nvm
RUSTUP_HOMErustupToolchains
CARGO_HOMEcargoБинарники и registry
GOPATHGoWorkspace (legacy layout)
GOROOTGoТекущий SDK

Проверка: env | grep -E 'PYENV|NVM|RUST|CARGO'.


Сценарий — legacy Node 16 и modern Node 22

cd ~/legacy-crm
cat .nvmrc # 16
fnm install 16
fnm use

cd ~/new-portal
cat .nvmrc # 22
fnm use

С --use-on-cd переключение автоматическое. Не ставьте fnm default 16 если основная работа на 22 — default только для "без .nvmrc".


Сценарий — Python data science

pyenv install 3.11.9
pyenv virtualenv 3.11.9 ds-311
pyenv local ds-311
pip install jupyter pandas scikit-learn
jupyter lab

Тяжёлые wheels (numpy) привязаны к версии Python — не смешивайте 3.10 и 3.11 venv.


Сценарий — Rust stable + nightly в одном репо

rust-toolchain.toml:

[toolchain]
channel = "1.82.0"

Для эксперимента:

rustup run nightly cargo build -Z build-std

Не коммитьте override nightly в toolchain без team agreement.


GitLab CI — полный пример

image: node:22-bookworm
stages: [test]
variables:
NPM_CONFIG_CACHE: "$CI_PROJECT_DIR/.npm"

before_script:
- node -v
- npm ci

test:
script:
- npm test
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- .npm/

Python job параллельно:

python-test:
image: python:3.12-slim
before_script:
- python -m pip install uv
- uv sync --frozen
script:
- uv run pytest

Корпоративный прокси

export HTTP_PROXY=http://proxy.corp:8080
export HTTPS_PROXY=http://proxy.corp:8080
curl -fsSL https://fnm.vercel.app/install | bash

Rust:

export RUSTUP_DIST_SERVER=https://internal-mirror/rust
export RUSTUP_UPDATE_ROOT=https://internal-mirror/rustup

Документируйте mirror в internal wiki.


Безопасность установочных скриптов

Скрипты curl | bash — стандарт индустрии, но риск supply chain:

  • читайте скрипт перед pipe (curl -fsSL URL -o install.sh);
  • pin версию asdf tag, не master;
  • проверяйте checksum release binary.
Не запускайте curl | bash от неизвестных URL

Официальные источники: fnm.vercel.app, rustup.rs, pyenv.run, get.sdkman.io, asdf-vm.com.


Интеграция с direnv

direnv автоматически экспортирует env при cd:

# .envrc
use fnm
layout python python3
direnv allow

Комбинация fnm + pyenv + direnv — автоматический onboarding без ручного fnm use.


Troubleshooting — расширенные кейсы

СимптомПричинаРешение
pyenv: no such command 'virtualenv'Нет pluginУстановить pyenv-virtualenv
fnm on cd не срабатываетНет --use-on-cdОбновить eval строку
Mise и asdf conflictОба в PATHВыбрать один
Windows long pathMAX_PATHEnable long paths in OS
Antivirus блокирует rustupHeuristicException для ~/.rustup
sudo rustupWrong installReinstall without sudo
nvm: version not installedEmpty .nvmrcnvm install
jabba: java not foundWrong shell initjabba init in rc

Чек-лист code review — toolchain

  • .nvmrc / .python-version / rust-toolchain.toml в PR
  • README обновлён при bump версии
  • CI matrix покрывает минимальную supported версию
  • Breaking change runtime — changelog + migration guide
  • Docker image tag синхронизирован с .nvmrc

Дополнительные упражнения

  1. Настройте direnv + fnm для двух проектов с разным Node.
  2. Установите ghcup и соберите Hello World на Haskell.
  3. Создайте .sdkmanrc и sdk env для Java 17 и 21.
  4. Напишите GitLab CI с pyenv в custom Docker image.
  5. Замерьте время fnm install и nvm install для одной версии.
  6. Документируйте onboarding в README по шаблону из этой статьи.

Docker Compose и fnm

Compose pin образы (node:22-alpine); fnm — для локальной разработки на хосте. Не ожидайте, что docker compose exec увидит fnm shims — внутри контейнера свой PATH.


Упражнения для практики

  1. Установите fnm, поставьте Node 20 и 22, переключитесь между ними, создайте .nvmrc.
  2. Установите pyenv, поставьте 3.10 и 3.12, сделайте pyenv local в двух разных папках.
  3. Установите rustup, создайте rust-toolchain.toml с nightly, выполните cargo build.
  4. Настройте GitHub Actions с node-version-file для своего репо.
  5. Намеренно сломайте PATH (два node), найдите через which -a node, почините.
  6. Подключите WSL pyenv и откройте проект в VS Code Remote-WSL.

Onboarding README — полный шаблон

# Project X — Developer Setup

## Prerequisites
- fnm (Node): see encyclopedia/620
- pyenv (Python 3.12.4): `.python-version`
- rustup (optional): `rust-toolchain.toml`

## First run
git clone ...
cd project
fnm use && npm ci
pyenv install -s && python -m venv .venv
source .venv/bin/activate && pip install -r requirements.txt
cargo fetch # if rust/

## Verify
node -v # matches .nvmrc
python -V # matches .python-version
npm test

Ссылка на 621 для npm ci и lock-файлов.


Сравнение менеджеров — итоговая таблица

Если нужноВыберите
Только Node, скоростьfnm
Node на macOS legacynvm
Только Pythonpyenv
Rustrustup (обязательно)
Java/Kotlin/Scala SDKsdkman
JVM cross-platformjabba
5+ языков в monorepoasdf или mise
Windows native без WSLfnm + pyenv-win + rustup

Связанные материалы

ТемаМатериал
npm, pip, cargoПакетные менеджеры
WASM toolchainWebAssembly (WASM)
Node стартПервая программа на Node.js
Python стартПервая программа на Python
ОСОперационная система — о разделе
ТерминалТерминал — о разделе
GitОсновы работы с Git
JavaJava — о разделе
RubyRuby — о разделе

Внешние ресурсы

Ruby — rbenv и chruby

rbenv — менеджер версий Ruby (альтернатива RVM).

# macOS / Linux
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
rbenv install 3.3.4
rbenv global 3.3.4
ruby -v

.ruby-version в корне проекта:

3.3.4

chruby — лёгкое переключение без shims; часто в паре с ruby-install.

ToolShimsWindows
rbenvДаWSL
chrubyНетWSL
RVMДаWSL

После rbenv — bundler для gems (621). Ruby intro.


PHP — phpenv и asdf

phpenv — аналог pyenv для PHP.

git clone https://github.com/phpenv/phpenv.git ~/.phpenv
phpenv install 8.3.9
phpenv local 8.3.9
php -v

На Windows проще asdf plugin или Docker. Затем composer. PHP intro.


mise (бывший rtx) — универсальный runner

mise — современная альтернатива asdf с быстрым Rust-core.

curl https://mise.run | sh
mise use node@22
mise use python@3.12
mise install

.mise.toml:

[tools]
node = "22"
python = "3.12"
rust = "stable"
asdfmise
Плагины communityВстроенные core tools
Медленнее на больших спискахБыстрее
.tool-versions.mise.toml

Elixir — kiex и asdf

kiex — переключение Erlang/Elixir (legacy). Рекомендуется asdf с плагинами erlang + elixir:

asdf plugin add erlang
asdf plugin add elixir
asdf install erlang 27.0
asdf install elixir 1.17.0-otp-27
asdf local erlang 27.0
asdf local elixir 1.17.0-otp-27

.tool-versions:

erlang 27.0
elixir 1.17.0-otp-27

Elixir привязан к версии OTP. Elixir intro.


Scala — coursier и sbt java

Scala использует JVM — сначала sdkman Java 17+, затем coursier (cs):

cs install scala:3.4.1 scalac:3.4.1
cs setup

Или sbt через sdkman. build.sbt не pin Java — используйте .jvmopts или javac -version в CI.


Deno и Bun — отдельно от nvm

Deno и Bun — не Node; собственные бинарники.

RuntimeМенеджерФайл
Nodefnm/nvm.nvmrc
Denodeno upgradedeno.json
Bunbun upgradepackage.json

Не ставьте Deno через fnm. Для polyglot monorepo — asdf/mise с отдельными plugins.


Корпоративный onboarding — playbook

День 1 — новый разработчик

  1. README с версиями: Node, Python, Java из [620] и [621].
  2. Скрипт scripts/setup.sh:
#!/usr/bin/env bash
set -euo pipefail
fnm install
fnm use
node -v
npm ci
  1. VS Code .vscode/extensions.json — ESLint, Python, rust-analyzer.

Неделя 1 — команда

АртеfactСодержание
.nvmrcNode LTS
.python-versionpyenv pin
rust-toolchain.tomlchannel + targets wasm32
.tool-versionsasdf unified
mise.tomlальтернатива asdf
CI matrixте же версии

Квартал — audit

  • Удалить EOL Node/Python из ~/.fnm, ~/.pyenv.
  • Документировать migration guide при bump major.

WSL2 — гибрид Windows + Linux

Типичная схема:

  • Windows: PowerShell, VS Code, fnm для frontend.
  • WSL Ubuntu: pyenv, rustup, Docker backend.
wsl --install -d Ubuntu

В WSL ~/.bashrc:

eval "$(fnm env --use-on-cd)"
export PATH="$HOME/.pyenv/bin:$PATH"
eval "$(pyenv init -)"

Открывайте репозиторий через \\wsl$\Ubuntu\home\user\proj или clone внутри WSL для performance.


Nix и devcontainers — альтернативы

Nix flakes — декларативные dev shells:

# flake.nix (упрощённо)
devShells.default = mkShell {
buildInputs = [ nodejs_22 python312 ];
};

devcontainer.json — Docker-образ с pin версий для VS Code Remote.

ПодходПлюсыМинусы
fnm/pyenvБыстрый стартКаждый ставит сам
asdf/miseОдин toolLearning curve
NixReproducibleСложность
devcontainerОдинаково у всехDocker required

Расширенный FAQ

Можно ли pin Node в package.json?

"engines": { "node": ">=22 <23" }

.nvmrc точнее для fnm. engines — предупреждение, не автомат switch.

volta vs fnm?

Volta pin в package.json, fast on Windows. fnm — широкое community, .nvmrc. Оба лучше системного node.

pyenv virtualenv?

Plugin pyenv-virtualenv создаёт venv привязанный к папке. Альтернатива — стандартный python -m venv после pyenv.

rustup override directory?

rustup override set stable
rustup override set nightly

Приоритет выше rust-toolchain.toml в некоторых случаях — предпочитайте файл в repo.

Несколько Java одновременно?

sdk use java 17.0.11-tem
sdk use java 21.0.3-tem

Разные терминалы — разные версии. JAVA_HOME export в скрипт запуска.


Сценарии по языкам — deep dive

Node.js frontend team

fnm + .nvmrc 22
corepack enable
pnpm install

Corepack pin pnpm без global install.

Python data team

pyenv 3.12
uv venv
uv sync

Pin в .python-version + uv.lock в 621.

Rust systems team

rustup default stable
rustup target add wasm32-unknown-unknown
rust-toolchain.toml in repo

Java enterprise

sdk install java 17.0.11-tem
sdk install java 21.0.3-tem
./gradlew -version

Gradle wrapper pin distribution — не sdkman Gradle binary.

Mobile Android

sdk install java 17.0.11-tem
# Android Studio embeds JDK — align versions

Kotlin Gradle использует JDK из JAVA_HOME или embedded.


Мониторинг версий в production

СлойГде pin
Docker baseFROM node:22-alpine
K8sобраз с digest
Lambdaruntime parameter nodejs22.x
CIactions/setup-node node-version-file

Локальный fnm не влияет на production — только на dev parity.


Упражнения — продвинутый уровень

  1. Настройте mise с node + python + rust в monorepo.
  2. Nix flake или devcontainer — выберите один, поднимите среду с нуля.
  3. WSL + Windows fnm — один repo, две ОС, один .nvmrc.
  4. sdkman + Gradle 8 — два Java проекта, разные JAVA_HOME в scripts.
  5. asdf elixir + erlang — Phoenix hello, .tool-versions в git.
  6. Audit: du -sh ~/.fnm ~/.pyenv ~/.rustup — удалите EOL.


Содержание