Registries
BatleHub proxies, caches, and privately hosts 23 registry types — from language package managers to OS package repositories, editor extension marketplaces, and generic file mirrors.
Every registry type can run in one of three modes, set per registry in the config:
- proxy — a pure read-through cache in front of an upstream. The first request is fetched from upstream and stored; every later request is served from cache.
- local — a fully private registry. Nothing is fetched from upstream; you publish and serve your own artifacts.
- hybrid — local artifacts win, and anything not published locally falls through to the upstream proxy.
Five types are proxy-only (no private publish model): GitHub, Forgejo, GitLab (they host source/releases upstream) and JetBrains IDE archives + Generic file mirrors (path-only caches).
The registries
Source hosting
| Registry | type | What it proxies | Modes | Publish | Default upstream |
|---|---|---|---|---|---|
| GitHub | github | Releases, assets, tarballs, raw files | proxy-only | ❌ | api.github.com |
| Forgejo / Gitea | forgejo | Releases, assets, archives, raw (/api/v1) | proxy-only | ❌ | codeberg.org |
| GitLab | gitlab | Releases, link assets, archives (/api/v4) | proxy-only | ❌ | gitlab.com |
Language package managers
| Registry | type | What it proxies | Modes | Publish | Default upstream |
|---|---|---|---|---|---|
| npm | npm | Packument + tarballs | proxy · local · hybrid | ✅ | registry.npmjs.org |
| Cargo | cargo | Sparse index + .crate | proxy · local · hybrid | ✅ | crates.io |
| Go Modules | goproxy | GOPROXY (.info/.mod/.zip) | proxy · local · hybrid | ✅ | proxy.golang.org |
| Maven | maven | Metadata XML + JAR/POM | proxy · local · hybrid | ✅ | repo1.maven.org |
| PyPI | pypi | Simple API (PEP 503/691) + wheels | proxy · local · hybrid | ✅ | pypi.org |
| Conda | conda | repodata.json + .conda/.tar.bz2 | proxy · local · hybrid | ✅ | conda.anaconda.org |
| Composer (PHP) | composer | Packagist v2 (p2 metadata + dist) | proxy · local · hybrid | ✅ | repo.packagist.org |
| RubyGems | rubygems | Gems + versions + info API | proxy · local · hybrid | ✅ | rubygems.org |
| NuGet (.NET) | nuget | v3 index + flat + .nupkg | proxy · local · hybrid | ✅ | api.nuget.org |
| Terraform | terraform | Providers + modules (v1 API) | proxy · local · hybrid | ✅ | registry.terraform.io |
| Ansible Galaxy | galaxy | Collections API v3 (versions list, version document, tarball) + the v1 role reads | proxy · local · hybrid | ✅ | galaxy.ansible.com/api/ |
Editor extensions
| Registry | type | What it proxies | Modes | Publish | Default upstream |
|---|---|---|---|---|---|
| OpenVSX | openvsx | Extension VSIX | proxy · local · hybrid | ✅ | open-vsx.org |
| VS Code Marketplace | vscode-marketplace | Extension VSIX (MS Gallery) | proxy · local · hybrid | ✅ | marketplace.visualstudio.com |
| JetBrains Marketplace | jetbrains-marketplace | Plugin API + downloads | proxy · local · hybrid | ✅ | plugins.jetbrains.com |
OS / system packages path-addressed
| Registry | type | What it proxies | Modes | Publish | Default upstream |
|---|---|---|---|---|---|
| Debian / APT | deb | Packages/Release + .deb | proxy · local · hybrid | ✅ | none — set upstreams |
| RPM / YUM / DNF | rpm | repodata/ + .rpm | proxy · local · hybrid | ✅ | none — set upstreams |
| Pacman / Arch | pacman | <repo>.db + .pkg.tar.zst | proxy · local · hybrid | ✅ | none — set upstreams |
| Alpine / apk | apk | APKINDEX.tar.gz + .apk | proxy · local · hybrid | ✅ | none — set upstreams |
Binaries & mirrors path-addressed
| Registry | type | What it proxies | Modes | Publish | Default upstream |
|---|---|---|---|---|---|
| JetBrains IDEs | jetbrains | IDE installer archives | proxy-only | ❌ | download.jetbrains.com |
| Generic mirror | generic | Any HTTP file tree | proxy-only | ❌ | none — set upstreams + path_allow |
Build caches RFC 0028
| Registry | type | What it proxies | Modes | Publish | Default upstream |
|---|---|---|---|---|---|
| Nix binary cache | nix | nix-cache-info, one {hash}.narinfo per store path (relayed with only URL: rewritten, so every Sig: still verifies) and the NARs | proxy · local · hybrid | ✅ | cache.nixos.org |
Toolchains RFC 0010
Typed, so a release can be blocked rather than merely cached — the identity the generic mirror cannot give the same bytes.
| Registry | type | What it proxies | Modes | Publish | Default upstream |
|---|---|---|---|---|---|
| Node distributions | nodedist | index.tab/index.json + release tarballs, SHASUMS256.txt byte-exact (nvm, fnm, n, mise) | proxy-only | ❌ | nodejs.org/dist |
| SDKMAN | sdkman | Candidates API + download broker (the JDK, Gradle, Maven, Kotlin, …); the broker's 302 followed server-side | proxy-only | ❌ | api.sdkman.io/2 + broker.sdkman.io |
| Rust toolchain | rustup | Channel manifests (the filtered listing) + per-target component tarballs and their .sha256; the .asc relayed byte-exact | proxy-only | ❌ | static.rust-lang.org |
Feature matrix
Every registry and how its capabilities map across BatleHub's features. The path-addressed types (Deb, RPM, Pacman, JetBrains IDEs, Generic) have no per-package version model, so the structural axes (version listing, source archive, binary, age gate, warming, search) show —. They still get registry-level RBAC and multi-upstream fanout, and Deb/RPM/Pacman support signed private hosting. Forgejo and GitLab mirror GitHub's behaviour.
Legend: Ver. version listing · Src source archive · Bin binary/extension asset · Pub private publish · Fan multi-upstream fanout · Age release age gate · Warm cache warming (version enumeration) · Search Package Explorer upstream search. ✓ supported · — not applicable · ⚠ partial.
| Registry | Ver. | Src | Bin | Pub | Fan | Age | RBAC | Warm | Search |
|---|---|---|---|---|---|---|---|---|---|
| GitHub | ✓ | ✓ | ✓ | — | ✓ | ✓ | ✓ | ✓ | — |
| Forgejo / Gitea | ✓ | ✓ | ✓ | — | ✓ | ✓ | ✓ | ✓ | — |
| GitLab | ✓ | ✓ | ✓ | — | ✓ | ✓ | ✓ | ✓ | — |
| npm | ✓ | ✓ | — | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Cargo | ✓ | ✓ | — | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Go Modules | ✓ | ✓ | — | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Maven | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | — | ✓ |
| PyPI | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Conda | ✓ ¹ | ✓ | ✓ | ✓ | ✓ | ⚠ ² | ✓ | ✓ ¹ | — |
| Composer | ✓ | ✓ | — | ✓ | ✓ | ✓ | ✓ | — | ✓ |
| RubyGems | ✓ | ✓ | — | ✓ | ✓ | ✓ | ✓ | — | ✓ |
| NuGet | ✓ | — | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Terraform | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | — | ✓ |
| Ansible Galaxy | ✓ ⁶ | ✓ | — | ✓ | ✓ | ✓ ⁷ | ✓ | ✓ | — |
| OpenVSX | ✓ | — | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| VS Code Marketplace | ✓ | — | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | — |
| JetBrains Marketplace | ✓ | — | ✓ | ✓ | ✓ | ✓ | ✓ | — | ✓ |
| Debian / APT ³ | — | — | — | ✓ | ✓ | — | ✓ | — | — |
| RPM / YUM / DNF ³ | — | — | — | ✓ | ✓ | — | ✓ | — | — |
| Pacman / Arch ³ | — | — | — | ✓ | ✓ | — | ✓ | — | — |
| JetBrains IDEs ³ | — | — | — | — | ✓ | — | ✓ | — | — |
| Generic ³ | — | — | — | — | ✓ | — | ✓ | — | — |
| Node distributions | ✓ | ✓ | ✓ | — | ✓ | ✓ ⁴ | ✓ | ✓ ⁵ | — |
| SDKMAN | ✓ | — | ✓ | — | ✓ | ⚠ ⁴ | ✓ | ✓ ⁵ | — |
¹ Conda has no dedicated per-package version listing API. BatleHub synthesises one by scanning
repodata.jsonacrossnoarch,linux-64,osx-64,osx-arm64, andwin-64; results are the union of versions found on all available platforms.² Conda timestamps come from the
timestampfield inrepodata.json(ms since epoch). Most packages carry it; packages without one skip the gate unless you setdeny_missing_timestamp = trueon the rule.³ Path-addressed type: artifacts are fetched by file path with no per-package version model, so the structural axes show
—. These types don't enumerate versions but can pre-warm specific files viacache.warm_paths, and are gated with a mandatorypath_allowallowlist. Deb/RPM/Pacman additionally support signed private hosting (local/hybrid); JetBrains IDE archives and Generic are proxy-only.⁴ Toolchain age gates (RFC 0010 §6.7):
nodedistreads the release date fromindex.tab, so current releases are gated and a de-listed one reaches the gate undated;sdkmanpublishes no dates at all, so the gate is decided entirely bydeny_missing_timestamp. On both kinds that field is mandatory on arelease_age_gaterule.⁵ Warming by platform: a Node release and an SDKMAN version are one archive per platform, so
warm_packageswarms the platforms incache.warm_platforms, defaulting to the server's own. The console's per-version fetch button is refused for the same reason.⁶ One page, always (RFC 0031 §4.4):
ansible-galaxyresolves a pagination link against the configured API root, and upstream's links are absolute paths that replace the whole path — so no continuation BatleHub could emit would be followed back to it. Every listing it serves therefore carries a nullnext, and the adapter walks upstream's pages itself.⁷ Galaxy age gates: every upstream collection version carries
created_at, so the gate is fully decided in proxy mode. A locally published collection and an air-gapped listing may carry no date, sodeny_missing_timestampis mandatory on arelease_age_gaterule here, as it is on the toolchain kinds.Package Explorer upstream ("Not Yet Proxied") search: Go uses pkg.go.dev; PyPI is exact-name lookup; Terraform combines module search with namespace/exact provider lookup. The release proxies (GitHub/Forgejo/GitLab), VS Code Marketplace, Conda, and the path-addressed types have no upstream search API — see the Package Explorer guide.
READMEs
What a package says about itself, per version. Whether a registry has one at all is a property of its protocol, not a preference: the text either travels in a document the proxy already fetches to resolve a version, or it sits inside the artifact — and that decides whether the package page can show it for a version this instance holds no bytes for.
Held nowhere here is the column worth reading before you go looking for a gap: versions + README means the package page answers in full for a package nothing here has ever pulled; versions only means it lists the versions and says the README arrives when one is first downloaded; neither means the page answers from what this instance holds and nothing else.
Fetchable is whether the page offers a Fetch this version button on those upstream-only rows, and whether the catalogue offers one on an upstream search result. no is not a limitation of the button but of the coordinate: a Maven version is a set of files, a Terraform provider is addressed by OS and architecture as well as version, a PyPI version is an sdist plus one wheel per interpreter and platform, and a conda artifact carries a channel platform and a build string — so "fetch this version" has no single meaning for any of them. The page says which rather than showing a disabled button — see fetching from the console.
| Registry | README source | Per version | Held nowhere here | Fetchable |
|---|---|---|---|---|
| github | the README is one of the repository files this proxy already serves by path, under raw/{ref}/, so a second URL for it would be a second answer to a solved question | — | neither | no |
| forgejo | the README is one of the repository files this proxy already serves by path, under raw/{ref}/, so a second URL for it would be a second answer to a solved question | — | neither | no |
| gitlab | the README is one of the repository files this proxy already serves by path, under raw/{ref}/, so a second URL for it would be a second answer to a solved question | — | neither | no |
| cargo | a file inside the artifact | yes | versions only | yes |
| npm | the metadata document, else the artifact | yes | versions + README | yes |
| openvsx | a URL in the metadata, read separately | yes | versions + README | yes |
| goproxy | a file inside the artifact | yes | versions only | yes |
| pypi | the metadata document, else the artifact | yes | versions + README | no |
| conda | a file inside the artifact | yes | versions only | no |
| composer | a file inside the artifact | yes | versions only | yes |
| vscode-marketplace | a URL in the metadata, read separately | yes | versions + README | yes |
| maven | the POM carries <description>, which is a sentence rather than a document; putting one where a reader expects the other makes every package look thinly documented | — | versions only | no |
| terraform | a file inside the artifact | yes | versions only | no |
| rubygems | a file inside the artifact | yes | versions only | yes |
| nuget | a file inside the artifact | yes | versions only | yes |
| deb | path-addressed: there is no package identity to hang a README on | — | neither | no |
| rpm | path-addressed: there is no package identity to hang a README on | — | neither | no |
| pacman | path-addressed: there is no package identity to hang a README on | — | neither | no |
| apk | an .apk carries pkgdesc, one sentence in .PKGINFO; putting a sentence where a reader expects a document makes every package look thinly documented | — | neither | no |
| jetbrains | path-addressed: there is no package identity to hang a README on | — | neither | no |
| jetbrains-marketplace | the metadata document, already fetched | yes | versions + README | yes |
| generic | path-addressed: there is no package identity to hang a README on | — | neither | no |
| nodedist | a Node release is a set of tarballs and a checksum file; the dist tree carries no prose | — | versions only | no |
| sdkman | SDKMAN describes a distribution, not a package: no document in the protocol carries prose about a candidate | — | versions only | no |
| rustup | a toolchain release is a manifest and a set of tarballs; the dist tree carries no prose | — | versions only | no |
| galaxy | a file inside the artifact | yes | versions only | yes |
| nix | a store path is a NAR and its narinfo; the protocol carries no prose, and the NAR is a filesystem image rather than a package with a manifest | — | neither | no |
Configured per registry with [registries.readme] and [registries.upstream_detail]. Both are on by default, and the second one makes an outbound request the first time somebody opens a package page for something this instance holds nothing of — see what leaves this instance.
Two settings shape what else the page can do: remote_images = "proxy" renders a README's images through this server rather than charting them, and console_fetch (on by default) is the Fetch this version button, on the package page and on the catalogue's upstream rows alike. Prose search across stored READMEs is instance-wide and off by default — [search] readmes.
See also
- User Guide — task-oriented walkthroughs for the most common registries.
- Administration → Configuration — how to declare registries in
config.toml. - Caching · Access Control · Roadmap.