Build Tools & Package Managers — Cross-Language Comparison

Build Tools & Package Managers — Cross-Language Comparison

  • Type: cross-cutting comparison
  • Languages covered: 51 (see _index)
  • Last updated: 2026-05-07

TL;DR

  • Modern tooling bundles: version manager + package manager + dependency resolver + build orchestrator + test runner + linter + formatter. Best-in-class languages unify these (Cargo, .NET CLI, Mix, Go toolchain). Worst-in-class fragment them across 5+ tools.
  • Cargo (Rust) is the de-facto template for “what good looks like”: single binary, lockfile-based reproducibility, integrated test/bench/doc, no global state pollution.
  • Python’s tool churn has finally stabilized: uv (Astral) won the 2025 race against poetry/pdm/pip-tools/hatch as the dominant resolver. Pair with ruff (formatter+linter) and pytest (testing).
  • Java fragmentation persists: Maven (XML), Gradle (Groovy/Kotlin DSL), Mill, sbt all coexist. Pick by ecosystem, not preference.
  • Compiler-as-build-system is a 2020s trend: Zig’s build.zig, Odin’s build via Odin code, V’s v build. The build system speaks the same language as your code.
  • No first-class package manager is still common in C/C++/Fortran; vcpkg/conan/spack are converging answers.

What “build tooling” means in 2026

A complete toolchain provides:

  • Version manager: install + switch between language versions (rustup, nvm, pyenv, sdkman).
  • Package manager: download + install dependencies (cargo, npm, pip, maven).
  • Dependency resolver: solve compatible-version graph (uv resolver, npm/pnpm resolver, cargo resolver).
  • Lockfile: pin exact versions for reproducibility (Cargo.lock, package-lock.json, requirements.txt or uv.lock, Gemfile.lock).
  • Build orchestrator: compile, link, package (cargo build, mvn package, npm run build).
  • Test runner: discover + execute tests (cargo test, pytest, jest).
  • Linter: catch likely bugs (clippy, ruff, eslint).
  • Formatter: enforce style (rustfmt, ruff format, prettier, gofmt).
  • Type checker (if external): mypy/pyright, tsc, dialyzer.
  • Doc generator: rustdoc, sphinx, javadoc.
  • Publish path: cargo publish, npm publish, pypi twine, mvn deploy.

Languages with single-tool stories (one binary does ~all of this): Rust (cargo), Go, .NET (dotnet CLI), Dart, Deno, Bun, Elixir (mix), Crystal (shards-driven).

Languages with stacked stories (assemble from N tools): Python (uv + ruff + pytest + mypy), Ruby (bundler + rake + rspec + rubocop), C/C++ (CMake + vcpkg + ctest + clang-format + clang-tidy), Java (Maven OR Gradle + JUnit + Checkstyle/SpotBugs + google-java-format).

Categories

1. Single unified tool (the modern gold standard)

  • RustCargo: install via rustup (toolchain manager). cargo build/test/run/bench/doc/publish/install. Cargo.toml + Cargo.lock. crates.io. The reference design.
  • Gogo toolchain (built into the go binary). go build/test/run/install/get/mod. Modules + go.mod + go.sum. No separate package manager. Workspaces (1.18+) for multi-module repos.
  • [[Languages/csharp|C#]] / [[Languages/fsharp|F#]] / VB.NET — dotnet CLI. dotnet new/build/test/run/publish/pack. NuGet for packages. Solution + project files (.csproj/.fsproj/.sln) — XML but tooled.
  • Dartdart pub. dart create/run/test; pub get/upgrade/publish. Lockfile. Flutter has its own CLI on top.
  • ElixirMix. mix new/compile/test/deps.get/format/release. Hex.pm for packages. mix.exs + mix.lock.
  • CrystalShards (package mgr) + Crystal compiler. shards install/build. shard.yml + shard.lock. Slightly less unified than Rust/Go.
  • SwiftSwift Package Manager (SPM). swift build/test/run/package. Package.swift is Swift code. Apple frameworks via Xcode (separate UX).
  • Zigzig build (uses build.zig written in Zig). Native package manager (zon files) since 0.11. zig fetch for dependencies. Compiler-as-build-system.
  • OdinOdin compiler itself; build scripts written in Odin. No first-party package manager (community: pkg). Dependencies typically vendored.
  • Vv CLI. v new/run/build/test. vpm package manager. v.mod files.
  • NimNimble. nimble install/build/test. .nimble file.
  • JuliaPkg (built-in REPL mode). ]add/rm/update/test/precompile. Project.toml + Manifest.toml. Julia’s package mgmt is excellent — sysimage caching, env stacking.
  • Rocroc dev/build/test/check/format. Packages by URL/hash (no central registry yet).
  • Gleamgleam new/build/test/format/run/publish. Hex.pm reused (BEAM ecosystem). gleam.toml.
  • Ponyponyc compiler + corral package manager. Less unified than Cargo.

2. Package manager + separate build system

  • Python — installer/resolver + build backend stack. 2026 winning combo: uv (Astral) + ruff (Astral) + pytest + mypy (or pyright). PEP 518 pyproject.toml is canonical metadata. Build backends: hatch, setuptools, poetry, pdm, flit. Version manager: pyenv (legacy) or uv python (winning). PEP 723 inline script metadata.
  • RubyBundler (deps) + Rake (build) + RSpec/Minitest (test) + RuboCop (lint). Gemfile + Gemfile.lock. Version manager: rbenv, rvm, asdf, mise.
  • PHPComposer (deps) + Make/Phing (build, optional) + PHPUnit/Pest (test) + PHP_CodeSniffer/PHPStan (lint/static analysis). composer.json + composer.lock. Packagist registry.
  • JavaMaven (XML, declarative) OR Gradle (Groovy/Kotlin DSL, imperative) OR Mill (Scala-based, newer challenger). Maven Central registry. Test: JUnit 5/TestNG. JaCoCo coverage.
  • Scalasbt (default, Scala DSL) OR Mill (Scala-based) OR Maven OR Gradle. Both reach into the JVM ecosystem. build.sbt is Scala source.
  • KotlinGradle (default; Kotlin DSL recommended) OR Maven. Same JVM packaging story.
  • GroovyGradle (built in Groovy) OR Maven. Grape (@Grab) for ad-hoc script deps.
  • Clojuredeps.edn / Clojure CLI tools (clj/clojure, modern) OR Leiningen (lein, legacy but widely used). deps.edn is the official future. Test: clojure.test, kaocha. Maven/Clojars registries.
  • JavaScript / TypeScriptnpm (default) / pnpm (best — content-addressed store) / yarn (declining) + Node.js as runtime. Bundlers: Vite (winning), webpack (legacy), Rollup, esbuild, Bun (also a runtime). package.json + lockfile per tool. TS adds tsc + tsup/tsdown. Test: vitest (winning), jest, node:test built-in.
  • PerlCPAN (centralized 30+ year archive) + cpanm / carton (modern). cpanfile for declarative deps. Build: ExtUtils::MakeMaker, Module::Build, Dist::Zilla.
  • LuaLuaRocks (de facto). *.rockspec files. LuaJIT pairs with it. Embedded contexts (Roblox, Defold, Love2D) bypass entirely.
  • RCRAN (centralized, vetted) + install.packages(); renv for reproducibility; devtools for development. Bioconductor for bio packages.

3. OS package manager as the package manager

  • C — historically apt/yum/brew + manual ./configure && make install. Modern: vcpkg (Microsoft), Conan (JFrog), Spack (HPC), pkg-config + CMake for build. CMake (CMake DSL), Meson (Python DSL), Bazel (Starlark DSL), Make (the original) all live here.
  • C++ — same as C, plus Conan 2.x (most polished) + CMake. Bazel for monorepos. Build2 as a unified attempt.
  • FortranFPM (Fortran Package Manager) is gaining traction; otherwise CMake + Make. Spack for scientific computing.
  • COBOL — none; the source IS the deliverable. JCL on mainframes. GCC’s gcobol uses standard GCC tooling.
  • AdaAlire (modern, 2020+) + GPRBuild for builds. AdaCore tools. Crates.io equivalent at alire.ada.dev.
  • PascalFree Pascal Package Manager (FPMake) + Lazarus packages. Less centralized.
  • TclTEA (Tcl Extension Architecture), Teapot, Tcllib. Less centralized than modern languages.

4. Compiler-as-build-system (write your build in your language)

  • Zigbuild.zig is a Zig program. The compiler interprets it.
  • Odin — build scripts in Odin.
  • Vv build introspects the project; v.mod.
  • sbtbuild.sbt is Scala source.
  • SCons — Python-as-build (cross-language; not in 51).
  • JuliaProject.toml is declarative, but build customization is done in Julia code (build.jl scripts).

5. Image-based / interactive

  • Smalltalk (Pharo) — Iceberg for git integration; Metacello for package management; the image IS the deployment artifact. Tonel format for source on disk.
  • Common LispQuicklisp (community registry, ~3000 systems) + ASDF (build/system definition). Image saved via save-lisp-and-die (SBCL).
  • Racketraco pkg (built-in) + raco build/test. PLT/community catalogs.
  • Scheme — implementation-specific. Chicken: chicken-install + eggs. Racket has its own. Guile uses guile-utils + Guix.

6. Theorem-prover toolchains

  • LeanLake (Lean’s native build/package manager). lakefile.lean (or lakefile.toml). mathlib4 is the reference project.
  • Coq (Rocq)dune (cross-language OCaml build) + opam (OCaml package manager) for source-level Coq packages. OPAM Coq Archive.
  • Agdaagda --build + --library; libraries via agda-lib files. Less polished than Lean’s Lake.
  • Idrispack package manager (de facto for Idris 2). idris2 --build for builds.

7. Shell / scripting / “just run it”

  • Bash — none; copy script, chmod +x, run. shellcheck for linting, shfmt for formatting. Versioning is OS package version of bash itself.
  • PowerShellPowerShellGet / PSResourceGet (modern, 2024+) for modules. Install-Module. PSGallery is the registry.

8. Database / declarative

  • SQL — schema-versioning tools (Flyway, Liquibase, sqlx-migrate, dbmate, atlas) play this role; ORM/query builders (Prisma, Drizzle, Diesel, ActiveRecord, SQLAlchemy, Ecto) on top.

9. Logic programming

  • PrologSWI-Prolog Pack manager (pack_install/1) + community packs. SICStus has its own.
  • Erlangrebar3 (modern) + Hex.pm (shared with Elixir). rebar.config. mix from Elixir is interoperable.

Per-language quick reference

LanguageVersion mgrPackage mgrBuild/testLinterFormatter
Pythonuv (or pyenv)uv / pippytest, hatch, setuptoolsruff, pylint, mypyruff format, black
JavaScriptnvm, fnm, volta, misepnpm / npm / yarn / bunvitest, jest, node:testeslint, biomeprettier, biome
TypeScript(inherits JS)(inherits JS) + tscvitest, jest, tsxtsc, eslint, biomeprettier, biome
Javasdkman, asdf, jenvMaven / Gradle / MillJUnit 5, TestNGCheckstyle, SpotBugs, ErrorPronegoogle-java-format, palantir
Cos pkgvcpkg / Conan / SpackCMake, Meson, Makeclang-tidyclang-format
C++os pkgConan / vcpkgCMake, Meson, Bazel, Build2clang-tidy, cppcheckclang-format
[[Languages/csharp|C#]]dotnetNuGet (via dotnet)dotnet test (xUnit/NUnit/MSTest)Roslyn analyzersdotnet format
Gogo install (or asdf)go modulesgo test, gotestsumgo vet, staticcheck, golangci-lintgofmt, goimports
RustrustupCargo + crates.iocargo test, criterion (bench)clippyrustfmt
Swiftswiftly, asdfSPMswift test, XCTestswift-lint, SwiftLintswift-format, SwiftFormat
Kotlinsdkman, kotlincGradle / Mavenkotlin-test, JUnitdetekt, ktlintktfmt, ktlint
Rubyrbenv, rvm, miseBundler + RubyGemsRSpec, MinitestRuboCop, StandardRuboCop, Standard
PHPphpenv, asdfComposer + PackagistPHPUnit, PestPHPStan, Psalm, PHP_CodeSnifferPHP-CS-Fixer
Scalasdkman, coursiersbt / Mill / Maven / GradleScalaTest, MUnit, ZIO TestScalafixScalafmt
Dartdart pub globaldart pub + pub.devdart test, flutter testdart analyzedart format
Elixirasdf, miseMix + HexExUnitCredo, Dialyzermix format
HaskellghcupCabal / Stack + Hackage / Stackagehspec, tasty, QuickCheckHLintormolu, fourmolu, brittany
Clojure(jvm)deps.edn / Leiningen + Clojarsclojure.test, kaochaclj-kondocljfmt, zprint
[[Languages/fsharp|F#]]dotnetNuGetdotnet test (xUnit), ExpectoF# analyzersFantomas
Lua(luajit/lua install)LuaRocksbustedluacheckStyLua
Rrenv, riginstall.packages + CRAN/Bioconductortestthatlintrstyler
JuliajuliaupPkg + General registryTest stdlib, Aqua.jlJET.jl, ExplicitImports.jlJuliaFormatter.jl
Zig(zig install)build.zig + zon fileszig build test(built into compiler)zig fmt
NimchoosenimNimbleunittest, testamentnimble checknimpretty
Crystalasdf, miseShardsspecAmebacrystal tool format
OCamlopamopam + dunealcotest, ppx_inline_testmerlin (LSP)ocamlformat
Perlplenv, perlbrewcpanm + CPAN, cartonTest::More, Test2Perl::Criticperltidy
Erlangasdf, kerlrebar3 + Hex.pmEUnit, CommonTestdialyzer, elviserlfmt
Racket(racket install)raco pkgrackunit(built-in)(built-in)
Common Lisp(impl install)Quicklisp + ASDFFiveAM, Parachute, RoveSBCL warnings(none std)
Schemeimpl-specificimpl-specific (eggs etc.)impl-specificimpl-specificimpl-specific
Fortranos pkgFPM + SpackFPM test, pFUnit(compiler warnings)findent, fprettify
COBOLos pkgnone(build script)(compiler)none
AdaAlireAlire (alr)AUnit, GNATtestGNATcheck, GNATprovegnatpp
Pascalos pkgFPMake, Lazarus packagesfpcunit(compiler warnings)jcfsettings
Prologos pkgSWI pack_installplunit(built-in)(impl-specific)
Tclos pkgTEA / Teapot / Tcllibtcltesttclcheckerindent (style/)
GroovysdkmanGrape (@Grab) / Gradle / MavenSpock, JUnitCodeNarc(Gradle/Maven plugins)
Bashos pkgnonebats, shunit2shellcheckshfmt
PowerShellos installerPSResourceGet (modern) / PSGetPesterPSScriptAnalyzerPSScriptAnalyzer
SQL(engine-specific)none for the language; migration tools (Flyway, Liquibase, atlas)(engine + dbunit/pgTAP)sqlfluffsqlfluff, pg_format
Vv upvpmv testv vetv fmt
Odingit pull(none/community pkg)build via Odin code(compiler warnings)(community)
Roc(roc install)URL/hash imports (no central registry yet)roc testroc checkroc format
Gleamasdf, miseMix-compatible Hex.pmgleam test(compiler)gleam format
Ponyponyupcorralponytest (built-in)(compiler)(none official)
Idris(manual)packidris2 --check(compiler)(none)
LeanelanLake + Reservoir registryLake test targets(kernel checks)(none std)
Coq (Rocq)opamopam + Coq archivedune(kernel checks)(none std)
Agda(cabal/stack)agda libraries(none std)(kernel checks)(none std)
Smalltalk (Pharo)(image installer)Metacello + IcebergSUnit(image lints)(image-based)

Decision rubric

What makes good tooling?

  • Single source of truth for dependencies (one file, not five).
  • Reproducible builds via lockfile + content-addressed cache.
  • Fast incremental rebuilds (Cargo, esbuild, ts-go, mold linker).
  • No global state pollution — projects are isolated (uv venvs, npm node_modules, cargo target).
  • Easy publish path — one command, predictable URL.
  • Cross-platform out of box (Cargo on Win/Mac/Linux/Wasm; Zig cross-compiles everywhere).
  • Speaks your team’s other tools (git, CI, IDE, container builds).

Best-in-class examples to imitate:

  • Cargo (Rust) — the gold standard for unification.
  • Mix (Elixir) — the unsung gold standard. Same DX as Cargo for BEAM.
  • uv (Python) — Astral’s resolver wrote the chapter on “10× faster” in the resolver space.
  • Pkg (Julia) — sysimage caching is unique; project envs work cleanly.
  • go toolchain — minimal-flag philosophy, but underpowered for some monorepo cases.
  • dotnet CLI — comprehensive; the XML project files are the wart.

Avoidable failure modes:

  • Mixing build systems (Maven + Gradle) without a clear ownership rule.
  • Per-developer global state (legacy CL Quicklisp, Python pre-pyenv).
  • Missing lockfiles (Common Lisp, classic Lua, Bash).
  • Network-dependent builds (no offline cache; many CI horror stories).
  • “Vendor everything by copying source” without a tool to update it (early Odin, classic C).

Edge cases & nuances

  • Python’s “10 ways to install” problem — finally won by uv (Astral, written in Rust). pip remains the install backend; pyproject.toml + uv.lock the metadata. PEP 723 inline metadata gives single-file scripts pinning.
  • Java’s three-way split — Maven (declarative XML, plugin-rich, slow), Gradle (imperative, fast incremental, debugging hell), Mill (Scala-based challenger). Pick by team familiarity; Maven for libraries, Gradle for apps is the conventional choice.
  • JS bundler turnover — esbuild (Go, fast) + Vite (uses esbuild dev, Rollup prod, winning), Rollup (libraries), webpack (legacy), Turbopack (Next.js), Bun (runtime+bundler). 2026 status: Vite + Vitest is the default for new projects.
  • Rust’s Cargo.lock rule — commit it for binaries, don’t commit it for libraries. Almost every other language gets this wrong.
  • Java’s Reproducible Builds — JEP 392 made javac builds reproducible. Few teams use it.
  • Common Lisp’s Quicklisp model — single curated dist, monthly snapshots. Less Cathedral than CRAN, less Bazaar than crates.io. Ages well; not innovating.
  • Lean’s Lake + Reservoir is the most modern of the theorem-prover toolchains.
  • Zig’s zig cc is a drop-in C/C++ compiler with cross-compilation built in. Effectively makes Zig a build tool for C.

Cross-references

For per-language detail, see each note’s Getting started (install + project layout) and Ecosystem (testing/doc tools) sections. The 51 individual notes are linked from _index.

Citations