When is `python -m venv --system-site-packages` the right call, and what does it cost?
answer
- One boolean line in a small config file
- The base packages become visible, not merged
- Order decides which copy wins
- Reproducibility is what you trade away
- include-system-site-packages = true
basics
~20 sIt writes include-system-site-packages = true into pyvenv.cfg, appending the base installation's site-packages to sys.path after the environment's own. Use it to reuse a binary package the base interpreter already has; it costs you reproducibility and clean isolation.
solid answer
~50 sThe flag flips one line in `pyvenv.cfg`, and that line makes the base installation's `site-packages` visible to the environment. Ordering matters: the environment's own directory comes first on `sys.path`, so anything you install locally shadows the base copy, while everything else stays importable. The honest use case is a heavy binary package the platform already provides and that you cannot reasonably install from an index — bindings shipped by an OS package manager, or an accelerator-linked build produced by the vendor. The cost is that the environment is no longer described by its requirement pins: the same pins on a host with different system packages give a different `sys.path`, an upgrade of a system package silently changes the environment, and you cannot uninstall a base-installed distribution from inside it. Default to the isolated form and treat the flag as a deliberate, documented exception.
code
console · 3 linespython3 -m venv --system-site-packages .venv-shared
grep include-system-site-packages .venv-shared/pyvenv.cfg
.venv-shared/bin/python -c "import sys; print([p for p in sys.path if p.endswith('site-packages')])"go deeper
Know that the default environment is isolated and that this flag deliberately removes part of that isolation. You are unlikely to need it; recognising it in someone else's build script is the useful part.
Explain the mechanism: one boolean in pyvenv.cfg, the base site-packages appended after the environment's own, so local installs shadow rather than replace, and an uninstall of a base package is refused.
Show the judgement: accept it for a platform-provided binary dependency that cannot reasonably be installed from an index, and reject it wherever reproducibility matters, since the environment then depends on host state no pin file records.
Treat it as a policy question. Decide whether any service may depend on host-installed packages, how such a dependency is declared and verified on every host, and what the alternative is when a vendor ships only a system-level build.
### What the flag actually does `python -m venv --system-site-packages .venv` differs from a plain creation in exactly one place: the line `include-system-site-packages` in `pyvenv.cfg` reads `true` instead of `false`. There is no other change to the directory, and because the interpreter reads that file at every startup, editing the line by hand on an existing environment has the same effect as creating it with the flag. That is a useful thing to know both because it makes the mechanism concrete and because it lets you check what a mystery environment on a server is doing without re-reading the deployment scripts. ### The effect on sys.path With the flag on, `site` appends the base installation's `site-packages` directory to `sys.path` *after* the environment's own. The order is the whole story: * A distribution installed into the environment wins, because its directory is searched first. * A distribution present only in the base installation is importable, because its directory is still on the path. * Installing into the environment therefore does not remove the base copy; it shadows it, leaving two versions on disk and first-match-wins resolution between them. That shadowing is where the surprises live. `pip list` inside the environment now reports base-installed distributions alongside your own; a freeze of that list is not a description of the environment you meant to build; and asking to uninstall a base-installed distribution from inside the environment is refused, because the files live outside it. ### When it is genuinely the right call * **A platform-provided binary package.** Some bindings — GUI toolkits, hardware or system-service libraries, vendor builds linked against a specific accelerator or driver stack — are shipped by the operating system's package manager or by the hardware vendor, and building an equivalent from an index is anywhere from painful to impossible. Letting the environment see the base installation is far less bad than abandoning environments altogether. * **A deliberately shared, expensive base layer.** On a constrained machine, or in a controlled image where a large compiled dependency is installed once and every environment is a thin overlay on top of it, the tradeoff can be a conscious one. * **A short-lived diagnostic environment.** When you want an isolated place to install one tool but still want everything the host already has, the flag saves a reinstall you were not going to keep. ### When it is the wrong call Anything you intend to reproduce. An environment created with the flag is not determined by its requirement pins alone — it is determined by the pins *plus the state of the machine*. Two hosts with the same pin file and different system packages produce different behaviour, and a routine upgrade of a system package changes an application's dependencies without anyone editing the application. That defeats the reason environments exist. It also breaks the mental model your teammates have: when someone reports that an import works on the server and fails in CI, this flag is a leading suspect, and it is invisible unless you read `pyvenv.cfg`. ### The practical stance Default to the isolated form; a plain `python -m venv .venv` is right nearly all the time. Where the flag is genuinely needed, make it explicit — record it in the command that builds the environment, note *which* base-provided package it exists for, and treat that package as a documented host requirement rather than an accident. If the only reason for reaching for it is that installing something from an index was slow or awkward, that is a packaging problem to solve, not a reason to give up isolation. One last detail worth carrying: since CPython 3.12 a newly created environment contains only `pip` — `setuptools` and `wheel` are no longer bootstrapped into it. Teams sometimes discover this while migrating an old build script, reach for `--system-site-packages` so the environment can see a system-installed `setuptools`, and quietly give up isolation to paper over a build-requirement declaration they should have written instead. ### Spotting it on a running system Because the setting lives in a file the interpreter reads at startup, you can always answer "is this environment isolated?" without trusting anyone's memory of how it was built. Print `pyvenv.cfg` from `sys.prefix` and read the boolean, or list the `site-packages` entries on `sys.path` and see whether one of them sits under `sys.base_prefix` rather than under `sys.prefix`. Both are one-liners, both work under a service manager where no shell was ever involved, and both belong in the first minute of investigating an import that behaves differently on two hosts.
- With the flag on, which copy of a distribution wins if it exists both in the environment and in the base installation?The environment's copy. Its `site-packages` is placed before the base installation's on `sys.path`, so the first match wins and the base copy is shadowed rather than replaced. Both remain on disk, which is exactly why diagnosis gets harder: `pip list` shows a mixture, and printing a package's `__file__` is often the quickest way to prove which one was actually imported.
- Can you uninstall a base-installed distribution from inside such an environment?No. Its files live outside the environment, so the installer declines to remove them — and on a system interpreter they may be owned by the OS package manager, where removing them would be actively harmful. The only move available from inside is to install your own version into the environment so it shadows the base one, which leaves two versions on disk and is a good reason to prefer an isolated environment in the first place.
- Can you turn the behaviour on or off for an environment that already exists?Yes, by editing the `include-system-site-packages` line in `pyvenv.cfg`; the interpreter reads that file at every startup, so the next run picks it up. It is still better to recreate the environment, because the flag is normally an intentional part of how the environment is built, and hand-edited state on a server that no build script reproduces is exactly the kind of drift that makes an incident hard to explain.
saying these in an interview costs you the question
- Thinks the flag copies system packages into the environment
- Uses it routinely to avoid installing dependencies
- Believes base packages take precedence over environment installs
- Expects to be able to uninstall a system package from inside
- Claims an environment built with it is still reproducible from pins
- Cannot say which file records the setting