Bastion
1.x
Docs/Bastion/Response Caching
Open

Reading3 min
Updated31 Jul 2026
Sourcev1/subsystems/caching.mdx

Bastion caches HTTP responses to reduce upstream load and improve response times. The caching subsystem respects standard Cache-Control headers, supports per-route policies, and provides a pluggable store interface for custom backends.

Configuration01

bastion.WithCaching(bastion.CachingConfig{
    Enabled:    true,
    DefaultTTL: 5 * time.Minute,
    MaxSize:    1000,
    Methods:    []string{"GET", "HEAD"},
    VaryBy:     []string{"Accept", "Accept-Language"},
})

Configuration Fields

FieldTypeDefaultDescription
EnabledboolfalseEnable or disable response caching
DefaultTTLtime.Duration5mDefault cache entry lifetime
MaxSizeint1000Maximum number of cached responses (in-memory store)
Methods[]string["GET", "HEAD"]HTTP methods eligible for caching
VaryBy[]string[]Headers to include in the cache key

Cache-Control Header Respect02

The cache respects standard Cache-Control directives from both the client and the upstream:

Client Directives

DirectiveBehavior
no-cacheBypass cache, fetch from upstream
no-storeBypass cache, fetch from upstream

Upstream Directives

DirectiveBehavior
no-storeResponse is not cached
privateResponse is not cached
max-age=NResponse is cached for N seconds (overrides DefaultTTL)

TTL Priority

The effective TTL for a cached response is determined in this order:

  1. Per-route TTL (if configured)

  2. Upstream Cache-Control: max-age header

  3. Global DefaultTTL

Per-Route Cache Policies03

Individual routes can override or disable caching:

bastion.WithRoute(bastion.RouteConfig{
    Path: "/api/products/*",
    Cache: &bastion.RouteCacheConfig{
        Enabled: true,
        TTL:     10 * time.Minute,
        Methods: []string{"GET"},
        VaryBy:  []string{"Accept", "X-Region"},
    },
    Targets: []bastion.TargetConfig{
        {URL: "http://products-svc:8080"},
    },
})

RouteCacheConfig Fields

FieldTypeDescription
EnabledboolEnable caching for this route
TTLtime.DurationCache TTL (overrides global default and max-age)
Methods[]stringCacheable methods (overrides global methods)
VaryBy[]stringHeaders to vary the cache key by (overrides global)

Disabling Cache for a Route

bastion.WithRoute(bastion.RouteConfig{
    Path: "/api/auth/*",
    Cache: &bastion.RouteCacheConfig{
        Enabled: false,
    },
    Targets: []bastion.TargetConfig{
        {URL: "http://auth-svc:8080"},
    },
})

Cache Key Generation04

Cache keys are generated from a SHA-256 hash of:

  1. HTTP method

  2. Request path

  3. Query string

  4. Values of VaryBy headers (sorted for determinism)

The resulting key format is gw:cache:<hash>. This ensures that requests with different query parameters or vary-by header values produce distinct cache entries.

Response Headers05

Cached responses include headers indicating cache status:

HeaderValueDescription
X-CacheHITResponse was served from cache
X-Cache-Age<seconds>How many seconds since the response was cached

Cacheable Responses06

Only responses meeting these criteria are cached:

  • Status code is in the 200-399 range.

  • HTTP method is in the configured Methods list.

  • The upstream response does not include Cache-Control: no-store or Cache-Control: private.

Cache Store Interface07

The caching subsystem accepts any backend that implements the CacheStore interface:

type CacheStore interface {
    Get(ctx context.Context, key string) ([]byte, error)
    Set(ctx context.Context, key string, value []byte, ttl time.Duration) error
    Delete(ctx context.Context, key string) error
}

In-Memory Store (Default)

When no external store is provided, Bastion uses an in-memory LRU cache bounded by MaxSize. Entries are evicted in FIFO order when the cache is full. Expired entries are cleaned up lazily on access and periodically via background cleanup.

Custom Store

Provide a custom store for distributed caching (e.g., Redis):

gateway.SetCacheStore(myRedisStore)

Cache Invalidation08

Admin API

The admin API exposes an endpoint to invalidate cached entries:

DELETE /gateway/api/cache

This clears the entire cache.

Programmatic Invalidation

cache.Invalidate(ctx, "GET", "/api/products/123")

Cache Metrics09

The gateway tracks cache hits and misses:

MetricDescription
gateway.cache_hits_totalTotal cache hits
gateway.cache_misses_totalTotal cache misses

These are also available in GatewayStats.CacheHits and GatewayStats.CacheMisses via the admin API and dashboard.