Language-Native Package Managers¶
Runtime version management (mise) and dependency management are
separate concerns. Once mise has resolved the correct python or
bun binary — or once rv has resolved the correct ruby binary —
the language-native tools take over. This separation means mise never
needs to understand gem resolution algorithms, and rv/uv/bun never
need to understand cross-language version switching.
rv — Ruby version and gem management¶
rv is a Rust-backed Ruby version and gem manager from the Spinel team (the same group that maintains Bundler, RubyGems, and rbenv). It is inspired by uv's approach to Python: a single fast binary that replaces rvm, rbenv, chruby, asdf-ruby, ruby-build, and ruby-install with one coherent tool. Precompiled Ruby installs in under a second; gem operations are an order of magnitude faster than the Ruby-based alternatives.
Why rv for Ruby, and not mise?
Two reasons. First, rv is faster and safer than mise's core
ruby-build-backed plugin: it ships precompiled Ruby binaries with
signed attestations, avoiding the entire "compile Ruby from
source" class of problems (OpenSSL mismatches, missing development
headers, Apple Silicon toolchain gaps). Second, rv's gem-adjacent
features — rv clean-install as a drop-in replacement for
bundle install --frozen, rv tool install for isolated CLI
tools, and rvx for ephemeral execution — have no mise equivalent.
mise reads .ruby-version for detection (via idiomatic file
support), so tool inspection and project navigation work as
expected. It just doesn't try to install Ruby itself — rv does
that.
Installation¶
curl --proto '=https' --tlsv1.2 -LsSf \
https://github.com/spinel-coop/rv/releases/latest/download/rv-installer.sh | sh
# Shell activation is already wired in conf.d/70-tools.zsh:
# eval "$(rv shell zsh)"
rv --version # expect: rv 0.5.x or higher
rv ruby list # list available/installed Ruby versions
Project setup¶
rv ruby pin 3.3.4 # writes .ruby-version (committed to VCS)
rv ruby install # installs the pinned version (precompiled, ~0.5s)
# Gem management — rv clean-install is a faster replacement
# for `bundle install --frozen`, using precompiled gems where possible.
bundle init
bundle add rails --version "~> 8.0"
bundle add rspec --group test
bundle lock
rv clean-install # also available as: rv ci
Gemfile and bundle configuration¶
# Gemfile (committed)
source "https://rubygems.org"
ruby "3.3.4" # matches .ruby-version; rv enforces this
gem "rails", "~> 8.0"
gem "rspec", group: :test
Setting BUNDLE_PATH inside .bundle/gems/ keeps project gems
isolated per-project. rv also supports an alternative layout where
gems live under ~/.local/share/rv/gems keyed by Ruby version and
Gemfile hash.
Team coexistence with rbenv¶
If your team uses rbenv, both managers can coexist as long as the
.ruby-version file stays consistent:
| Tool | Reads | Installs to | Shim strategy |
|---|---|---|---|
| rv (you) | .ruby-version + Gemfile |
~/.local/share/rv |
PATH manipulation (rv shell) |
| rbenv (team) | .ruby-version |
~/.rbenv/versions |
Shims in ~/.rbenv/shims |
Gemfile.lock is the shared source of truth for dependencies.
uv — Python dependency management¶
uv (Astral) is a Rust-backed Python package and project manager that replaces pip, pip-tools, virtualenv, and portions of poetry in a single binary. It is 10-100x faster than pip for most workloads and produces deterministic lockfiles by default. mise manages the uv binary version and the Python interpreter; uv manages virtual environments and dependency resolution.
How mise and uv cooperate
mise installs the Python interpreter (or reuses one uv already
installed). With python.uv_venv_auto = "create|source" in your
mise config, cd into a project creates and activates .venv
automatically. You can also run mise sync python --uv to share
a single Python installation between the two tools.
Project initialization¶
uv init my-service
cd my-service
uv python pin 3.12.7 # writes .python-version, which mise reads
uv add fastapi uvicorn
uv add --dev pytest ruff mypy
uv sync # creates .venv/ in project root
Lockfile strategy¶
uv.lock records the complete resolved dependency graph including
hashes. Commit it. It is the canonical record of what runs in
production. Do not commit .venv/ — it is regenerated from the
lockfile by uv sync in under three seconds on most hardware.
uv run vs. manual activation¶
Prefer uv run <command> over manually activating the virtual
environment. uv run ensures the correct interpreter and
dependencies are active without leaking virtualenv state into parent
shells. When the python.uv_venv_auto mise setting is enabled, the
.venv/bin directory is prepended to PATH automatically on cd,
making explicit activation unnecessary for most workflows.
bun — JavaScript and TypeScript¶
bun is the JavaScript runtime, package manager, bundler, and test runner for all JS/TS projects in this stack. It replaces Node, npm/yarn/pnpm, Jest, and in most cases webpack/esbuild. The single-binary design means dependency management, test execution, and script running are always version-aligned.
Team migration from yarn/nvm to bun
If your team currently uses yarn and nvm and is gradually adopting
bun, the framework still holds: list bun under [tools] in
your personal mise.toml, but keep .nvmrc in repos that
teammates share. mise reads .nvmrc via the
idiomatic_version_file_enable_tools setting, so you get correct
Node resolution for legacy scripts. When the project fully
migrates to bun, drop .nvmrc and add node to the [tools]
block only if you need it for tooling that doesn't yet run on
bun.
Project initialization¶
bun init
bun add hono
bun add -d typescript @types/bun biome
# CI-safe install: exits non-zero if lockfile would change
bun install --frozen-lockfile
bun run dev
bun run test
bun.lock¶
bun.lock is a binary lockfile. Commit it. It is deterministic,
human-unreadable (by design), and optimized for fast dependency
resolution. If you need a human-readable lockfile for auditing, run
bun install --save-text-lockfile to produce a text representation
alongside the binary form.
Replacing npm scripts¶
bun executes package.json scripts natively. For teams migrating
from npm/yarn, the only change needed is replacing npm run with
bun run and npx with bun x. There is no global package
installation for CLI tools — use bun x <tool> for ephemeral
execution, or add tools as dev dependencies for consistent versioning.