Docs menu

Package managers

How pip, Poetry, and uv work on Primcloud: how one is selected, what runs during install, and how to authenticate against private package indexes.

On this page

Primcloud supports three Python package managers: pip, Poetry, and uv. Which one runs is decided by the file at the root of your repo. Only one may be present.

Supported package managers#

File at repo root Package manager Lockfile
requirements.txt pip No
poetry.lock Poetry (with pyproject.toml) Yes
uv.lock uv (with pyproject.toml and .python-version) Yes

Primcloud ships a pinned version of each: roughly pip 26.x, Poetry 2.4.x, and uv 0.11.x at the time of writing. You don't pick these; the Runtime carries them and they roll forward as it updates.

If both poetry.lock and requirements.txt are present (or any other combination of two), the build fails with a "multiple Python package manager files were found" error. Pick one and delete the other.

Pipenv is not supported. Pipfile and Pipfile.lock are recognized during detection so the build can surface a helpful error, but no install runs against them. To migrate off Pipenv, export a requirements.txt and switch to pip, or move to Poetry or uv (both of which support the same lockfile-driven workflow Pipenv provides).

Install behavior#

The build picks the package manager, installs it into its own layer, then runs one command against your project:

pip:

Terminal
pip install --no-input --progress-bar off --requirement requirements.txt

pip is a package installer, not an environment manager. It installs what requirements.txt says to install, but it doesn't uninstall packages that were removed from the file. The venv layer is not cached between builds for this reason; only pip's HTTP/wheel cache (via PIP_CACHE_DIR) is persisted, which speeds up repeat installs without the correctness pitfalls of a cached venv.

Poetry:

Terminal
poetry sync --only main --compile --no-interaction

--only main skips dev groups so tests, linters, and other tooling stay out of the runtime image. --compile pre-compiles .pyc files up front. poetry sync fully reconciles the environment against poetry.lock, uninstalling anything no longer listed, so the venv layer is safe to cache. The Poetry download cache is written to the home directory and discarded at the end of the build (the cached venv makes it unnecessary).

uv:

Terminal
uv sync --locked --no-default-groups --compile-bytecode --no-progress

--locked fails the build if uv.lock is out of sync with pyproject.toml, so a partial commit can't produce a mismatched image. --no-default-groups skips dev dependency groups. --compile-bytecode pre-compiles .pyc files. Like Poetry, uv sync fully manages the venv, so the layer is cached across builds.

Full detail on layer caching and reuse is in Python on Primcloud → Cache behavior.

Private packages and registries#

pip, Poetry, and uv all read the standard Python indexing environment variables. Set these on your app in the Secrets panel in the dashboard, and they take effect on the next build.

pip. Add an extra index by setting:

  • PIP_EXTRA_INDEX_URL: for example, https://<user>:<token>@pkgs.example.com/simple/.

Or replace the default index entirely with PIP_INDEX_URL. Basic-auth credentials embedded in the URL work; Primcloud does not surface them in build logs.

For per-requirement token substitution, requirements.txt supports environment variable interpolation:

requirements.txt
--extra-index-url https://__token__:${PYPI_TOKEN}@pkgs.example.com/simple/
some-private-package==1.2.3

PYPI_TOKEN (or whatever you name it) is set as an environment variable on the app.

Poetry. Poetry reads credentials from environment variables named after the source key in pyproject.toml. For a source declared as:

pyproject.toml
[[tool.poetry.source]]
name = "my-private-feed"
url = "https://pkgs.example.com/simple/"
priority = "supplemental"

Set:

  • POETRY_HTTP_BASIC_MY_PRIVATE_FEED_USERNAME = your username or token ID.
  • POETRY_HTTP_BASIC_MY_PRIVATE_FEED_PASSWORD = your token.

The source name is uppercased with dashes replaced by underscores. See Poetry's repositories docs for the full auth surface.

uv. uv reads per-index credentials from environment variables named after the index defined in pyproject.toml. For an index named my-private-feed, set:

  • UV_INDEX_MY_PRIVATE_FEED_USERNAME
  • UV_INDEX_MY_PRIVATE_FEED_PASSWORD

See uv's indexes reference for the full variable naming rules and auth options.

All three managers respect standard credentials in URLs and in netrc files if you'd rather ship those, but secrets are the least error-prone shape on Primcloud, and every secret is stored encrypted and never surfaced in build logs.

Lockfiles#

Lockfile behavior on Primcloud tracks each manager's own semantics:

  • pip: no lockfile support. requirements.txt is an install list; whichever versions resolve at build time are what get installed. Pin exact versions in requirements.txt if you need reproducibility, or generate one with a tool like pip-tools and commit its output.
  • Poetry: poetry.lock is mandatory when poetry.lock is at the root (the file's existence is what selects Poetry). poetry sync uses it verbatim; a lockfile out of sync with pyproject.toml fails the build.
  • uv: uv.lock is mandatory when uv.lock is at the root. uv sync --locked fails the build if the lockfile disagrees with pyproject.toml.

Two builds of the same commit produce different dependency graphs under pip if a package publishes a new version between them; under Poetry or uv, the graph is fixed by the lockfile.