How to update, investigate, and resolve dependency conflicts in templates and extensions.
Read after the top-level MAINTENANCE_RUNBOOK.md.
Before bumping a version, verify that it exists on PyPI and that its requirements are compatible with the template's Python version.
# Latest published version
curl -s "https://pypi.org/pypi/<pkg>/json" | jq -r '.info.version'
# List recent releases
uv pip index versions <pkg>
# Inspect requires-python and dependencies (PyPI metadata)
curl -s "https://pypi.org/pypi/<pkg>/<version>/json" | jq '.info | {requires_python, requires_dist}'
# Show what uv would resolve in a generated project
cd my-app && uv treeExample:
uv pip index versions fastapi
curl -s "https://pypi.org/pypi/pydantic-settings/json" | jq -r '.info.requires_python'
cd smoke-test-app && uv tree --package fastapiIf a version is missing, PyPI returns 404 or uv pip index versions omits it. That immediately tells you the range in pyproject.toml is invalid.
Meaning: The requested version does not exist on PyPI.
Common cause: A template or extension pins a version that was yanked, never published, or mistyped.
Fix:
- Verify the exact package name and version on PyPI.
- Either:
- Drop the dependency if it is no longer needed.
- Pin to the latest compatible release.
- Rename the package if upstream renamed it in a new major line.
Meaning: uv cannot satisfy the dependency graph, usually because two packages require incompatible versions of the same dependency or different Python versions.
Common cause: Two extensions add conflicting version constraints to merged pyproject.toml keys, or a template pins a major version that an extension's extras cannot use.
Fix strategies (in order of preference):
- Align both sides to a mutually compatible version. This is the cleanest fix.
- Downgrade the more aggressive requirement if the newer major is not strictly needed.
- Constrain the conflict in
pyproject.tomlusing[tool.uv]overrides or explicit pins in the extension layer that owns the dependency. - Mark extensions as incompatible if they truly cannot coexist (
incompatibleWithintemplates.json).
Meaning: A package requires requires-python newer (or older) than the template declares.
Fix: Update requires-python in the template pyproject.toml consistently, and ensure CI uses a matching Python version.
- Edit
extensions/<slug>/pyproject.toml(partial manifest with only the keys the extension adds). - Use conservative ranges:
>=x.y.z,<next-majoror compatible caret-style bounds where appropriate. - Avoid major-version bumps unless you have validated breaking changes.
- Re-scaffold the extension with each compatible template and run validation.
Templates ship a full pyproject.toml (or under template/). Update dependency versions there.
When core supports manifest merge, extensions union dependencies by package name; later layers win on conflicts. See create-python-app docs/PYPROJECT_MERGE.md.
A major dependency update is high-risk. For each major:
- Read the changelog or migration guide.
- Check
requires-pythonand transitive requirements. - Test with L2 isolation for the affected extension(s) and the relevant curated L3 profile(s).
- If breaking changes affect generated code, update template
.templatefiles or extension files.
Generated projects do commit uv.lock when the template or extension includes one, but CI smoke tests often run fresh uv sync without a pre-existing lock. If a transitive dependency starts breaking installs, consider:
- Pinning the transitive dependency in the template or extension
pyproject.toml. - Adding a constraint group or override in
create-python-appcore (see MAINTENANCE_SECURITY.md).
Avoid relying on transient PyPI states; pin when reproducibility matters.
gh pr list --repo Create-Python-App/create-python-app --author dependabot --state open
gh pr list --repo Create-Python-App/cpa-templates --author dependabot --state open
gh pr view <pr> --repo Create-Python-App/<repo>gh pr comment <pr> --repo Create-Python-App/<repo> --body "@dependabot rebase"Only merge if CI passes. Security-related bumps take priority. If a Dependabot PR fails CI, treat it as a bug fix: reproduce, adjust the dependency range or lockfile, and push to the same PR rather than opening a duplicate.
# Why a version was chosen
cd my-app && uv tree --package <pkg>
# Show outdated packages (when lock exists)
cd my-app && uv lock --upgrade-package <pkg> --dry-run
# Verbose sync for debugging
cd my-app && UV_LOG=debug uv sync
# Export resolved requirements
cd my-app && uv export --format requirements-txt- The target version exists on PyPI for every related package.
-
requires-pythonis satisfied across template and extensions. - Peer/extra conflicts are resolved or explicitly worked around.
- The change is scoped to the affected template/extension.
- Local validation passes (
uv sync, ruff, pytest). - Full matrix passes for affected templates.
- If security-related, the CVE is actually addressed by the bump.