Package formats
OpenArtifact serves many package formats natively, each on the URL its client expects, behind one permission model.
URL conventions
Replace HOST with your server (for example http://localhost:8080) and REPO with the repository name (^[a-zA-Z0-9_-]{1,100}$).
- Every repository is served under
/repos/REPO/.... - Maven, sbt, Ivy and raw are served under a format prefix:
/repos/maven/REPO,/repos/sbt/REPO,/repos/ivy/REPO,/repos/raw/REPO. Repositories named like these prefixes are not reachable by the generic URL. - Docker / OCI is the exception: the registry API is at
HOST/v2/, and the first path segment after/v2/is the repository name (details). - Set
BASE_URL(baseUrl) to the externally visible URL: npm tarball URLs, Helmindex.yaml, PyPI JSON, the Cargoconfig.jsonand the Terraform download URLs are built from it.
Format matrix
Format id is the format value used when creating a repository. Hosted repositories support upload for every format; proxy and group are limited as shown (details: hosted, proxy, group).
| Format | Format id | Client URL | Types | Upload | Page |
|---|---|---|---|---|---|
| Maven | maven | HOST/repos/maven/REPO | hosted, proxy, group | PUT per file (mvn deploy) | maven |
| sbt | sbt | HOST/repos/sbt/REPO | hosted, proxy, group | PUT per file (sbt publish) | ivy-sbt |
| Ivy | ivy | HOST/repos/ivy/REPO | hosted, proxy, group | PUT per file (ivy:publish) | ivy-sbt |
| Terraform / OpenTofu | terraform | registry host HOST, source HOST/REPO/... (discovery at /.well-known/terraform.json) | hosted, proxy, group | PUT /_api/modules/MODULE/SYSTEM/VERSION, PUT /_api/providers/TYPE/VERSION/OS/ARCH (relative to HOST/repos/REPO) | terraform |
| Raw | raw | HOST/repos/raw/REPO/<path> | hosted, proxy, group | PUT <path> (curl -T) | raw |
| npm | npm | HOST/repos/REPO/ | hosted, proxy, group | npm publish (PUT /<pkg>) | npm |
| PyPI | pypi | HOST/repos/REPO/simple/ | hosted, proxy, group | twine upload to HOST/repos/REPO/legacy/ | pypi |
| Docker / OCI | docker | HOST/v2/ (image HOST/REPO[/image]) | hosted, proxy, group | docker push | docker |
| Helm | helm | HOST/repos/REPO/ (index.yaml, charts/) | hosted, proxy, group | POST /charts (raw chart .tgz) | helm |
| Debian (APT) | deb | HOST/repos/REPO/ (dists/, pool/) | hosted, proxy, group | POST /api/v1/repositories/REPO/debs (multipart) | debian |
| RPM (YUM/DNF) | rpm | HOST/repos/REPO/ (repodata/repomd.xml, Packages/) | hosted, proxy, group | POST /api/v1/repositories/REPO/packages (multipart) | rpm |
| Arch Linux (pacman) | pacman | HOST/repos/REPO/os/<arch> (<name>.db, packages) | hosted, proxy, group | PUT /os/<arch>/<pkg>.pkg.tar.zst (+ .sig) | pacman |
| Go modules | go | GOPROXY=HOST/repos/REPO | hosted, proxy, group | PUT <module>/@v/<version> (module zip) | go |
| Cargo | cargo | sparse+HOST/repos/REPO/index/ | hosted, proxy, group | cargo publish (PUT /api/v1/crates/new) | cargo |
| NuGet | nuget | HOST/repos/REPO/v3/index.json | hosted, proxy, group | dotnet nuget push (PUT /v3/package) | nuget |
| RubyGems | rubygems | HOST/repos/REPO/ | hosted, proxy, group | gem push (POST /api/v1/gems) | rubygems |
| Conda | conda | HOST/repos/REPO/<platform>/repodata.json | hosted, proxy, group | POST /<platform> with X-Filename | conda |
| Alpine (apk) | apk | HOST/repos/REPO/<branch>/<repo> (<arch>/APKINDEX.tar.gz) | hosted, proxy, group | PUT <branch>/<repo>/<arch>/<name>-<version>.apk or POST /api/v1/repositories/REPO/apks (multipart) | apk |
| Conan (1.x and 2) | conan | HOST/repos/REPO/ (v2/conans/..., v1/conans/...) | hosted, proxy, group | conan upload | conan |
Arch Linux (pacman) is uploaded with a PUT of the package file to HOST/repos/REPO/os/<arch>/<file>; its .db/.files databases are generated. A pacman proxy mirrors an Arch mirror root (details).
Debian and RPM have no upload route under /repos/REPO/: they are uploaded through the REST endpoints under /api/v1/repositories/REPO/. POST or PUT to HOST/repos/REPO/upload of such a repository answers 404 and names the endpoint to use.
Proxy repositories exist for these formats (Maven, sbt, Ivy, npm, PyPI, Helm, Go, Cargo, NuGet, RubyGems, Debian, RPM, Docker and raw); group repositories for the same formats. Creating any other combination is rejected with 400 validation_failed. Proxy and group repositories are read-only: writes answer 405.
Authentication
Authentication is required unless allowAnonymousRead is enabled or the repository is marked public (anonymous read only; writes always need a token). Package clients authenticate with an API token: Authorization: Bearer <TOKEN>, or HTTP Basic with the token as the password (any username). Account passwords are accepted only by the web UI login. Create tokens as described in authentication; what a token may do is governed by RBAC.
Read requests map to the read action and writes (PUT, POST, PATCH, DELETE) to write on the repository. The Debian/RPM REST upload endpoints under /api/v1/repositories/REPO/{debs,packages,comps} are authorized the same way, against the repository.
Behaviour shared by all formats
- Blobs are content-addressed by SHA-256 and deduplicated across repositories; a blob is removed from storage only when no package references it.
- Deletes are soft by default: the artifact, version or tag moves to the trash (404 on the native protocol, absent from listings, search and generated indexes) and can be restored until its retention expires. A repository can enable
immutable_releasesto block deleting or overwriting released versions. - Hosted repositories of raw, Maven, npm, Docker, Helm, PyPI, Cargo, Go and NuGet can be replicated between instances (federation).
- Uploads emit
artifact.uploadedand deletesartifact.deletedwebhook events (webhooks). - Storage quotas are enforced on upload for every hosted format; proxy caches are not metered (quotas).
- A repository with a license policy whose action is
blockrejects an upload whose declared license is denied (403, codeLICENSE_BLOCKED). The license is read from the package metadata; Conan, Go, Terraform and raw uploads carry none and are not checked. - Client setup renders the snippets for every client with your own server URL and repository name. Client snippets in the web UI and in the MCP
repositorytool come frominternal/clientsetup(UI counterpart:web/src/lib/installCommands.ts). Where this documentation differs from those snippets (Go format id), the page says so.