Putnami
DocsGitHub

Licensed under FSL-1.1-MIT

Getting Started
Concepts
How To
Build A Web App
Build An Api Service
Share Code Between Projects
Configure Your App
Add Persistence
Add Authentication
Add Background Jobs
Develop With Ai
Structure Business Logic With Di
Upgrade Putnami
Principles
Tooling & Workspace
Workspace
Cli
Jobs & Caching
Extensions
Templates
Error Handling
Frameworks
Typescript
ExtensionOverviewWebReact RoutingForms And ActionsStatic FilesApiErrors And ResponsesConfigurationLoggingHttp And MiddlewareDependency InjectionPlugins And LifecycleSessionsAuthPersistenceEventsStorageCachingWebsocketsTestingHealth ChecksTelemetryProto GrpcSmart ClientSchema
Go
ExtensionOverviewHttpDependency InjectionPlugins And LifecycleConfigurationSecurityPersistenceErrorsEventsStorageCachingLoggingTelemetryGrpcService ClientsValidationOpenapiTesting
Python
Extension
Platform
Ci
  1. DocsSeparator
  2. FrameworksSeparator
  3. GoSeparator
  4. Caching

Caching

go.putnami.dev/cache provides a generic caching layer with in-memory, disk, and layered implementations. All caches are safe for concurrent use.

Cache interface

All implementations share the same interface:

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

Memory cache

In-memory cache with optional FIFO eviction:

import "go.putnami.dev/cache"

c := cache.NewMemoryCache(cache.MemoryConfig{
    MaxEntries:      1000,           // 0 = unlimited
    CleanupInterval: 5 * time.Minute,
})
defer c.Close()

Configuration

Field Type Default Description
MaxEntries int 0 Maximum entries (0 = unlimited). FIFO eviction when exceeded
CleanupInterval time.Duration — Interval for removing expired entries

Disk cache

Filesystem-backed persistent cache that survives process restarts:

c, err := cache.NewDiskCache(cache.DiskConfig{
    Dir:             "./cache",
    CleanupInterval: 10 * time.Minute,
})
if err != nil {
    log.Fatal(err)
}
defer c.Close()

Objects are stored as files with SHA-256 hashed filenames. The directory is created automatically if it doesn't exist.

Configuration

Field Type Default Description
Dir string — Cache directory (created if needed)
CleanupInterval time.Duration — Interval for removing expired entries

Layered cache

Compose an L1/L2 cache hierarchy. On a cache miss in L1, the value is fetched from L2 and promoted to L1:

memory := cache.NewMemoryCache(cache.MemoryConfig{MaxEntries: 100})
disk, _ := cache.NewDiskCache(cache.DiskConfig{Dir: "./cache"})

c := cache.NewLayeredCache(memory, disk)
defer c.Close()

Behavior

Operation L1 (memory) L2 (disk)
Get Check first; on miss, fetch from L2 and promote Checked on L1 miss
Set Write Write
Delete Delete Delete
Clear Clear Clear

Operations

Set and get

// Store with TTL
err := c.Set(ctx, "user:123", []byte(`{"name":"Jane"}`), 5*time.Minute)

// Store without expiration
err := c.Set(ctx, "config", data, 0)

// Retrieve
value, found := c.Get(ctx, "user:123")
if !found {
    // cache miss or expired
}

Check and delete

if c.Has(ctx, "user:123") {
    // key exists and is not expired
}

err := c.Delete(ctx, "user:123")

// Clear all entries
err := c.Clear(ctx)

Patterns

Cache-aside

func (s *UserService) GetUser(ctx context.Context, id string) (*User, error) {
    key := "user:" + id

    // Check cache
    if data, found := s.cache.Get(ctx, key); found {
        var user User
        json.Unmarshal(data, &user)
        return &user, nil
    }

    // Cache miss — fetch from database
    user, err := s.repo.FindByID(ctx, "id", id)
    if err != nil {
        return nil, err
    }

    // Store in cache
    data, _ := json.Marshal(user)
    s.cache.Set(ctx, key, data, 10*time.Minute)

    return &user, nil
}

Cache invalidation

func (s *UserService) UpdateUser(ctx context.Context, id string, input UpdateInput) error {
    if err := s.repo.Update(ctx, id, input); err != nil {
        return err
    }
    // Invalidate cached entry
    return s.cache.Delete(ctx, "user:"+id)
}

Related guides

  • Persistence — database queries to cache
  • Configuration — cache configuration

On this page

  • Caching
  • Cache interface
  • Memory cache
  • Configuration
  • Disk cache
  • Configuration
  • Layered cache
  • Behavior
  • Operations
  • Set and get
  • Check and delete
  • Patterns
  • Cache-aside
  • Cache invalidation
  • Related guides