Cache

Nimbus provides a unified caching API with support for memory, Redis, Memcached, DynamoDB, and Cloudflare KV. Call cache.Boot(nil) in your server boot to initialize from .env.

Documentation

Detailed guides:

Remember (getOrSet)

The most common pattern: try cache first, otherwise compute, store, and return.

// Boot in bin/server.go (uses CACHE_DRIVER from .env)
cache.Boot(nil)

user, err := cache.RememberT("user:1", 10*time.Minute, func() (User, error) {
    var u User
    err := database.Get().First(&u, 1).Error
    return u, err
})

Get, Set, Has, Missing, Pull

Use Get and Set when you need more control. Has / Missing check existence without fetching. Pull retrieves and deletes in one call (e.g. flash messages).

cache.Set("app:settings", map[string]any{"theme": "dark"}, 5*time.Minute)
settings, ok := cache.Get("app:settings")

cache.SetForever("app:version", "2.0.0")  // never expires

if cache.Has("products:featured") { /* key exists */ }
token, ok := cache.Pull("verify:token:123")  // get and delete

Namespaces

Group related keys under a prefix and clear them together.

usersCache := cache.Namespace("users")
usersCache.Set("42", user, 10*time.Minute)  // stores under "users:42"
usersCache.Clear()  // clears all "users:*"

Configuration

Set CACHE_DRIVER in .env. Supported: memory, redis, memcached, dynamodb, cloudflare.

DriverEnv vars
memory(default, no config)
redisREDIS_URL (e.g. redis://localhost:6379)
memcachedMEMCACHED_SERVERS (e.g. localhost:11211)
dynamodbCACHE_DYNAMO_TABLE, AWS_REGION, AWS credentials
cloudflareCLOUDFLARE_ACCOUNT_ID, CLOUDFLARE_NAMESPACE_ID, CLOUDFLARE_API_TOKEN

Real-Life Example: API Response Caching

func (ctrl *ProductController) Index(c *http.Context) error {
    page := c.QueryInt("page", 1)
    key := fmt.Sprintf("products:page:%d", page)

    products, err := cache.RememberT[[]Product](key, 5*time.Minute, func() ([]Product, error) {
        var products []Product
        err := db.Scopes(database.Paginate(page, 20)).
            Preload("Category").
            Find(&products).Error
        return products, err
    })
    if err != nil {
        return err
    }

    return c.JSON(200, products)
}

Real-Life Example: Cache Invalidation on Update

func (ctrl *ProductController) Update(c *http.Context) error {
    id := c.Param("id")

    // ... validate and update product ...

    // Invalidate specific cache entry
    cache.Delete(fmt.Sprintf("product:%s", id))

    // Invalidate related listing caches
    productsCache := cache.Namespace("products")
    productsCache.Clear()  // Clear all product listing pages

    return c.JSON(200, product)
}

Real-Life Example: Rate Limiting with Cache

func checkRateLimit(ip string, limit int) bool {
    key := fmt.Sprintf("ratelimit:%s", ip)
    val, ok := cache.Get(key)
    if !ok {
        cache.Set(key, 1, time.Minute)
        return true  // First request
    }
    count := val.(int)
    if count >= limit {
        return false  // Exceeded
    }
    cache.Set(key, count+1, time.Minute)
    return true
}

Best Practices

  • Use Remember / RememberT to eliminate cache stampede
  • Choose TTL carefully — too short wastes compute; too long serves stale data
  • Invalidate on writes — always clear cache when underlying data changes
  • Use namespaces — group related keys for easy bulk invalidation
  • Use Memory for dev, Redis for prod — switch via CACHE_DRIVER env var
  • Include user/tenant IDs in cache keys to prevent data leakage