NORA: Minimalist Rust Artifact Registry with No External Dependencies
A developer built NORAβa single Rust binary for storing artifacts in Docker v2/OCI, Maven, npm, PyPI, Cargo, Go, and raw formats. It's just 34 MB in size, uses 12 MB RAM at idle, and skips databases or external services entirely. Metadata lives in JSON files on disk, with consistency ensured via atomic renames. Out-of-the-box support for S3 backend, Prometheus metrics, health checks, and Swagger docs.
Why Ditch Nexus, Artifactory, and Harbor
Nexus OSS demands 4 GB RAM for its Java process, and migrations between versions (Core/Community/Pro) are a headache due to switching from OrientDB to PostgreSQL. Artifactory OSS sticks to Maven/Gradle/Ivy; Docker and npm support is paywalled. Harbor zeros in on containers, sidelining Maven, npm, and PyPI. GitLab Registry has caveats: OCI artifacts, buildx cache, and multi-arch images need workarounds.
Time spent on hacks outpaced building a custom solution.
No-DB, No-Web-Admin Architecture
Everything's on the filesystem: artifacts and JSON metadata side by side. The catalog builds by walking directories. No migrations, clustering, or external servicesβboots in 3 seconds.
nora (34 MB, Rust, 450+ tests)
βββ /v2/ β Docker Registry v2 + OCI (images, Helm charts)
βββ /maven/ β Maven (JAR, WAR, POM)
βββ /npm/ β npm (Node.js packages)
βββ /pypi/ β PyPI (Python packages)
βββ /cargo/ β Cargo (Rust crates, sparse index RFC 2789)
βββ /go/ β Go Modules
βββ /raw/ β Raw (anything)
βββ /metrics β Prometheus
βββ /health β K8s liveness probe
βββ /ready β K8s readiness probe
βββ /api-docs β Swagger
βββ /data/ β storage (FS or S3)
Config via config.toml or env vars. Read-only web UI for browsing, searching, and stats. Changes go through git with CI/CD auditing.
Supported Formats
- Docker v2 + OCI:
/v2/β images, Helm charts, full spec compliance. - Maven:
/maven/β JAR, WAR, POM with Central proxying. - npm:
/npm/β Node.js packages, sparse index. - PyPI:
/pypi/β Python packages. - Cargo:
/cargo/β Rust crates per RFC 2789. - Go:
/go/β modules with proxy.golang.org proxying. - Raw:
/raw/β arbitrary files.
Authentication and Security
- htpasswd files for basic auth.
- API tokens with RBAC (read/write/admin), token revocation.
- Anonymous read access, TLS via reverse proxy (nginx/Traefik).
Extras:
- Structured JSON logs (method, path, status, user).
- Rate limiting per endpoint.
- Audit log in JSONL.
- GC:
nora gc --dry-runfor Docker blobs. - Backup/restore:
nora backup -o file.tar.gz.
Performance Comparison
| Metric | NORA | Nexus OSS | Artifactory |
|------------------|----------|-----------|-------------|
| Binary Size | 34 MB | 600+ MB | 1+ GB |
| Cold Start | ~3 sec | 30-60 sec| 30-60 sec |
| RAM | 12 MB | 2-4 GB | 2-4 GB |
| External Svcs | 0 | H2/PG | PG/Tomcat |
| Formats | 7 | 20+ | 30+ |
Under load (2 cores, 4 GB RAM): pull 268 MB image in 6 sec, push in 19 sec, RAM peaks at 250 MB.
Deployment and Usage
Quick start:
docker run -d \
-p 8080:8080 \
-v nora-data:/data \
getnora/nora:0.5.0
Docker push:
docker login localhost:8080 -u admin
docker tag myapp:latest localhost:8080/myapp:latest
docker push localhost:8080/myapp:latest
npm:
npm config set registry http://localhost:8080/npm/
npm publish
Upstream proxy: auto-caches from Docker Hub, npmjs, PyPI, Maven Central.
Air-Gapped Networks and Mirroring
For isolated setups: nora mirror --format docker --packages "nginx:latest" --output bundle on an external node, transfer bundle, then nora restore --input bundle inside. SHA256 integrity checks.
Key Takeaways
- Single binary, no DB: 34 MB, 12 MB RAM, filesystem storage.
- 7 formats: Docker/OCI, Maven, npm, PyPI, Cargo, Go, raw.
- Upstream proxy + cache, RBAC tokens, audit logs.
- Roadmap: online GC, multi-node, NuGet/RubyGems, OIDC.
β Editorial Team
No comments yet.