Engine binary resolution
rift.spawn() needs a runnable rift engine binary. There is no postinstall script —
npm install never touches the network or the filesystem beyond what npm itself does. Resolution
happens on demand, at first use: the first time you call rift.spawn() (or run npx rift-fetch
explicitly), the SDK works through a fixed order and stops at the first hit.
Resolution order
- Explicit override.
opts.binaryPath(passed torift.spawn({ binaryPath })), or else theRIFT_BINARY_PATHenvironment variable, used as-is if the path exists on disk. PATHlookup. The first ofrift-http-proxy/rift/mbfound onPATH(rift-http-proxy.exe/rift.exe/mb.exeon Windows) — but only if it--version-probes as Rift.mbis checked because Mountebank-migration setups commonly have it onPATH, but Homebrew’s Mountebank also installs a binary namedmb— running it in place of Rift would be silently wrong. Rift reportsrift <version>for--version; Mountebank reports a bare<version>. A candidate whose output doesn’t match, or that fails to run at all, is skipped (not treated as an error) and the next candidate is tried. This means a Mountebankmbsitting onPATHis skipped, not run.- Local version cache. A previously-downloaded binary for the resolved version, under the
cache directory (
~/.cache/rift-node/binaries/rift-<version>/by default). - Air-gap check. If
RIFT_OFFLINEorRIFT_SKIP_BINARY_DOWNLOADis set, resolution stops here and throws — it never falls through to a download. The thrown error names the resolved version and tells you to setRIFT_BINARY_PATHto an existing binary, install one toPATH, or unset the air-gap override. - Download. Only reached if nothing above matched and the environment isn’t air-gapped: fetch the release archive for the resolved version, verify its checksum, extract it, and cache the binary for next time.
Steps 1–3 never touch the network. Only step 5 does, and only after steps 1–4 have all missed.
Environment variables
Faithfully reproduced from the rift-core package README:
| Variable | Applies to | Purpose |
|---|---|---|
RIFT_BINARY_PATH |
engine binary | explicit binary path override; skips PATH/cache/download |
RIFT_FFI_LIB |
cdylib | explicit cdylib path override; skips cache/download, no checksum (you own the file) |
RIFT_CACHE_DIR |
cdylib | overrides the cache root (defaults to XDG_CACHE_HOME, then %LOCALAPPDATA% on Windows, else ~/.cache) |
RIFT_DOWNLOAD_URL |
both | alternate release mirror base (also the FFI manifest base for the cdylib) |
RIFT_MIRROR_URL |
engine binary | alternate release mirror base (binary only; RIFT_DOWNLOAD_URL wins if both are set) |
RIFT_OFFLINE / RIFT_SKIP_BINARY_DOWNLOAD |
both | air-gapped mode: never reach the network; resolution throws with manual-install instructions (file name, release URL, and the exact cache path to place it at) if nothing local is found |
RIFT_SKIP_CHECKSUM |
engine binary only | opt out of a missing (not mismatched) checksum sidecar — not available for the cdylib |
Two asymmetries are load-bearing, not oversights:
RIFT_CACHE_DIRis documented against the cdylib cache; the engine binary’s cache root is currently fixed at~/.cache/rift-node/binariesand isn’t reconfigurable via this variable.RIFT_SKIP_CHECKSUMonly exists for the engine binary. The cdylib’s checksum check has no opt-out at all — a corrupt library isdlopen‘d in-process (a memory-safety hazard), whereas a corrupt binary merely fails toexec.
A missing checksum sidecar (as opposed to a checksum that fails to verify) is fatal for the binary
too, unless RIFT_SKIP_CHECKSUM is set — downloads never run unverified silently by default.
Air-gapped / offline usage
Set RIFT_OFFLINE=1 (or RIFT_SKIP_BINARY_DOWNLOAD=1) to guarantee resolution never reaches the
network. In that mode, resolution still tries the explicit override, PATH, and the local cache —
only the final download step is disabled. If none of those hit, the thrown error is actionable: it
names the version that was being resolved and tells you to either point RIFT_BINARY_PATH at an
existing binary, install one onto PATH, or unset the air-gap variable. Run npx rift-fetch ahead
of time (e.g. as part of building an air-gapped image, or warming a CI cache) so the binary is
already in the local cache by the time rift.spawn() runs air-gapped.
Alpine / musl
On Linux, the release archives ship both glibc and musl builds. The resolver detects the running
C library flavor and selects the *-unknown-linux-musl target on musl hosts (e.g. Alpine) instead
of the default *-unknown-linux-gnu — the glibc build won’t run there without gcompat. Detection
prefers Node’s own report (process.report’s glibcVersionRuntime field, present only on glibc
builds); its absence is corroborated by checking for /etc/alpine-release as a secondary signal.
This only matters for the host actually running rift.spawn() — cross-fetching a binary for a
different platform (e.g. npx rift-fetch preparing an image for another target) requires passing
the target’s libc explicitly, since the host’s own probe can’t observe a platform it isn’t running.
Version pinning
The version resolved when nothing pins one explicitly is DEFAULT_ENGINE_VERSION, currently
v0.15.0 — the latest Rift engine release this SDK is tested against. This is deliberately a
separate value from two other version markers that can look similar but serve different
purposes:
DEFAULT_CDYLIB_VERSION(currentlyv0.12.0) — the default version resolved for the embedded transport’slibrift_fficdylib. It’s pinned tominEngineVersion, not to the latest release, because the FFI ABI is the compatibility-sensitive surface for in-process embedding: resolving anything newer than the SDK’s floor risks an ABI the embedded transport hasn’t validated.package.json’sminEngineVersion(currently0.12.0) — the floorrift.connect()’s version preflight enforces against a remote engine’s reported/configversion. It only rises when the SDK starts depending on newer engine behavior;DEFAULT_ENGINE_VERSIONmoves independently and is always>=it.
If you need a specific engine version for rift.spawn(), pass { version } rather than relying on
the default.