Skip to content

Storage Adapters

OpenCodeHub stores git objects, LFS files, package-registry blobs (npm/OCI), and any artifacts produced by the platform on a pluggable storage backend. Two backends are supported:

  • local — the server’s filesystem. The default. Suitable for single-host deployments and for development.
  • s3 — any S3-compatible object store. The same code path serves AWS S3, MinIO, Cloudflare R2, Garage, SeaweedFS, Ceph RGW, Wasabi, Backblaze B2, and any other S3-v4 implementation.

Removed backends. Previous releases also supported Google Drive, Microsoft OneDrive, Dropbox, FTP, Google Cloud Storage, Azure Blob Storage, and an rclone-as-adapter option. They were removed because none of them support the S3-style multipart semantics OpenCodeHub needs for efficient large-blob operations; rclone as a backup target remains as a separate, optional utility (/api/admin/sync, scripts/sync-storage.ts).


Data is written under the directory pointed to by DATA_DIR (e.g., /data/storage). A .meta sidecar file is written next to each uploaded blob to persist content-type metadata.

Terminal window
STORAGE_TYPE=local
# If using the 1-click install, DATA_DIR handles this automatically.
# Otherwise, manually set:
DATA_DIR=./data
# (Which internally resolves STORAGE_PATH to ./data/storage)

When to choose local: single-server deployments, self-hosting on a home server or NAS, development, and CI runners that do not need distributed blob storage.


The s3 driver speaks the S3 v4 API. Any vendor that implements it works by setting STORAGE_ENDPOINT to the vendor’s endpoint URL and STORAGE_REGION to its documented region string. Path-style addressing is enabled automatically when an endpoint is provided, which is required by MinIO, Garage, SeaweedFS, and most self-hosted stacks.

Terminal window
STORAGE_TYPE=s3
STORAGE_BUCKET=opencodehub
STORAGE_REGION=us-east-1
STORAGE_ENDPOINT= # leave empty for AWS S3
STORAGE_ACCESS_KEY_ID=...
STORAGE_SECRET_ACCESS_KEY=...
Terminal window
STORAGE_TYPE=s3
STORAGE_BUCKET=opencodehub
STORAGE_REGION=us-east-1
# STORAGE_ENDPOINT left empty
STORAGE_ACCESS_KEY_ID=AKIA...
STORAGE_SECRET_ACCESS_KEY=...

Create the bucket and an IAM user with s3:ListBucket, s3:GetObject, s3:PutObject, s3:DeleteObject, and s3:GetObjectVersion permissions. Enable bucket versioning for cheap backups.

MinIO is the most popular S3-compatible server; it works as a drop-in replacement for AWS S3 and is easy to run on a NAS, home server, or Kubernetes cluster.

Terminal window
STORAGE_TYPE=s3
STORAGE_BUCKET=opencodehub
STORAGE_REGION=us-east-1
STORAGE_ENDPOINT=http://minio.local:9000
STORAGE_ACCESS_KEY_ID=minioadmin
STORAGE_SECRET_ACCESS_KEY=minioadmin

The bundled docker-compose.yml includes a MinIO service under the with-minio profile:

Terminal window
docker compose --profile with-minio up -d

The MinIO web console is exposed on :9001; create the bucket opencodehub and an access key before starting the app.

R2 is S3-compatible, has zero egress fees, and is well-suited to self-hosters who already use Cloudflare for DNS / Tunnel.

Terminal window
STORAGE_TYPE=s3
STORAGE_BUCKET=opencodehub
STORAGE_REGION=auto
STORAGE_ENDPOINT=https://<account_id>.r2.cloudflarestorage.com
STORAGE_ACCESS_KEY_ID=...
STORAGE_SECRET_ACCESS_KEY=...

Create an R2 API token with Object Read & Write scope on the bucket in the Cloudflare dashboard.

Garage is an S3-compatible distributed object store designed for home labs and small clusters. It’s lighter than MinIO and well suited to multi-NAS setups.

Terminal window
STORAGE_TYPE=s3
STORAGE_BUCKET=opencodehub
STORAGE_REGION=garage
STORAGE_ENDPOINT=http://garage.local:3900
STORAGE_ACCESS_KEY_ID=...
STORAGE_SECRET_ACCESS_KEY=...

SeaweedFS is an S3-compatible distributed object store optimised for small files; great for NAS deployments where every byte counts.

Terminal window
STORAGE_TYPE=s3
STORAGE_BUCKET=opencodehub
STORAGE_REGION=us-east-1
STORAGE_ENDPOINT=http://seaweedfs.local:8333
STORAGE_ACCESS_KEY_ID=...
STORAGE_SECRET_ACCESS_KEY=...

If you already run Ceph for block or file storage, the RADOS Gateway provides a fully S3-compatible HTTP frontend.

Terminal window
STORAGE_TYPE=s3
STORAGE_BUCKET=opencodehub
STORAGE_REGION=default
STORAGE_ENDPOINT=https://rgw.example.com
STORAGE_ACCESS_KEY_ID=...
STORAGE_SECRET_ACCESS_KEY=...

All expose an S3-compatible endpoint. Use the S3 access key the vendor issues and the endpoint URL it documents.

Terminal window
# Wasabi
STORAGE_ENDPOINT=https://s3.wasabisys.com
STORAGE_REGION=us-east-1
# Backblaze B2 (S3-compatible API)
STORAGE_ENDPOINT=https://s3.<region>.backblazeb2.com
STORAGE_REGION=us-west-004
# DigitalOcean Spaces
STORAGE_ENDPOINT=https://<region>.digitaloceanspaces.com
STORAGE_REGION=nyc3

OperationLocal SSDS3/R2 Object Storage
Repository page load~50-100ms5-30 seconds
Clone (small repo)~100ms2-10 seconds
Push (10 files)~200ms1-5 seconds
File browser navigation~30ms500ms-2s

When using object storage, every Git operation requires multiple HTTP requests:

  1. List objects - 1 API call
  2. Download each file - 40+ API calls for a typical repo
  3. Each request has ~50-100ms latency (network + S3 processing)

A repository page load might download:

  • HEAD, config, refs/heads/* (branch info)
  • objects/pack/*.idx, *.pack (git objects)
  • All hook files, info files, etc.

40 files × 100ms = 4+ seconds minimum

Best: Local SSD storage + S3 for backups only

Terminal window
STORAGE_TYPE=local
STORAGE_PATH=/var/lib/opencodehub/repos

Use a cron job or background process to sync to S3 for disaster recovery.

☁️ Serverless (Vercel, Cloudflare Workers)

Section titled “☁️ Serverless (Vercel, Cloudflare Workers)”

Trade-off: Accept latency or implement caching

Terminal window
STORAGE_TYPE=s3
# Enable local cache (coming soon)
ENABLE_REPO_CACHE=true
CACHE_TTL_SECONDS=300
CompanyApproach
GitHubRepos on local NVMe clusters, S3 for backups only
GitLabGitaly (dedicated Git servers with local storage)
BitbucketSharded storage servers, repos cached in memory

Key insight: Major Git hosts never serve live traffic from object storage. They use local disk + memory caching for hot repos.

We’re working on:

  • Local disk cache with TTL-based invalidation
  • Parallel S3 downloads (70% faster initial loads)
  • Redis metadata cache (instant branch/tree info)
  • Gitaly-like architecture for enterprise deployments

To migrate from local to S3:

Terminal window
# 1. Backup current repos
tar -czf repos-backup.tar.gz data/repos/
# 2. Upload to S3
aws s3 sync data/repos/ s3://your-bucket/repos/ --endpoint-url $STORAGE_ENDPOINT
# 3. Update .env
STORAGE_TYPE=s3
STORAGE_BUCKET=your-bucket
# 4. Clear local cache
rm -rf .tmp/repos/

To migrate from S3 to local:

Terminal window
# 1. Download from S3
aws s3 sync s3://your-bucket/repos/ data/repos/ --endpoint-url $STORAGE_ENDPOINT
# 2. Update .env
STORAGE_TYPE=local
STORAGE_PATH=./data/repos