How Trivy Handles Caching: Redis vs. Memory vs. Filesystem Backends Explained
Trivy abstracts storage through a unified Cache interface in pkg/cache/cache.go, offering three interchangeable backends—in-memory (MemoryCache), filesystem BoltDB (FSCache), and Redis (RedisCache)—that persist artifact metadata and layer blobs to eliminate redundant downloads across scans.
Scanning container images repeatedly wastes bandwidth and time when the same layers must be re-fetched from registries. According to the aquasecurity/trivy source code, the scanner mitigates this by caching two distinct data types—ArtifactInfo (image metadata and scan results) and BlobInfo (per-layer package details)—through a pluggable backend selected via the --cache-backend flag.
Cache Architecture and Data Model
Trivy’s cache system is built around a Go interface that decouples storage implementation from scanning logic. This allows operators to trade off speed, persistence, and sharing capabilities depending on the runtime environment.
The Cache Interface
The contract is defined in [pkg/cache/cache.go](https://github.com/aquasecurity/trivy/blob/main/pkg/cache/cache.go) and specifies six core operations:
PutArtifact/GetArtifact– Store and retrieve image metadata.PutBlob/GetBlob– Store and retrieve layer-level package information.MissingBlobs– Identify which artifact or blob IDs are absent from the cache.Clear– Purge all cached data.
Data Types Stored
| Type | Content | Purpose |
|---|---|---|
| ArtifactInfo | OS family, layer digests, configuration history | Avoids re-pulling image manifests. |
| BlobInfo | Installed packages, OS libraries, application dependencies | Skips re-analysis of unchanged layers. |
Selecting a Cache Backend
Backend selection follows a factory pattern implemented in [pkg/cache/client.go](https://github.com/aquasecurity/trivy/blob/main/pkg/cache/client.go), which reads CLI flags defined in [pkg/flag/cache_flags.go](https://github.com/aquasecurity/trivy/blob/main/pkg/flag/cache_flags.go).
switch opts.CacheBackend {
case cache.TypeMemory:
return cache.NewMemoryCache()
case cache.TypeFS:
return cache.NewFSCache(opts.CacheDir)
case cache.TypeRedis:
return cache.NewRedisCache(opts.RedisBackend,
opts.RedisCACert,
opts.RedisCert,
opts.RedisKey,
opts.RedisTLS,
opts.TTL)
}
Available flags include:
--cache-backend– Choosememory,fs, orredis.--cache-dir– Filesystem path (BoltDB database location).--redis-backend– Redis URL (redis://host:port/db).--redis-tls,--redis-ca-cert,--redis-cert,--redis-key– TLS configuration.--cache-ttl– Expiration duration for Redis entries (default0for no expiry).
In-Memory Cache (Transient)
The MemoryCache implementation in [pkg/cache/memory.go](https://github.com/aquasecurity/trivy/blob/main/pkg/cache/memory.go) provides zero-latency storage for ephemeral scanning workflows.
- Storage: Two
sync.Mapinstances (artifactBucket,blobBucket) keyed by ID. - Operations:
Storefor writes,Loadfor reads with type assertion; missing entries return wrappedxerrors.Errorfinstances. - Lifecycle: Data exists only for the process duration. Calling
Clearre-initializes the maps.
This backend is ideal for one-off CI jobs or local development where persistence is unnecessary and maximum speed is prioritized.
Filesystem Cache (Persistent)
The FSCache implementation in [pkg/cache/fs.go](https://github.com/aquasecurity/trivy/blob/main/pkg/cache/fs.go) uses BoltDB to provide durable, local storage.
- Database: A single
fanal.dbfile created under the directory specified by--cache-dir(default~/.cache/trivy). - Schema: Two buckets—
artifactBucketandblobBucket—store JSON-serialized structs. - Validation: On retrieval, Trivy checks
types.BlobJSONSchemaVersionandArtifactJSONSchemaVersionto ensure compatibility with the current binary. - Expiration: Not automatic; users purge stale data with
trivy cache clear, which closes the DB handle and removes the directory.
MissingBlobs performs a sequential scan of the database to filter requested IDs against stored keys, returning a slice of missing digests for the scanner to fetch.
Redis Cache (Distributed)
The RedisCache implementation in [pkg/cache/redis.go](https://github.com/aquasecurity/trivy/blob/main/pkg/cache/redis.go) enables shared caching across multiple Trivy instances using github.com/go-redis/redis/v8.
-
Key Naming: Entries use the prefix
fanal::followed by type and ID:fanal::artifact::<artifactID> fanal::blob::<blobID> -
TTL: The
--cache-ttlflag maps to RedisEXflags onSEToperations; a zero value creates permanent keys. -
TLS: When
--redis-tlsis enabled, the client loads CA, certificate, and key files viaGetTLSConfig. If certificates are omitted, a minimal TLS config (server verification only) is used. -
Clear Operation: Uses the
SCANcommand with patternfanal::*, then pipelinedUNLINK(non-blocking delete) in batches of 100 keys to avoid blocking the Redis server.
Network round-trips introduce latency, making this backend best suited for distributed CI pipelines where the cost of redundant layer downloads exceeds Redis overhead.
When to Use Each Backend
| Scenario | Recommended Backend | Rationale |
|---|---|---|
| Local ad-hoc scans | memory |
No disk I/O or setup; data discarded automatically. |
| Repeated workstation scans | fs |
Survives reboots; eliminates re-downloads for frequently analyzed images. |
| Distributed CI/CD pipelines | redis |
Shared state across parallel workers; TTL prevents unbounded growth. |
| High-security environments | redis with TLS |
Encrypted transport and optional mutual TLS authentication protect data in transit. |
Practical Configuration Examples
CLI Usage
# Ephemeral memory cache (fastest, no persistence)
trivy image --cache-backend memory alpine:3.18
# Persistent filesystem cache (default behavior)
trivy image --cache-backend fs --cache-dir /var/cache/trivy alpine:3.18
# Shared Redis cache with 1-hour TTL and mutual TLS
trivy image \
--cache-backend redis \
--redis-backend redis://cache.internal:6379/0 \
--cache-ttl 1h \
--redis-tls \
--redis-ca-cert /etc/ssl/ca.pem \
--redis-cert /etc/ssl/client.crt \
--redis-key /etc/ssl/client.key \
alpine:3.18
Programmatic Usage (Go Library)
import "github.com/aquasecurity/trivy/pkg/cache"
// In-memory: transient, zero overhead
memCache := cache.NewMemoryCache()
// Filesystem: persistent across process restarts
fsCache, err := cache.NewFSCache("/opt/trivy-cache")
if err != nil {
log.Fatal(err)
}
// Redis: remote, TTL-enabled, TLS-secured
redisCache, err := cache.NewRedisCache(
"redis://redis.example.com:6379/0",
"/etc/ssl/ca.pem", // CA certificate
"/etc/ssl/client.crt", // Client certificate
"/etc/ssl/client.key", // Client key
true, // Enable TLS
time.Hour, // TTL
)
if err != nil {
log.Fatal(err)
}
Summary
- Trivy caches two data types—
ArtifactInfoandBlobInfo—through a unified interface inpkg/cache/cache.go. - Three backends implement this interface:
MemoryCache(ephemeral,sync.Map),FSCache(BoltDB on disk), andRedisCache(remote with TTL). - Selection occurs in
pkg/cache/client.gobased on the--cache-backendflag, with Redis offering additional TLS and TTL controls. - Filesystem is the default for standalone CLI usage, while Redis optimizes distributed CI environments through shared state and configurable expiration.
Frequently Asked Questions
How do I switch between cache backends in Trivy?
Use the --cache-backend flag with values memory, fs, or redis. For example, trivy image --cache-backend redis --redis-backend redis://localhost:6379/0 image:tag. The factory logic in pkg/cache/client.go instantiates the corresponding implementation based on this flag.
Does Trivy’s Redis cache support TLS encryption?
Yes. Set --redis-tls to enable TLS, and optionally provide --redis-ca-cert, --redis-cert, and --redis-key for mutual TLS authentication. If only --redis-tls is specified, the client uses a minimal TLS configuration that verifies the server certificate without presenting a client certificate.
What happens when a Redis cache entry reaches its TTL?
When --cache-ttl is specified (e.g., 30m), Trivy passes this duration to Redis during each SET operation. Once the TTL expires, Redis automatically deletes the key. Subsequent scans treat the missing entry as a cache miss and re-download the corresponding layer or artifact data.
Can I use Trivy as a Go library with a custom cache implementation?
Yes. The Cache interface in pkg/cache/cache.go is public, allowing you to implement custom storage backends (e.g., S3, PostgreSQL) by satisfying the PutArtifact, GetArtifact, PutBlob, GetBlob, MissingBlobs, and Clear method signatures. Pass your implementation to the scanner initializer to replace the built-in backends.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →