Package Registry, Dependency Proxy, Package Formats, Permissions, and Artifact Distribution: Concepts, Architecture, and Mental Model
Model GitLab packages as governed release artifacts with project/group namespace, format-specific endpoints, version identity, authentication, provenance, retention, and dependency-proxy trust boundaries.
Learning objectives
- Distinguish Package Registry packages from job artifacts, OCI images, and dependency proxies.
- Explain project ownership, group aggregation, package format/version identity, and provenance.
- Choose among documented Generic Package credentials without confusing authentication with authorization.
- Treat duplicate/immutability semantics as package-format and configuration specific.
- Explain the different current availability/status of container-image and package dependency proxies.
1. The practical problem: a build file becomes a dependency the moment someone consumes it
Chapter 21 optimized pipeline execution. Chapter 22 changes the lifecycle of the output. A job artifact can be excellent short-lived pipeline evidence, but a reusable library, CLI binary, schema bundle, model asset, or installer needs a stable package identity that consumers can resolve independently of the producing job.
Publishing therefore creates a production dependency. You must know which project owns the package, which endpoint names it, which version consumers request, who may publish or delete it, which credential performed the action, how integrity is verified, and what happens if the version disappears.
2. Four objects that look similar but have different contracts
| Object | Primary purpose | Identity / lifecycle |
|---|---|---|
| Job artifact | Move or preserve pipeline output. | Bound to job/pipeline; retention-oriented; Chapter 16. |
| Package Registry package | Distribute a versioned dependency or release file. | Project-owned package name/version plus format-specific metadata/endpoints. |
| Container Registry image | Distribute OCI container images. | Repository plus immutable digest and mutable tags; Chapter 23. |
| Dependency Proxy | Cache/proxy an upstream dependency. | Cache identity follows upstream reference; it is not the same as publishing your own package. |
Do not promote an artifact into a “package” merely by keeping it forever. The Package Registry gives consumers a package-manager/API contract and creates explicit publish/read/delete permissions.
3. Mental model: source → pipeline identity → project package → consumer
flowchart TD S[Commit / ref] --> P[Pipeline + job] P -->|ephemeral CI_JOB_TOKEN| R[Project Package Registry] R --> M[Package metadata: name + version + files + hashes] M --> C[Consumer job / package manager] C --> V[Checksum + provenance verification] U[Upstream registry] --> DP[Dependency Proxy] DP --> C
The producer job authenticates to the project registry and publishes a versioned object. GitLab records package/file metadata and checksums. A consumer resolves an exact package identity and independently verifies content. The Dependency Proxy is a separate upstream-cache path: it reduces repeated external downloads but does not turn a mutable upstream tag/version into your own governed package.
4. Package ownership follows GitLab projects; group views aggregate rather than erase ownership
The durable write boundary is normally a project package registry: publishing to project A creates package state owned by project A. GitLab also exposes group-level views/endpoints for discovery or consumption for formats that support them, aggregating packages in the group hierarchy. That does not mean the package has lost its source project or permission boundary.
For the Generic Package Registry used in this chapter, the file URL is explicitly project-scoped:
PUT /projects/:id/packages/generic/:package_name/:package_version/:file_name
GET /projects/:id/packages/generic/:package_name/:package_version/:file_name
Write the project ID/path into your provenance record. A package with the right name and version in the wrong project is still the wrong dependency.
5. Package formats are product capabilities, not one universal protocol
GitLab supports multiple package-manager protocols and a Generic Package API. Current documentation includes long-established formats such as Composer, Conan, Go, Maven, npm, NuGet, PyPI, Generic Packages, and Helm. Support and detailed behavior are version-sensitive, and newer registry capabilities can appear independently.
| Format family | Why it exists | Behavior to verify before standardizing |
|---|---|---|
| Generic | Arbitrary release files without a native package protocol. | Name/version/file rules, duplicate-file setting, SHA-256, retention. |
| npm / PyPI / Maven / NuGet | Native ecosystem dependency resolution. | Scope/group endpoints, duplicate/version rules, forwarding, client auth. |
| Composer / Conan / Go / Helm | Native ecosystem distribution. | Supported endpoints, authentication protocol, metadata/hash behavior. |
| Container images | OCI image distribution. | Use Container Registry, not Package Registry; Chapter 23. |
Do not write a company-wide rule such as “GitLab packages are immutable” without checking the exact format. Duplicate semantics differ by protocol and configuration.
6. Package identity has at least five coordinates
For reproducible consumption, record GitLab host, owning project, package name, package version, and file or package-manager coordinate. Add an integrity hash and producing commit/pipeline when traceability matters.
host: gitlab.example.invalid
project: platform/ch22-lab
format: generic
name: ch22-synthetic
version: 0.0.42
file: payload.txt
sha256: <recorded SHA-256>
producer_sha: <40-hex Git commit>
producer_pipeline: <pipeline id>
A human-friendly version is not a checksum. A checksum is not a source commit. Keep both semantic identity and content identity.
7. Authentication is format-specific; authorization still comes from the target registry
For current Generic Packages, official documentation supports
personal access tokens with api, project access tokens
with api and sufficient role,
CI_JOB_TOKEN, and deploy tokens with
read_package_registry and/or
write_package_registry. Do not assume every package
format accepts every token type.
| Credential | Good fit | Security property |
|---|---|---|
CI_JOB_TOKEN |
Publish/consume from CI/CD. | Short-lived and tied to the running job; preferred mandatory path. |
| Deploy token | Non-GitLab external consumer/publisher. | Persistent until expiry/revocation; separate read/write package scopes. |
| Project/PAT | Human/API operations that require user/project permissions. | Broader identity; avoid when job/deploy token is sufficient. |
| Group token | Only where the specific registry endpoint documents support. | Never infer support from another package format. |
Publication also needs authorization. Current project permissions normally require Developer or higher to publish and Maintainer/Owner to delete; project visibility and package-registry visibility affect reads.
8. Version “immutability” is a policy you must prove, not assume
Different formats react differently to the same name/version. Current Generic Package behavior allows additional files under an existing name/version by default, and group Owners can control duplicate Generic package publishing. Maven can add files to an existing name/version, while PyPI rejects a duplicate name/version. This is precisely why consumers should use package-manager semantics plus recorded hashes rather than relying on a generic idea of immutability.
For release-grade packages, prefer one-way version publication, prevent duplicate overwrite/addition where the format supports policy controls, and make republishing the same semantic version a visible exception.
9. Generic Packages give us a clean integrity lab
GitLab automatically calculates SHA-256 for Generic Package files.
The Packages API exposes file metadata including
file_sha256. Newer
glab packages download also verifies downloaded Generic
Package files against registry checksum metadata by default.
Response-header checksum verification depends on how object storage/direct download is configured, so the lab does not depend on that header. It verifies the downloaded deterministic content locally and shows the API metadata path separately.
10. “Dependency Proxy” currently means two materially different product surfaces
Container-image Dependency Proxy: Free,
group-scoped, Docker-Hub-oriented pull-through cache. In CI,
predefined variables such as
CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX can route image
pulls through it. GitLab checks upstream metadata while reusing
cached blobs, so a cache hit is not an integrity guarantee for a
mutable upstream tag.
Package dependency proxy: currently Premium/Ultimate and Beta. It caches supported upstream packages into project package state and uses Package Registry authorization. Because of its tier/status, this chapter teaches it through documentation/fixtures, not as a required live lab.
11. Read-only inspection before any publish
In a disposable project, first inspect the package feature and existing state:
PROJECT_ID="<disposable-project-id>"
# Existing package records; glab uses your current authenticated session.
glab api "projects/$PROJECT_ID/packages?per_page=100" \
| jq 'map({id,name,version,package_type,status,created_at})'
# Confirm the repository SHA that a future package should claim.
git rev-parse HEAD
If package operations are disabled for the project, fix the project feature setting before debugging tokens or curl syntax. If existing production-looking packages are present, do not use that project for the lab.
12. DevOps connection: registry writes are governed release actions
A package publication changes what downstream systems can resolve. Treat it like a deployment-quality action: reviewed source, reproducible build, narrow credential, explicit version, checksum/provenance evidence, retention decision, and consumer-impact analysis before deletion. This is the foundation for Chapter 23 container images and later release/security chapters.
Knowledge check
Why is a job artifact not automatically a good package distribution mechanism?
Artifacts are job/pipeline objects with retention-oriented lifecycle. Packages provide a consumer-facing version/protocol/permission contract independent of the producing job.
What is the minimum identity you should record for a Generic Package file?
Host, owning project, package name, version, file name, plus integrity/provenance such as SHA-256 and producing commit/pipeline.
Why can two GitLab package formats behave differently for the same version number?
Each format implements its own package-manager protocol and duplicate/version rules. “Package Registry” is a family of integrations, not one universal immutability rule.
What credential is preferred for the mandatory CI publish/consume path?
The ephemeral CI_JOB_TOKEN, because GitLab provides
it to the job and the Generic Package Registry documents it for
CI automation.
Does a Dependency Proxy guarantee that a mutable upstream tag has never changed?
No. A proxy is a cache/resolution layer. For immutable identity, pin a digest/version and verify integrity/provenance according to the ecosystem.
Summary
You can now separate package distribution from job artifacts and container images, locate package ownership at the correct project/group boundary, choose a documented credential, reason about format-specific duplicate behavior, and treat dependency proxies as cache layers rather than trust anchors.
Official references
Primary sources used for the current GitLab 19.3 behavior taught in this lesson:
- GitLab Docs — Package Registry
- GitLab Docs — Supported package managers and functionality
- GitLab Docs — Generic Packages
- GitLab Docs — Packages API
- GitLab Docs — CI/CD job token
- GitLab Docs — Dependency Proxy for container images
- GitLab Docs — Dependency Proxy for packages
- GitLab Docs — Reduce Package Registry storage
- GitLab CLI — glab packages upload
- GitLab CLI — glab packages download
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this
address.