# A fresh resolve is a different environment.

> Renest reinstalls your Python dependencies on every rebuild, but it never re-decides them. A nest stores the dependency lock from the environment that worked, and a restore installs exactly that list with uv, with no new resolution step.

Canonical page: https://renest.ai/docs/reresolving-deps-is-a-different-env

<h2 id="solver">A resolver's answer depends on the state of the package index</h2>

<p>When you type <code>pip install -r requirements.txt</code>, you are not handing the
machine a list of software. You are handing it a <em>constraint problem</em> — "torch,
some numpy that torch tolerates, whatever these forty transitive packages agree on" —
and asking a solver to find versions that satisfy it. The solver's answer depends on an
input nobody writes down: <strong>the state of the package index at the moment you
ask.</strong></p>

<p>Run the same file in March and in September and the solver is solving two different
problems, because the world it solves against has moved: new releases came out, one got
yanked, a transitive dependency loosened a bound. Both runs succeed. Both print the same
package names. They are not the same environment.</p>

<h2 id="names">A fresh resolve gives you a new environment under the old name</h2>

<p>This is why "I reinstalled everything exactly like before and now it behaves
differently" is such a common — and such a maddening — failure. Nothing you did changed.
The <em>requirements file</em> didn't change. But a requirements file was never a
description of your environment; it was the <em>question</em> that produced it, and the
same question now yields a different answer. What a fresh resolve gives you is
<strong>a new environment wearing the old environment's name</strong> — close enough to
load, different enough to break subtly, in the numerics, in a default, in some corner
the release notes didn't think worth mentioning.</p>

<h2 id="answer">A nest stores the dependency lock, not the requirements file</h2>

<p>A nest records the <strong>answer</strong>: a dependency lock taken from the
environment that actually worked, plus the Python version it ran on. If the environment
has a lock file, that file is stored as-is. If it doesn't, Renest reads which
packages are installed there, at which versions, and stores that list.</p>

<p>Some packages exist only as vendor builds, like a torch built for one CUDA version
(<code>torch==2.4.1+cu124</code>). The public index doesn't carry those, so by default
packing records a direct download address for each of them, with its fingerprint whenever the index
supplies one. Pack
with <code>--offline</code> and those addresses are skipped; the nest is then marked as
not rebuildable on another machine, and a restore says so up front.</p>

<h2 id="reinstall">A rebuild reinstalls the locked list without re-resolving it</h2>

<p>Here is the distinction this page exists for, because the two sentences sound alike
and are opposites in practice:</p>

<ul>
  <li><strong>Renest reinstalls your dependencies on every rebuild.</strong> True. A
  rebuild is not a disk image; packages are installed fresh on the target machine.</li>
  <li><strong>Renest re-resolves your dependencies on every rebuild.</strong> False —
  and if it were true, everything on this page would apply to us.</li>
</ul>

<p>The restore creates a fresh environment for the recorded Python version. It then hands
the stored lock to uv in the mode that installs exactly the listed packages. Nothing
gets solved: uv's job is reduced to <em>fetch these exact versions and put them in
place</em>. The decision was made once, on the machine where your setup worked, and the
lock carries that decision to the new one.</p>

<p>Some honest limits apply:</p>

<ul>
  <li>A lock pins <em>versions</em>, which is not the same as pinning bytes. Packages
  that carry a recorded fingerprint are checked against it. The rest are fetched by name and version from the package index, and nothing compares their bytes. A package installed from git or a direct download address is the exception: the wheel that was installed is stored in the nest, so a restore installs that wheel and needs neither git, a compiler nor that website.</li>
  <li>A lock can't bring back a package that has vanished from its source. There is one
  case where the restore does substitute. If the install fails because a pinned vendor
  download has been taken down, the restore retries once with the plain version of that
  package (the same version number without the vendor tag). It warns you when that
  happens, and your stored lock is not changed.</li>
  <li>Some packages, such as flash-attn, have to be compiled for the card that runs them.
  Packing warns about these: the file check can't vouch for them.</li>
</ul>

<p>Environments don't only break when someone changes them. They also break when someone
<em>re-derives</em> them and assumes derivation is deterministic. It isn't — so we keep
the derived thing.</p>
