fnm
fnm
Configuration#
Windows#
Caching the completion script#
fnm completions emits roughly 42 KB and costs about 30 ms to regenerate on every startup.
The output only changes with the fnm binary, so cache it:
fnm env cannot be treated this way — it has to run every time to create the multishell
directory for the current session.
multishell directories pile up#
Every shell fnm initialises leaves a directory under %LOCALAPPDATA%\fnm_multishells, and
Windows never cleans them up on exit, so they accumulate indefinitely.
They are junctions, so they take almost no space themselves, but the sheer count slows any traversal down. Clearing the stale ones:
Deleting a junction does not touch its target — the node installs under
%APPDATA%\fnm\node-versions are safe. Beware when sizing that folder: Get-ChildItem -Recurse follows junctions and counts the same node install over and over, which makes it look
like several GB when it is not.
macOS accumulates them too, under ~/.local/state/fnm_multishells. Those are symlinks, so
du -sh reports 0B — no disk cost, but the entry count grows without bound.
Cleaning by PID beats cleaning by age#
The directory name is <PID>_<timestamp>, so you can check whether the shell that created it is
still alive. That way today's open sessions are never caught in the sweep:
PIDs do get reused; the worst case is skipping one stale entry, never deleting a live one.
The check has one blind spot, though: the ancestor exited but a descendant is still running.
Child processes inherit their parent's PATH, so a directory whose creator is long gone may still
be referenced by something long-lived — an editor's integrated terminal, an agent session, a
tmux/herdr pane. Delete it and node simply vanishes inside those processes:
The safe version requires both conditions — process gone and older than a day:
Getting it wrong is not fatal: new shells regenerate their own entry, and the affected processes just need a restart.