You install Nim, run nimble install jester, and everything works — until you clone a second project that pins a different compiler version and needs a dependency that conflicts with the first. Then you discover that “the Nim toolchain” is actually three separate programs with overlapping names, and the official docs assume you already know which one you are supposed to be using.

They are Nimble (1,409★, pushed 2026-10-23), Choosenim (136★, 2026-01-09), and Atlas (153★, 2026-10-24). They solve three different problems — package management, compiler version management, and workspace isolation — and the most common Nim setup mistake is treating them as alternatives when two of them are complements.

TL;DR: The 30-Second Verdict

  • Always install Choosenim first. It manages which Nim compiler you are running. Without it you are stuck on whatever your distro shipped, usually two minor versions behind.
  • Use Nimble for everyday nimble install / nimble build work. It is the default, it ships with Nim, and its .nimble file format is the ecosystem standard.
  • Reach for Atlas when you need a self-contained deps/ workspace with pinned git revisions — CI reproducibility, or working on several projects that would otherwise fight over ~/.nimble/pkgs.
  • The sane default for 2026: Choosenim for the compiler, Nimble for libraries, Atlas for projects that must build identically on three machines.

What Each Tool Actually Owns

The naming overlap is the root of the confusion, so here is the split in one paragraph each.

Choosenim is a version manager — think nvm or pyenv. It downloads Nim releases, switches the active toolchain, and rewrites the nim/nimble shims in ~/.nimble/bin. It does not install packages.

Nimble is the package manager and a thin build front-end. It resolves the requires block in a .nimble file, installs packages into a per-user store (~/.nimble/pkgs2 on modern versions), runs nimble tasks, and wraps nim c for nimble build.

Atlas is a package cloner with isolated workspaces. Instead of a global package store, it clones dependencies into a project-local deps/ directory and generates the path configuration so the compiler sees exactly those copies. Nim 2.0 ships with Atlas, and the project describes it as the intended future of dependency handling for large projects.

Quick Comparison Table

DimensionChoosenimNimbleAtlas
Problem solvedCompiler versionsPackages + tasksIsolated dependency workspaces
ScopeUser-globalUser-global storePer-project
GitHub stars1361,409153
Last commit (2026)2026-01-092026-10-232026-10-24
Install methodBootstrap scriptShips with NimShips with Nim 2.0+ / bootstrap script
LockfileN/Animble.lock (with --lock)Git revisions in nim.cfg / deps/
Multiple compiler versionsYesNoNo
Vendored dependenciesNoNoYes (deps/)
Typical commandchoosenim stablenimble install pkgatlas use pkg
Best forEvery Nim developerApplication dependenciesCI, monorepos, reproducible builds

Decision Matrix: Pick By Use Case

Your situationUseWhy
Fresh machine, no Nim installedChoosenimOne command gets a current stable toolchain
Need to test a library against Nim 2.0 and 2.2ChoosenimSwitch versions per shell, no rebuild of packages
Normal app with five dependenciesNimbleDefault path, least friction
Air-gapped build serverAtlasdeps/ can be vendored into the image
Two projects requiring incompatible versions of the same libAtlasSeparate deps/ trees per project
Library author publishing to the package directoryNimble.nimble metadata is the publishing contract
Reproducing a bug report from a userAtlas + exact git revisionsClones the same commits, not “latest semver”

Choosenim — The Layer Everyone Skips

If you installed Nim from apt, you are running a snapshot from your distribution’s release cycle. That is usually fine for tutorials and consistently wrong for real projects, because Nim’s standard library and macros evolve between minor versions, and packages declare requires "nim >= 2.0.0" for a reason.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# Bootstrap Choosenim (Linux/macOS)
curl -sSf https://nim-lang.org/choosenim/init.sh -o init.sh
sh init.sh -y
export PATH="$HOME/.nimble/bin:$PATH"

# Install and switch compilers
choosenim stable          # latest stable release
choosenim 2.2.0           # pin an exact version
choosenim show            # what is active right now
nim --version
1
2
# Update the version manager itself, not the compiler
choosenim update self

The export PATH line is not optional ceremony: Choosenim installs into ~/.nimble/bin, and if /usr/bin/nim comes first in your PATH you will keep running the distro compiler while believing you switched. Verify with which nim — it must resolve inside ~/.nimble/bin.

Where Choosenim fails you: it is the least actively developed of the three (last push January 2026), it manages compilers only, and it does not isolate per-project compiler pins. If you have one project needing Nim 2.0 and another needing 2.2, you will be switching by hand or by direnv hook. That is a real gap, not a documentation problem.

Nimble — The Default, and Mostly Right

Nimble reads a .nimble file, resolves dependencies, and installs them into a shared per-user store. For a single project this is exactly what you want.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# myapp.nimble
version       = "0.3.0"
author        = "Platform Team"
description   = "Internal settlement service"
license       = "MIT"
srcDir        = "src"
bin           = @["myapp"]

requires "nim >= 2.0.0"
requires "jester >= 0.6.0"
requires "norm >= 2.5.0"
requires "karax#head"

task test, "Run the test suite":
  exec "nim c -r --outdir:build tests/all_tests.nim"

task release, "Static release build":
  exec "nim c -d:release --opt:speed -o:build/myapp src/myapp.nim"
1
2
3
4
5
6
7
8
9
nimble install                 # resolve and install declared dependencies
nimble install jester@0.6.0    # pin a version
nimble install jester@#head    # track the default branch (reproducibility hazard)
nimble install --depsOnly      # dependencies only, skip installing this package
nimble list -i                 # what is installed
nimble list jester --ver       # available versions
nimble deps                    # dependency tree as the resolver sees it
nimble test
nimble release

Two workflows are worth internalizing. nimble develop links a local checkout of a dependency into your project’s dependency graph, so you can patch a library and see the change without reinstalling — this is the single biggest quality-of-life feature Nimble has for anyone who files upstream patches. nimble lock / nimble.lock pins resolved versions and commit hashes; commit the lockfile, or your CI will silently resolve different code next week.

Where Nimble fails you: the package store is shared. Install project A which wants norm 2.5.0, then project B which wants norm 2.7.0, and you are in for a confusing afternoon of path precedence. nimble install pkg@#head compounds it by tracking a moving branch. This is not a bug in Nimble so much as the design cost of a global store — and it is exactly the hole Atlas fills.

Atlas — Isolated Workspaces for Projects That Must Reproduce

Atlas abandons the global store. Dependencies are cloned into deps/ next to your project, and the compiler is pointed at those copies.

1
2
3
4
5
6
7
8
9
# Nim 2.0+ ships atlas; otherwise bootstrap it
curl -fsSL https://raw.githubusercontent.com/nim-lang/atlas/HEAD/install.sh | bash -

# Inside a project directory
atlas use jester                 # clone latest into deps/ and wire the paths
atlas use "https://github.com/treeform/pixie"    # clone from an explicit URL
atlas install                    # clone everything the project currently references
atlas link                       # link a local checkout (dev workflow)
atlas env                        # print the environment atlas exports

The generated configuration lives in config.nims / nim.cfg pointing at deps/, which means nim c src/myapp.nim just works and git status shows precisely which dependency revisions your build used — because they are checked out at known commits, not resolved from a range.

1
2
3
4
5
6
# A reproducible build in CI: pin the compiler with choosenim, deps with atlas
curl -sSf https://nim-lang.org/choosenim/init.sh -o init.sh && sh init.sh -y
export PATH="$HOME/.nimble/bin:$PATH"
choosenim 2.2.0
atlas install
nim c -d:release --opt:speed -o:build/myapp src/myapp.nim

Where Atlas fails you: it is the newest and least documented of the three, its command surface is still shifting, and mixing Atlas workspaces with Nimble-installed global packages produces “which copy am I compiling?” confusion. Pick one dependency strategy per project and write it in the README — do not let contributors half-adopt Atlas.

And because deps/ is a plain directory, you can vendor it into a container image and build with network access disabled:

1
2
3
4
5
6
FROM nimlang/nim:latest
WORKDIR /app
COPY . .
# deps/ committed or mounted from the build context keeps this offline
RUN nim c -d:release --opt:speed -o:/usr/local/bin/myapp src/myapp.nim
CMD ["/usr/local/bin/myapp"]

Pitfalls and Migration Traps

$PATH order silently defeats Choosenim. If which nim is /usr/bin/nim, you are not using the compiler you think you are. Put ~/.nimble/bin first in both interactive and non-interactive shells (CI often sources only .profile, never .bashrc).

Nimble’s store is per-user, not per-project. Two projects with conflicting ranges will fight. Check nimble deps before blaming the library; the resolver is usually telling the truth.

@#head is not a version pin. It is “whatever the default branch is right now”. Use a tag or a commit hash in anything that must build again next month.

Lockfiles only help if you commit them. nimble.lock and deps/ are equally worthless if they are gitignored. Both should be in version control for applications (libraries should not commit lockfiles).

Release builds need -d:release explicitly. nim c produces a debug build by default with bounds checking and stack traces. nimble build respects -d:release passed through, but a plain nim c in your Dockerfile will ship a slow binary with debug info.

Docker image tags drift. nimlang/nim:latest moves under you; pin a minor tag and update deliberately. The same applies to Atlas: it ships with Nim 2.0 and may be older than the standalone release.

Cross-compilation is not handled by any of the three. Use --os/--cpu flags plus a matching C toolchain; do not expect nimble or atlas to fetch one for you.

FAQ

Do I need both Choosenim and Nimble? Yes, in practice. Choosenim manages the compiler version, Nimble manages packages. They install into the same ~/.nimble/bin, which is why the PATH ordering matters.

Is Atlas replacing Nimble? Not yet. Atlas handles dependency cloning and workspace isolation; Nimble still owns package metadata, tasks, and publishing to the package directory. Atlas can consume nimble packages, so the two coexist rather than compete.

How do I run two projects with different Nim versions? Install both versions with Choosenim and switch per shell (choosenim 2.0.14 / choosenim 2.2.0). A direnv hook that runs choosenim $(cat .nimbus-version) is the common workaround; there is no per-directory automatic switch built in.

Where are packages stored? Modern Nimble uses ~/.nimble/pkgs2 per user. Atlas stores clones in <project>/deps/. On Windows the Nimble store lives under %USERPROFILE%\.nimble.

Can I use a private git dependency? Yes with Nimble (requires "https://git.internal/team/lib.git") and with Atlas (atlas use <url>), provided your git credentials or SSH agent are configured for the build user.

What is the minimum viable setup for a new project? Choosenim for the compiler, a .nimble file with pinned ranges, a committed lockfile, and nimble test/nimble build tasks. Add Atlas only when you actually hit cross-project version conflicts or need offline vendoring.

For how Nim compares with the other systems languages before you commit to the toolchain, see our V vs Odin vs Nim comparison. If you are building a service rather than a CLI, the Nim web frameworks comparison covers what runs on top of this toolchain. And for a second opinion on toolchain version managers, our Julia juliaup/pkg/Revise breakdown solves the same compiler-pinning problem in a different ecosystem.


💰 想测试你的市场判断力?我用 Polymarket 做预测市场交易——这是全球最大的预测市场平台,从大选结果到技术监管时间线,什么都可以押注。和赌博不同,这是真正的信息市场:你懂的信息越多,胜率越高。我靠预测技术相关事件的走向已经赚了不少。用我的邀请链接注册:Polymarket.com