Desk Clarity

Everyday document & browser help

pip freeze versus direct requirements: what an installed package list can tell you

By ON Lab · Sources checked November 8, 2026

pip freeze describes installed distributions in an environment. It does not discover which packages your project directly needs. pip list --not-required narrows that inventory to packages that are not dependencies of other installed packages; it still cannot tell whether your project uses them. Choose between preserving an environment and maintaining an intentional dependency declaration before deleting the transitive entries.

A reader asked whether removing indirect dependencies from a requirements export was safe when another person would recreate the environment. The question is historical, from 2020, and is not evidence of present search volume. We checked current pip and Python packaging documentation and built a small offline dependency graph to separate the decisions behind that question.

Three questions that need different records

QuestionUseful recordWhat it cannot prove
What is installed here?An inventory from the intended interpreterWhich packages the source code needs
What does this project intentionally require?Reviewed project dependencies, optional features and development requirementsEvery exact version another installation will select
Can another environment run this project?A clean installation and the project's relevant testsCompatibility with every other platform or future release

For a packaged project, the Python packaging guide describes [project].dependencies and optional dependency metadata. Existing applications may use a different documented workflow. Keep that workflow rather than adding a second competing dependency file merely because an export command is available.

Inspect the environment you intend to export

python -c 'import sys; print(sys.executable); print(sys.version)'
python -m pip --version
python -m pip freeze
python -m pip list --not-required --format=freeze

Here python means the selected project interpreter, not an assurance that a bare shell command already selects it. Use the explicit environment interpreter when necessary. If installation and execution disagree, first use the separate interpreter-location checks.

The current freeze documentation explicitly distinguishes reporting installed state from computing a solver result or lockfile. It also documents omissions of bootstrap tools: Python 3.11 and earlier omit more packaging tools by default than Python 3.12 and later. --all changes that inclusion policy; it does not identify direct project dependencies.

Our local counterexample

We created three original tiny wheel files and installed them in a disposable virtual environment. The invented distribution names below describe the fixture, not packages you should download. The test used Python 3.9.6 and pip 21.2.4; current online documentation was checked separately. No third-party package index or real application was involved.

Distributionfreeze inventorynot-required list
desk-appIncluded as a direct local-file referenceIncluded
desk-leafIncluded at version 1.0Excluded because desk-app requires it
desk-unrelatedIncluded as a direct local-file referenceIncluded despite being unrelated to the project

This shows why graph roots and project requirements are different. The list command inspected installed distribution relationships. It had no knowledge of our imagined application's intended behavior. A leftover standalone package survived the filtering, while a project might also directly use a package that another installed distribution happens to require.

Our first test assertion expected every freeze entry to use ==1.0. The actual output retained local wheel references for the two directly installed files, so we corrected that test expectation and read the complete output. Do not discard a direct reference or turn a workstation path into a portable installation promise just to make a requirements file look uniform.

Choose the export for the handoff you actually need

If you need an environment snapshot for investigation, retain the inventory and interpreter details. Save to a new filename after checking it does not contain existing work, for example environment-snapshot.txt. Review local paths, editable installations and access-dependent sources before sharing. A list that worked on one workstation may reference files unavailable on another.

If you need a maintainable project declaration, start with the project's existing metadata and actual features. Review runtime libraries, optional integrations, test tools and development tools separately. Do not automatically promote every installed distribution to a direct requirement. Do not automatically remove a distribution solely because not-required omitted it.

If you need repeatable resolved versions, use the project's chosen supported lock or constraint workflow and review its guarantees. A shorter root list normally lets the installer choose compatible indirect versions under the remaining constraints. That can be useful, but it is a different contract from recording the previously installed indirect versions. Omitting pins cannot be declared universally safe from the list output alone.

Verify with a fresh environment

  1. Preserve the current environment and original declaration.
  2. Create a separate disposable environment using the intended Python version.
  3. Install through the project's reviewed setup procedure.
  4. Run the real entry point and relevant tests, including optional features you intend to support.
  5. Record any missing distribution, version conflict or unavailable local source before changing the declaration.

Passing a base import does not exercise every plugin, command or optional path. Source import scans can help an audit, but dynamically loaded integrations and distribution names that differ from import names need additional review. We did not test a scanner or claim that one can reconstruct arbitrary project metadata.

If you use uv, preserving unmanaged packages during sync is a separate operation. The exact-versus-inexact syncing guide explains that behavior. Retaining an environment is not evidence that every retained package belongs in the project's dependency declaration.

Checked November 8, 2026. The offline fixture verifies inventory and dependency-root behavior in the recorded versions. It does not reproduce the reader's original project, validate pip-chill, measure search demand or guarantee cross-platform reproducibility.

Sources