Safeguard
Developer Tools•

Beam Python pipelines: pip freeze requirements or a custom container?

Beam can stage a requirements file to workers, but pip freeze lists everything installed. For complex pipelines a custom container fixes the environment.

Safeguard Security Team
4 min read

For a single file pipeline, a curated requirements file is the simplest way to give Beam workers their packages. For anything more complex, the Beam docs suggest packaging the pipeline and installing dependencies in a custom container. Either way, the pinned versions you write are what makes reruns repeatable.

What the Beam docs describe

The Apache Beam guide to Python pipeline dependencies says that if your pipeline uses public packages from PyPI, you must make them available remotely on the workers. For a pipeline that is a single Python file or notebook, the most direct route is a requirements file. For more complex cases, define the pipeline as a package and consider installing dependencies in a custom container.

To create the file, the docs suggest running pip freeze into a requirements file, and then editing it to delete everything your pipeline does not need. They note that pip freeze lists all packages installed on your machine regardless of where they came from. As an alternative they point to a tool such as pip-tools, where you list only top-level dependencies in an input file and compile the full set.

How staging works

When you supply the requirements file option, Beam downloads the listed packages into a local requirements cache at submission and stages that cache to the runner. At runtime, workers can install from the cache, possibly without a connection to PyPI. So the resolution happens on the machine that submits the job, which makes that machine part of your supply chain.

Comparing the approaches

ApproachStrengthWeak point
Raw pip freeze outputFastCaptures every package on your laptop, including unrelated ones
Curated requirements file with exact versionsSmall, readableTransitive dependencies need pinning too
Compiled file from a top-level inputRepeatable and completeNeeds a compile step in CI
Custom containerOne fixed environment for all workersAn image to build, scan and store

The freeze output deserves a second look. A laptop environment can hold tools, test libraries and packages from earlier experiments. Staging all of that onto workers widens what runs against your data. Trim it, and build the file in CI rather than on a developer machine.

A sound routine

  1. Keep a short input file of direct dependencies.
  2. Compile it to a fully pinned file in CI, with hashes if you can.
  3. For production, build a container from that file and reference the image by digest.
  4. Scan the image or the pinned file and keep the result with the release.
  5. Pin the Beam SDK version in the same file, since it is also a dependency.
  6. Rebuild on a schedule, and review the diff.

See pin Python dependencies in data projects and container image digests vs tags: why pinning matters.

Try it yourself

Click through it at your own pace, or open it full screen.

Watch how an image is broken into layers and packages. A worker container for a pipeline is built from layers like these.

Safeguard's SBOM and dependency scanning, including container images, covers this. A free scan is at gold.safeguard.sh/scan.

Quick check

Is pip freeze output safe to use as is?

The Beam docs say it lists every installed package regardless of origin, and tell you to remove what the pipeline does not need.

When does a custom container make sense?

For more complex pipelines, as the Beam docs suggest. It gives every worker the same fixed environment that you can scan and store.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.