Install go-cache using Go modules:
go get github.com/pzentenoe/go-cachepackage main
import (
"fmt"
"time"
"github.com/pzentenoe/go-cache"
)
func main() {
// Create a cache with 5-minute default expiration
// and 10-minute cleanup interval
c := cache.New(5*time.Minute, 10*time.Minute)
// Set a value
c.Set("mykey", "myvalue", cache.DefaultExpiration)
// Get a value
if val, found := c.Get("mykey"); found {
fmt.Println("Found:", val)
}
}go-cache supports three types of expiration:
- Default Expiration: Uses the cache's default expiration time
c.Set("key", "value", cache.DefaultExpiration)
c.SetDefault("key", "value") // Same as above- Custom Expiration: Specify a custom duration
c.Set("key", "value", 30*time.Second)- No Expiration: Item never expires
c.Set("key", "value", cache.NoExpiration)The janitor automatically removes expired items at regular intervals:
// Create cache with cleanup every 10 minutes
c := cache.New(5*time.Minute, 10*time.Minute)
// Create cache without automatic cleanup
c := cache.New(5*time.Minute, 0)When automatic cleanup is disabled, you can manually trigger it:
c.DeleteExpired()// Set with default expiration
c.Set("user:1", "Alice", cache.DefaultExpiration)
// Set with custom expiration
c.Set("session", "abc123", 1*time.Hour)
// Set without expiration
c.Set("config", appConfig, cache.NoExpiration)
// Add (only if not exists)
err := c.Add("user:1", "Bob", cache.DefaultExpiration)
if err != nil {
// Key already exists
}
// Replace (only if exists)
err = c.Replace("user:1", "Charlie", cache.DefaultExpiration)// Simple get
if val, found := c.Get("user:1"); found {
user := val.(string)
fmt.Println(user)
}
// Get with expiration info
if val, expTime, found := c.GetWithExpiration("user:1"); found {
user := val.(string)
if !expTime.IsZero() {
fmt.Println("Expires at:", expTime)
}
}// Delete single item
c.Delete("user:1")
// Delete all expired items
c.DeleteExpired()
// Delete all items
c.Flush()// Integer operations
c.Set("counter", int64(0), cache.NoExpiration)
c.Increment("counter", 1)
c.Decrement("counter", 1)
// Typed operations (with overflow protection)
c.Set("views", uint64(100), cache.NoExpiration)
result, err := c.IncrementUint64("views", 50)
if err != nil {
// Overflow would occur
}
// Float operations
c.Set("price", 19.99, cache.NoExpiration)
c.IncrementFloat("price", 5.00) // 24.99
c.DecrementFloat("price", 2.50) // 22.49go-cache stores values as any (interface{}). You need to type assert when retrieving:
type User struct {
Name string
Email string
}
user := User{Name: "Alice", Email: "alice@example.com"}
c.Set("user:1", user, cache.DefaultExpiration)
// Type assertion
if val, found := c.Get("user:1"); found {
user := val.(User)
fmt.Println(user.Name)
}Execute custom logic when items are evicted:
c.OnEvicted(func (key string, value any) {
fmt.Printf("Evicted: %s = %v\n", key, value)
})
// Callback is triggered on:
// - Delete()
// - DeleteExpired() (for expired items)
// - Manual eviction
// NOT triggered on Set() overwritesAll operations are thread-safe. The cache uses sync.RWMutex for concurrent access:
var wg sync.WaitGroup
// Safe concurrent writes
for i := 0; i < 100; i++ {
wg.Add(1)
go func (id int) {
defer wg.Done()
c.Set(fmt.Sprintf("key%d", id), id, cache.DefaultExpiration)
}(i)
}
wg.Wait()- Short-lived data (1-5 minutes): API responses, session tokens
- Medium-lived data (5-30 minutes): User preferences, configuration
- Long-lived data (1+ hours): Static content, rarely-changing data
- No expiration: Use
cache.NoExpirationsparingly (requires manual cleanup)
Use NewSharded() when:
- ✅ You have 100+ concurrent goroutines accessing the cache
- ✅ Profiling shows lock contention on cache operations
- ✅ Maximum throughput is critical
Stick with standard New() when:
- ❌ Low concurrency (< 10 goroutines)
- ❌ Small dataset (< 1,000 items)
- ❌ Simplicity is more important than performance
- Set appropriate expiration times to prevent unbounded growth
- Use
Flush()to clear cache when needed (e.g., during maintenance) - Monitor memory usage with
ItemCount() - Consider pausing the janitor during bulk operations
Always check return values:
// Check if item exists
if val, found := c.Get("key"); found {
// Safe to use val
}
// Handle overflow errors
result, err := c.IncrementUint64("counter", 1)
if err != nil {
log.Printf("Increment failed: %v", err)
}Use safe type assertions:
// Safe: checks type before using
if val, found := c.Get("user"); found {
if user, ok := val.(User); ok {
fmt.Println(user.Name)
}
}
// Unsafe: can panic
user := val.(User) // Only use if you're certain of the type- API Reference - Complete method documentation
- Sharded Cache - High-concurrency usage
- Serialization - Persist cache to disk
- Examples - Runnable code examples