Yes. pip freeze writes every package in the environment with an exact version, including transitive dependencies, so it pins more than the top level packages you chose. It is a start, but it carries no hashes, no platform logic and no record of where each file came from.
What the documentation says
pip's repeatable installs guide describes pinning with the double equals operator, which protects you from bugs or incompatibilities in newly released versions. Freeze generates a pinned requirements file, and the guide says this pins not only the top level packages but also all their transitive dependencies. Installing with the no dependencies option adds protection against pulling in anything the file does not list.
What freeze gives you and what it does not
| Property | pip freeze output |
|---|---|
| Exact versions | Yes |
| Transitive packages | Yes |
| Hashes | No |
| Records which are direct choices | No |
| Works across platforms | Only for the platform it ran on |
| Source index recorded | No |
The guide itself says pinning trusts the places you fetch from, relying on those sources not changing packages without a version bump. Hash checking is how you stop trusting that. The guide says hash-checking mode guards against a compromised index or certificate chain and against packages changing without a version change.
Why the output also hides intent
A frozen file mixes your choices with their dependencies in one flat list. In six months nobody can tell which line you asked for and which came along. That makes removal and review harder. A better flow keeps a short input file of direct dependencies and generates the pinned file from it with a lock tool.
Steps to improve a frozen file
- Keep a separate, short list of direct dependencies.
- Generate the pinned list from it, with hashes. See how to generate hashes for a Python requirements file.
- Install from that file with the environment variable PIP_NO_DEPS set so unlisted packages cannot join.
- Rebuild on purpose in a reviewed change.
- Scan the pinned set on a schedule, because pinned versions age.
Freeze in a clean environment
The output reflects whatever is installed, including tools you added by hand. Run freeze only in an environment built from your declared dependencies, never in one you have been experimenting in. Otherwise stray packages end up pinned into production, and you will be scanning and updating things you do not use.
Try it yourself
Click through it at your own pace, or open it full screen. Compare the flat list with how direct and transitive components are shown.
Quick check
Is a frozen requirements file a lock file?
It is close, but it has no hashes or platform information. A lock tool records more.
Will a pinned version stay safe?
No. New advisories can appear against a version you pinned, so keep scanning.
Safeguard's SBOM and dependency scanning matches a pinned set against new advisories, and a free scan takes a requirements file.
Sources
Last reviewed: 19 October 2026.