High-performance, thread-safe in-memory cache for Go with expiration support and advanced features.
- β‘ High Performance: Optimized for concurrent access with optional sharding
- π Thread-Safe: All operations protected with RWMutex
- β° Flexible Expiration: Per-item, default, or no expiration
- π§Ή Janitor: Background cleanup with runtime control
- πΎ Serialization: Persist cache to disk using Gob encoding
- π‘οΈ Overflow Protection: Built-in protection for numeric operations
- π High Concurrency: Sharded cache for reduced lock contention (2-4x faster)
- π― Simple API: Intuitive interface, easy to integrate
go get github.com/pzentenoe/go-cachepackage main
import (
"fmt"
"time"
"github.com/pzentenoe/go-cache"
)
func main() {
// Create cache with 5-minute default expiration and 10-minute cleanup
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)
}
}// Use sharded cache for high-concurrency workloads
sc := cache.NewSharded(5*time.Minute, 10*time.Minute, 32)
// Same API as standard cache
sc.Set("key", "value", cache.DefaultExpiration)
val, found := sc.Get("key")- Getting Started - Installation, basic usage, core concepts
- API Reference - Complete method documentation
- Sharded Cache - High-concurrency usage guide
- Serialization - Persist cache to disk
- Janitor Control - Runtime cleanup management
Runnable examples in examples/:
- Basic Usage - Core operations and expiration
- Sharded Cache - High-concurrency patterns
- Serialization - Save/Load cache data
- Concurrent Operations - Thread-safe operations
- Overflow Protection - Numeric operation safety
- Janitor Control - Runtime cleanup management
- Filesystem Persistence - Production-ready cache persistence
Run any example:
cd examples/basic && go run main.go// Set operations
c.Set("key", "value", cache.DefaultExpiration)
c.SetDefault("key", "value")
c.Add("key", "value", 5*time.Minute) // Only if not exists
c.Replace("key", "new", 5*time.Minute) // Only if exists
// Get operations
val, found := c.Get("key")
val, expTime, found := c.GetWithExpiration("key")
// Delete operations
c.Delete("key")
c.DeleteExpired() // Remove expired items
c.Flush() // Remove all itemsAll numeric operations include overflow/underflow protection:
// Increment/Decrement
c.Increment("counter", 1)
c.Decrement("counter", 1)
c.IncrementFloat("price", 5.50)
// Type-safe operations with error handling
result, err := c.IncrementUint64("views", 100)
if err != nil {
// Overflow would occur
}// Save and load cache to/from disk
c.SaveFile("cache.gob")
c.LoadFile("cache.gob")// Runtime cleanup management
c.PauseJanitor()
c.ResumeJanitor()
c.SetJanitorInterval(5 * time.Minute)
// Stop janitor goroutine when done
c.Close()The latest release (v1.4.0) adds sentinel errors for errors.Is, fixes several panic and race conditions in janitor lifecycle and typed operations, and deduplicates internals with generics β with full backward compatibility. See CHANGELOG.md for full version history and release notes.
Measured on Apple M4 Pro, Go 1.26, go test -bench=. -benchmem -benchtime=1s. All operations are zero-allocation:
| Benchmark | ns/op | B/op | allocs/op |
|---|---|---|---|
| Cache Get (not expiring) | 7.2 | 0 | 0 |
| Cache Get (expiring) | 33.7 | 0 | 0 |
| Cache Set | 13.6 | 0 | 0 |
| Cache IncrementInt64 | 26.3 | 7 | 0 |
| ShardedCache Get (not expiring) | 10.3 | 0 | 0 |
| ShardedCache Set | 18.7 | 0 | 0 |
| ShardedCache Increment | 28.6 | 8 | 0 |
Under concurrent load the sharded cache pulls ahead by design (per-shard locks):
| Concurrent benchmark (100 goroutines, own keys) | Cache | ShardedCache | Speedup |
|---|---|---|---|
| Increment | 125.6 ns/op | 33.5 ns/op | ~3.7x |
| Get (10k goroutines, not expiring) | 124.6 ns/op | 12.1 ns/op | ~10x |
Standard cache (New):
- Suitable for most applications
- Single RWMutex for all operations
- Fastest single-threaded reads
Sharded cache (NewSharded):
- Recommended for high-concurrency scenarios
- Independent shards with separate locks (configurable: 8, 16, 32, 64)
- β High concurrent read/write operations (100+ goroutines)
- β Lock contention identified in profiling
- β Maximum throughput required
Run them yourself:
go test -run=NONE -bench=. -benchmemSee Sharded Cache Guide for best practices.
All operations are thread-safe and can be called from multiple goroutines:
var wg sync.WaitGroup
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)
c.Get(fmt.Sprintf("key%d", id))
}(i)
}
wg.Wait()The cache uses interface{} internally, supporting any Go type. Use type assertions when retrieving values:
// Storing values
c.Set("user", User{Name: "Alice"}, cache.DefaultExpiration)
c.Set("count", 42, cache.DefaultExpiration)
// Retrieving with type assertion
if val, found := c.Get("user"); found {
user := val.(User) // Type assertion
fmt.Println(user.Name)
}
// Safe type assertion
if val, found := c.Get("count"); found {
if count, ok := val.(int); ok {
fmt.Println("Count:", count)
}
}For numeric operations, use the built-in increment/decrement methods which handle types safely.
We welcome contributions! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Add tests for new functionality
- Ensure tests pass and coverage is maintained (currently 92.9%):
go test -race ./... # Run with race detector go test -cover ./... # Check coverage
- Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see LICENSE file for details.
See CHANGELOG.md for version history and release notes.
- π Documentation
- π¬ Issues
- π Star on GitHub
Thank you for your support! β€οΈ
Pablo Zenteno - pzentenoe
