Skip to content

Artifact Management

What Is an Artifact

An artifact is the immutable output of a build stage that is promoted through environments.

Build once → push artifact → deploy the same artifact to staging, then production

Never rebuild for production. An artifact deployed to staging must be the exact same binary/image that reaches production. Rebuilding introduces variance.


Artifact Types

Type Example Storage
Docker image ghcr.io/org/api:v1.4.2 Container registry
Python wheel myapp-1.4.2-py3-none-any.whl PyPI / Nexus
Archive api-v1.4.2.tar.gz S3 / GCS / Nexus
Helm chart api-1.4.2.tgz Helm repo / OCI registry

Versioning

Semantic Versioning (SemVer)

MAJOR.MINOR.PATCH

1.4.2
│ │ └── Bug fix, no API change
│ └──── New feature, backwards compatible
└────── Breaking change

Pre-release and build metadata:

1.4.2-rc.1           # release candidate
1.4.2+build.20260330 # build metadata (ignored in comparisons)

CI-Friendly Versioning Strategies

Strategy Format When to Use
Git SHA abc1234 Every commit build
SemVer + SHA 1.4.2-abc1234 Release builds
Branch + build number main-142 Short-lived branch artifacts
Date-based 2026.03.30.1 Services with continuous deploy
# Generate version tag from git
- name: Set version
  run: echo "VERSION=$(git describe --tags --always)" >> $GITHUB_ENV

- name: Build and push
  run: |
    docker build -t ghcr.io/org/api:${{ env.VERSION }} .
    docker push ghcr.io/org/api:${{ env.VERSION }}

Container Registry

# Login and push to GitHub Container Registry
- name: Log in to registry
  uses: docker/login-action@v3
  with:
    registry: ghcr.io
    username: ${{ github.actor }}
    password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push
  uses: docker/build-push-action@v5
  with:
    push: true
    tags: |
      ghcr.io/${{ github.repository }}:${{ github.sha }}
      ghcr.io/${{ github.repository }}:latest

Image Tagging Strategy

Tag Meaning Auto-updated
latest Most recent main build Yes
v1.4.2 Specific release No (immutable)
sha-abc1234 Exact commit No (immutable)
main-142 Branch + build number Overwritten per build

Never use latest in production deployments. Always pin to an immutable tag.


Artifact Retention

Store artifacts long enough for rollback, not forever.

Environment Retention
PR builds 7 days
Main branch builds 30 days
Tagged releases 1 year
Production releases Indefinitely
# GitHub Actions artifact upload with retention
- uses: actions/upload-artifact@v4
  with:
    name: dist-${{ github.sha }}
    path: dist/
    retention-days: 30

Promotion Pattern

The artifact moves through environments unchanged:

Build → push image:sha-abc1234
           │
           ▼
        Staging  (deploy image:sha-abc1234)
        Smoke tests pass
           │
           ▼
        Production (deploy same image:sha-abc1234)

Each promotion updates the deployment, not the artifact. The image built at commit abc1234 is identical in staging and production.