How to reference images in your bundle
Bundles often deploy workloads that require container images.
Porter gives you two ways to handle this: hardcoded image references or declaring
images in the manifest’s images section.
Choosing the right approach depends on whether you need Porter to manage image
relocation for you.
Hardcoded image references
The simplest approach is to reference images directly in your bundle steps, just like you would in any shell script or Helm chart:
install:
- helm3:
description: "Install my app"
name: myapp
chart: ./charts/myappIn this case the chart controls which image to pull and where to pull it from. Porter has no knowledge of those images — it will not copy them when the bundle is published or archived, and it will not update the references when the bundle is moved to a different registry.
This approach is fine when:
- The bundle is only ever run in environments that have direct access to the original image registry (e.g., Docker Hub, ghcr.io).
- You are iterating quickly and want to avoid the overhead of declaring digests.
- The images are managed by a third-party Helm chart that already controls its own image references and doesn’t support overriding them.
Declaring images in the manifest
When you add images to the images section of porter.yaml, Porter tracks them
and manages their location for you:
images:
myapp:
description: "My application image"
imageType: "docker"
repository: "myregistry.example.com/myorg/myapp"
digest: "sha256:abc123..."You then reference the image in your bundle steps using template variables instead of a hardcoded string:
install:
- helm3:
description: "Install my app"
name: myapp
chart: ./charts/myapp
set:
image.repository: ${ bundle.images.myapp.repository }
image.digest: ${ bundle.images.myapp.digest }Use digest rather than tag so that the reference remains stable and
immutable across environments.
How relocation works
When you run porter publish, Porter copies every image declared in the
images section into the same repository as the bundle itself.
At runtime, ${ bundle.images.myapp.repository } and
${ bundle.images.myapp.digest } resolve to the relocated image, not the
original source.
Original: myregistry.example.com/myorg/myapp@sha256:abc123...
Published: myregistry.example.com/myorg/mybundle@sha256:abc123...This means the bundle and all its images travel together as a unit — no external registry access is needed at runtime.
The same applies when you run porter archive: the bundle archive (tgz file)
contains all declared images so they can be moved to a disconnected environment
and re-published there.
See Image References After Publishing for a deeper walkthrough.
Which approach to choose
| Scenario | Approach |
|---|---|
| Need to deploy in an airgapped environment | Declare images in images section |
| Moving bundles between registries | Declare images in images section |
| Images managed by a third-party chart | Hardcoded (or skip if chart doesn’t support overriding) |
| Fast iteration / local testing | Hardcoded is fine; add images section before publishing |
| Bundle always runs against the same registry | Either works |