TAG is a high-performance S3-compatible caching proxy for Tigris object storage. It provides transparent caching with request coalescing to reduce upstream load and improve latency for frequently accessed objects.
- S3-Compatible API: Supports all S3 API endpoints supported by Tigris
- Transparent Proxy Mode: Forwards client requests as-is with proxy headers, preserving original signatures (enabled by default)
- Embedded Cache: High-performance RocksDB-based cache with automatic cluster discovery
- Request Coalescing: Streaming broadcast pattern reduces duplicate upstream requests under concurrent load
- Range Request Caching: Background fetch of full objects on range cache miss for optimal ML training workloads
- Conditional Requests: Supports If-None-Match and If-Modified-Since for efficient cache validation
- AWS SigV4 Authentication: Full AWS Signature Version 4 validation and re-signing
- Prometheus Metrics: Comprehensive metrics for monitoring cache efficiency and performance
- Kubernetes Ready: Includes deployment manifests for production use
Install the latest release and run it against Tigris:
# Install the tag binary to /usr/local/bin and a default config to /etc/tag/config.yaml
curl -fsSL https://tag-releases.t3.storage.dev/latest/install.sh | bash
# TAG uses its own Tigris credentials with read-only access to the buckets it caches
export AWS_ACCESS_KEY_ID=your_access_key
export AWS_SECRET_ACCESS_KEY=your_secret_key
# Run (transparent proxy mode by default; clients use their own credentials)
tag --config /etc/tag/config.yamlTAG listens on http://localhost:8080. Point any S3 client at it using path-style addressing — see Usage. Prefer Docker or Kubernetes? See Installation.
Each release publishes the install script, run script, and a matching config.yaml to the release bucket, so you can install without cloning the repo:
# Latest release
curl -fsSL https://tag-releases.t3.storage.dev/latest/install.sh | bash
# A specific release
curl -fsSL https://tag-releases.t3.storage.dev/v1.11.1/install.sh | bashThe script installs the tag binary to /usr/local/bin and a default config to /etc/tag/config.yaml.
Pull and run the published image with Docker Compose:
cd deploy/docker
docker compose -f docker-compose.release.yml up -dSee docs/docker.md for single-node and cluster setups. To build the image from source instead, use the Compose files in docker/.
Deploy as a StatefulSet with an embedded distributed cache using the Kustomize manifests in deploy/kubernetes/:
kubectl apply -k deploy/kubernetes/base/See docs/deploy.md for the full guide.
Building TAG requires the Go toolchain and access to Tigris modules — see Contributing.
TAG supports all S3 API endpoints supported by Tigris, including bucket operations, object operations, multipart uploads, and more. See the Tigris S3 API documentation for the complete list of supported operations.
TAG supports path-style S3 access only. Virtual-hosted style requests are not supported.
| Style | URL Format | Supported |
|---|---|---|
| Path-style | http://localhost:8080/bucket/key |
Yes |
| Virtual-hosted | http://bucket.localhost:8080/key |
No |
When configuring S3 clients, ensure path-style addressing is enabled. See docs/usage.md for SDK-specific configuration.
| Header | Description |
|---|---|
X-Cache |
Cache status: HIT, MISS, BYPASS, or DISABLED |
- Objects larger than
size_thresholdare not cached - Objects with
Cache-Control: no-storeorprivateare not cached - Range requests trigger background fetch of full object (if within threshold)
- PUT/DELETE operations invalidate the cache entry
See docs/cache-control.md for detailed cache control and revalidation documentation.
TAG can be configured via YAML file or environment variables. Key settings:
AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY- TAG's own Tigris credentials with read-only access (required). In transparent proxy mode (default), clients use their own credentials directly.TAG_CACHE_NODE_ID- Unique node identifier for cluster modeTAG_CACHE_DISK_PATH- Path to cache data directoryTAG_LOG_LEVEL- Log level: debug, info, warn, error
See docs/configuration.md for full configuration reference.
For production, TAG ships manifests, Compose files, and guides under deploy/ and docs/. The Installation section covers getting a single instance running; the guides below cover production concerns:
- Kubernetes — StatefulSet, HPA, and services in
deploy/kubernetes/; high availability, scaling, and probes in docs/deploy.md. - Docker — single-node and cluster Compose in
deploy/docker/; see docs/docker.md. - TLS/HTTPS — see docs/tls.md.
- Benchmarks — see docs/benchmarks.md.
┌─────────────┐ ┌─────────────────────────────┐ ┌─────────────┐
│ Client │────▶│ TAG │────▶│ Tigris │
│ (S3 SDK) │◀────│ ┌─────────────────────┐ │◀────│ Storage │
└─────────────┘ │ │ Embedded Cache │ │ └─────────────┘
│ │ (RocksDB + Gossip) │ │
│ └─────────────────────┘ │
└─────────────────────────────┘
- Cache Check: TAG first checks if the object exists in its embedded cache
- Cache Hit: Returns cached object with
X-Cache: HITheader - Cache Miss: Forwards request to upstream Tigris, caches response, returns with
X-Cache: MISS
When multiple concurrent requests arrive for the same uncached object:
- First request becomes the "fetcher" and streams from upstream
- Subsequent requests join as "listeners" to the same broadcast
- All listeners receive data simultaneously as it streams from upstream
- Only one upstream request is made, regardless of concurrent client count
See docs/architecture.md for detailed architecture documentation.
A single TAG node saturates a 100 Gbps NIC at ~85+ Gbps for objects 1 MiB and larger, serves ~75K ops/sec for small objects at sub-millisecond p50, and holds low single-digit-millisecond TTFB — all while using around 12% of available CPU.
| Object size | OPS (64 threads) | Throughput | TTFB p50 |
|---|---|---|---|
| 1 KiB | ~75,700 | 74 MiB/s | < 1 ms |
| 100 KiB | ~33,300 | 3.2 GiB/s | 1 ms |
| 1 MiB | ~11,000 | 10.7 GiB/s | 1 ms |
| 4 MiB | ~2,800 | 10.8 GiB/s | 1 ms |
Measured with warp against a single i3en.24xlarge node over a 100 Gbps link. See docs/benchmarks.md for the full methodology, go-ycsb results, and limitations.
TAG exposes Prometheus metrics at /metrics including request counts, latencies, cache hit/miss rates, and broadcast statistics.
See docs/metrics.md for complete metrics reference.
TAG supports transparent proxy mode (default) with local SigV4 validation and per-bucket authorization caching, as well as signing mode with local credential stores.
See docs/security.md for authentication, access control, and security architecture.
- Go 1.24 or later
- Tigris account with access credentials (for running TAG and integration tests)
All dependencies, including Tigris's ocache modules, are public and fetched normally by the Go toolchain — no extra configuration required.
make build# Set credentials via environment variables
export AWS_ACCESS_KEY_ID=your_access_key
export AWS_SECRET_ACCESS_KEY=your_secret_key
# Run with default configuration
./tag
# Run with debug logging
TAG_LOG_LEVEL=debug ./tag# Run all tests
make test
# Run specific package tests
make test-auth
make test-cache
make test-proxy
# Run with race detector
make test-race
# Run S3 compatibility tests (requires AWS credentials)
make s3-test-local && make s3-testsSee docs/s3-compatibility-testing.md for detailed S3 compatibility testing guide.
# Format code
make fmt
# Run linters
make lint
# Run all checks
make check
# Generate coverage report
make test-coverageTAG is licensed under the Apache License 2.0. See NOTICE for attribution.
Contributions are welcome — see CONTRIBUTING.md. Contributors are required to sign the Contributor License Agreement.