Storage for Go, Nix, NPM, and Python packages.
- Read access: Serve NAR files and narinfo metadata from your local Nix store
- Upload support: Accept uploads of compressed NAR files (.nar, .nar.xz, .nar.gz, .nar.bz2) and narinfo metadata via HTTP PUT
- SSH Authentication: JWT-based authentication using SSH public keys with read/write permissions
- Proxy & Push: Built-in proxy and push commands for authenticated access to remote caches
- Compression support: Automatic decompression of uploaded NAR files
- NAR processing: Uses go-nix library for proper NAR file parsing and extraction
- Logging: Structured JSON logging with configurable verbosity
- Storage backends: Filesystem or S3-compatible storage (AWS S3, MinIO, GCP Cloud Storage)
- Kubernetes deployment: See
./k8sfor example Kubernetes manifests.
nix key generate-secret --key-name local-depot-1 > signing.keyThe --key-name can be any identifier you choose (e.g., mycompany-cache, home-cache-1). The -1 suffix is a convention for key versioning. Use the same key name consistently when configuring clients to trust your cache.
depot serve --private-key signing.key --verboseExtract the public key from your signing key, or fetch the public key from the Nix cache info handler (http://localhost:8080/nix/nix-cache-info).
# Convert the private key to public key
nix key convert-secret-to-public < signing.key
# Output: local-depot-1:public-key-base64...Add the public key to your Nix configuration to trust signatures from your cache. Replace local-depot-1:public-key-base64... with the actual output from the command above:
# Option 1: Add to ~/.config/nix/nix.conf
echo "trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= local-depot-1:public-key-base64..." >> ~/.config/nix/nix.conf
# Option 2: Add to /etc/nix/nix.conf (system-wide, requires sudo)
sudo sh -c 'echo "trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= local-depot-1:public-key-base64..." >> /etc/nix/nix.conf'
# Option 3: Use flags when running nix commands
nix build --option trusted-public-keys "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= local-depot-1:public-key-base64..." --option substituters "http://localhost:8080 https://cache.nixos.org" nixpkgs#slAdd your depot as a substituter:
# Add to nix.conf (depot first, then official cache as fallback)
echo "substituters = http://localhost:8080 https://cache.nixos.org" >> ~/.config/nix/nix.conf
# Or use the --option flag
nix build --option substituters "http://localhost:8080 https://cache.nixos.org" nixpkgs#slNote: The order matters - Nix checks substituters sequentially. List your depot first for faster lookups, with the official cache as a fallback.
Create an auth file with SSH public keys:
# auth.keys - format: permission ssh-keytype base64key comment
w ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABA... user@laptop
r ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABA... user@desktopThen start the server:
depot serve --auth-file auth.keys --private-key signing.key --verbose# Push a flake reference
depot push https://my-cache.example.com --flake-refs github:NixOS/nixpkgs#sl
# Push store paths
depot push https://my-cache.example.com --store-paths /nix/store/abc123...
# Push from stdin
echo "/nix/store/abc123..." | depot push https://my-cache.example.com --stdinOr push using nix copy - see push-without-tools for complete push examples.
nix copy --to https://my-cache.example.com nixpkgs#sl# Save specific modules.
depot go save golang.org/x/text@v0.21.0 rsc.io/quote@v1.5.2
# Save all dependencies from a go.mod file.
depot go save ./go.modThis saves modules and their transitive dependencies to .depot-storage/go. Each module's .info, .mod, and .zip files are fetched from proxy.golang.org.
depot go push http://localhost:8080# Point GOPROXY at your depot server.
export GOPROXY=http://localhost:8080/go,direct
export GONOSUMCHECK='*'
export GONOSUMDB='*'
# Or configure persistently.
go env -w GOPROXY=http://localhost:8080/go,direct
go env -w GONOSUMCHECK='*'
go env -w GONOSUMDB='*'In an air-gapped environment, omit ,direct so that Go does not attempt to fall back to direct fetching:
export GOPROXY=http://localhost:8080/goGONOSUMCHECK and GONOSUMDB disable checksum database lookups, which are unreachable in an air-gapped environment.
Then use Go as normal:
go mod download
go build ./...depot npm save expressThis will create a .depot-storage in the current directory containing the NPM package tarballs and metadata.
depot npm push http://localhost:8080npm install --registry http://localhost:8080 express# Download specific packages.
depot python save "requests>=2.0.0" "flask==2.3.0"
# Download from a requirements.txt file.
depot python save --stdin < requirements.txt
# Or pipe a list of packages.
echo "requests>=2.0.0" | depot python save --stdinThis will create a .depot-storage/python directory containing the Python package files and metadata.
The save command supports standard Python package specifiers:
package==1.0.0- Exact versionpackage>=1.0.0- Minimum versionpackage>=1.0.0,<2.0.0- Version rangepackage~=1.4.2- Compatible release
depot python push http://localhost:8080# Install from your depot.
pip install --index-url http://localhost:8080/python/simple/ requests
# Use as an additional package index.
pip install --extra-index-url http://localhost:8080/python/simple/ requests
# In requirements.txt, use:
# --index-url http://localhost:8080/python/simple/
# requests>=2.0.0Or configure pip permanently in pip.conf or ~/.pip/pip.conf:
[global]
index-url = http://localhost:8080/python/simple/The server supports SSH key-based authentication using JWT tokens. Authentication is configured via a text file containing SSH public keys with permission levels.
Each line in the auth file has the format:
<permission> <ssh-keytype> <base64-key> <comment>
Where:
permission:rfor read-only,wfor read-writessh-keytype: SSH key type (e.g.,ssh-rsa,ssh-ed25519)base64-key: The base64-encoded public keycomment: Optional comment
Example auth file:
w ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC... admin@laptop
r ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD... readonly@desktop
w ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... deploy@ci
You can fetch public SSH keys from a Github username, by adding .keys, e.g. https://github.com/$GITHUB_USERNAME.keys
- If any key has read-only (
r) permission, all access requires authentication - If only write (
w) keys are configured, only uploads require authentication - If no auth file is provided, no authentication is required
The depot proxy command creates an authenticated proxy to a remote cache:
# Start proxy on default port (43407)
depot proxy https://my-cache.example.com
# Start proxy on random port
depot proxy https://my-cache.example.com --port 0
# Then use nix commands through the proxy
nix copy --to http://localhost:43407 nixpkgs#slThe server supports uploading NAR files in multiple compression formats:
.nar- Uncompressed NAR files.nar.xz- XZ-compressed NAR files (most common with Nix).nar.gz- Gzip-compressed NAR files.nar.bz2- Bzip2-compressed NAR files
The server automatically detects the compression format from the URL and decompresses the content before processing.
Start server with S3 storage backend:
# Using AWS S3 with IAM role (EC2/ECS/Fargate).
depot serve \
--storage-type=s3 \
--s3-bucket=my-depot-bucket \
--s3-region=us-east-1 \
--database-url=postgres://user:pass@host/db
# Using MinIO with explicit credentials.
depot serve \
--storage-type=s3 \
--s3-bucket=depot \
--s3-region=us-east-1 \
--s3-endpoint=http://localhost:9000 \
--s3-access-key-id=minioadmin \
--s3-secret-access-key=minioadmin \
--s3-force-path-style=true \
--database-url=sqlite:///tmp/depot.db
# Environment variables can also be used.
export DEPOT_STORAGE_TYPE=s3
export DEPOT_S3_BUCKET=my-depot-bucket
export DEPOT_S3_REGION=us-east-1
depot serveS3 configuration options:
--storage-type: Set tos3for S3 storage--s3-bucket: S3 bucket name (required)--s3-region: AWS region (default: us-east-1)--s3-endpoint: Custom endpoint for MinIO/LocalStack--s3-access-key-id: Access key (uses IAM if not set)--s3-secret-access-key: Secret key (uses IAM if not set)--s3-force-path-style: Use path-style URLs (required for MinIO)
go build -o depot ./cmd/depotgo run ./cmd/depotgo run ./cmd/depot serve --store-path=$HOME/depot-store --verbosenix buildnix runnix developnix build .#docker-imageOnce you've built the image, you can load it into a local Docker daemon with docker load.
docker rmi ghcr.io/a-h/depot:latest || true
docker load < resultgunzip -c result | microk8s ctr image import -mkdir -p ${HOME}/depot-store
docker run --rm -v ${HOME}/depot-store:/depot-store -p 8080:8080 ghcr.io/a-h/depot:latestPush a store path to the binary cache. If authentication is enabled, use the proxy command to proxy with authentication.
nix copy --to http://localhost:8080 `nix eval github:NixOS/nixpkgs/8cd5ce828d5d1d16feff37340171a98fc3bf6526#sl --raw` --refreshPush a couple of Go modules, NPM packages, Python packages, and Nix packages.
export DEPOT_URL=http://localhost:8080
# Save and push Go modules.
go run ./cmd/depot go save rsc.io/quote@v1.5.2
go run ./cmd/depot go push $DEPOT_URL
# Save and push NPM packages.
go run ./cmd/depot npm save express lodash
go run ./cmd/depot npm push $DEPOT_URL
# Save and push Python packages.
go run ./cmd/depot python save "requests>=2.0.0" "flask==2.3.0"
go run ./cmd/depot python push $DEPOT_URL
# Push Nix packages.
go run ./cmd/depot nix push $DEPOT_URL --flake-refs nixpkgs#hello
go run ./cmd/depot nix push $DEPOT_URL --flake-refs nixpkgs#jqDownload a couple of Go modules, NPM packages, Python packages, and Nix packages from depot.
export DEPOT_URL=http://localhost:8080
export DEPOT_GO_URL=$DEPOT_URL/go
export DEPOT_NPM_URL=$DEPOT_URL/npm
export DEPOT_PYTHON_URL=$DEPOT_URL/python/simple/
export DEPOT_NIX_URL=$DEPOT_URL/nix
export DOWNLOAD_DIR=$(mktemp -d)
echo "Downloading artifacts to $DOWNLOAD_DIR"
# Download Go modules from depot.
GOPROXY=$DEPOT_GO_URL GONOSUMCHECK='*' GONOSUMDB='*' go mod download rsc.io/quote@v1.5.2
# Download NPM packages from depot.
npm pack --registry $DEPOT_NPM_URL --pack-destination $DOWNLOAD_DIR express lodash
# Download Python packages from depot.
python -m pip download --dest $DOWNLOAD_DIR --index-url $DEPOT_PYTHON_URL requests flask
# Download Nix packages from depot.
nix build \
--no-link \
--option substituters "$DEPOT_NIX_URL https://cache.nixos.org" \
nixpkgs#hello nixpkgs#jqnix store ls --store http://localhost:8080 --recursive /nix/store/4h86fqf4nl9l4dqj8sjvqfw0f9x22wpg-sl-5.05Run all tests including integration tests:
go test ./... -v -coverprofile=coverage.out -timeout 5mgo test ./storage -v -run TestS3StorageShow coverage summary:
go tool cover -func=coverage.out | grep totalWarning: this may damage the running db.
sqlite3 -header -column "file:$HOME/depot-store/depot.db?ro=1" "SELECT key from kv;"export FLAKE=github:NixOS/nixpkgs/8cd5ce828d5d1d16feff37340171a98fc3bf6526
export PKG=github:NixOS/nixpkgs/8cd5ce828d5d1d16feff37340171a98fc3bf6526#sl
# Copy flake input and source to the store.
nix flake archive --to http://localhost:8080/nix $FLAKE --refresh
# Copy the sl package of the flake, and it derivation.
nix copy --to 'http://localhost:8080/nix' $PKG --refresh
nix copy --derivation --to 'http://localhost:8080/nix' $PKG --refresh
# Copy realised paths of inputs to the derivation so that we can build it on the remote.
nix copy --to http://localhost:8080/nix $(
nix-store --realise $(
nix derivation show "$PKG" | jq -r '.[].inputDrvs | keys[]'
)
)If you're hosting Depot on Docker or Kubernetes, you may encounter SQLite disk I/O errors due to filesystem restrictions. If you see an error like this:
sqlite: step: disk I/O error
This is because SSHFS (Rancher Desktop's default), 9fs and other network filesystems do not support file locking, which SQLite requires. To resolve this, you can use a volume that supports file locking, such as a local disk or a network filesystem that supports it. Disabling WAL with the &_journal_mode=DELETE SQLite connection string can also resolve the issue.