Publish CDKTF Constructs as a Python Package
Once a reusable CDKTF construct proves itself, other teams want it. Packaging it as a normal Python distribution — part of Python constructs and modules under CDKTF workflows and Terraform synthesis — lets them pip install your infrastructure building blocks and pin versions like any other dependency.
Problem Framing
Copy-pasting a construct between repositories forks it immediately: a fix in one place never reaches the others. Publishing it as a versioned package gives every consumer the same tested code, a changelog, and a clear upgrade path — the same discipline you already apply to application libraries, now applied to infrastructure.
Prerequisites
- Python 3.9+ with
buildandtwine, plus Poetry or pip-tools for dependency management - A construct that takes typed inputs and exposes typed outputs, not one hard-coded to one account
- Access to a package index (PyPI or a private index such as CodeArtifact)
# CLI: verify build tooling is present
python -m build --version && twine --version
Structuring and Building the Package
Keep the construct import-light: it should depend on cdktf and the specific provider bindings it needs, and nothing about a particular environment. Declare those as install requirements so consumers resolve them transitively.
# pyproject.toml (excerpt) — declare the construct package
# CLI: python -m build (produces dist/*.whl)
[project]
name = "acme-cdktf-network"
version = "1.3.0"
requires-python = ">=3.9"
dependencies = [
"cdktf>=0.20,<0.21",
"cdktf-cdktf-provider-aws>=19,<20",
]
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
With metadata in place, build a wheel and a source distribution. Provider note: pin the provider binding range so a consumer cannot accidentally pull an incompatible generated API.
Verification
Install the built wheel into a throwaway environment and synthesize a stack that uses it — the surest proof the package is self-contained.
# CLI: install the wheel and synth a consuming stack
pip install dist/acme_cdktf_network-1.3.0-py3-none-any.whl
cdktf synth # expect: cdk.tf.json produced with the construct's resources
Troubleshooting
ModuleNotFoundError after install — the package used a flat layout and shipped tests but not the module; adopt a src/ layout and confirm the wheel contains your package with unzip -l dist/*.whl.
jsii version conflicts — two construct packages pin incompatible cdktf ranges; align them or the consumer's resolver will fail. This is why narrow, explicit ranges matter.
Snapshot drift on upgrade — a provider-binding bump changes synthesized output; regenerate and review snapshot tests as part of the release.
FAQ
Should each construct be its own package?
Group closely related constructs (a networking bundle) into one package, but keep unrelated domains separate so consumers only pull what they use.
How do consumers override defaults?
Expose typed constructor parameters with sensible defaults. Consumers pass overrides; they never edit your package source.
Can I publish to a private index?
Yes — point twine at CodeArtifact or a self-hosted index and configure consumers' pip.conf accordingly.
Related
- Building Reusable CDKTF Constructs in Python — how to design the construct you are about to package.
- Python Constructs & Modules — the parent cluster on typed, reusable infrastructure.
- Managing IaC Dependencies with Poetry and pip-tools — pinning and resolving the dependencies your package declares.