# How CasaOS Implements Caching with Its Cache Package: Architecture and Usage

> Discover how CasaOS implements caching with its cache package. Learn about the architecture, usage, and the thread-safe caching layer integrated with go-cache.

- Repository: [IceWhale/CasaOS](https://github.com/IceWhaleTech/CasaOS)
- Tags: architecture
- Published: 2026-06-26

---

**CasaOS implements a lightweight, thread-safe caching layer by wrapping the `patrickmn/go-cache` library in a singleton pattern with a 5-minute default TTL and 60-second cleanup interval.**

The CasaOS cache package provides an in-process memory store for the IceWhaleTech/CasaOS repository, eliminating the need for external dependencies like Redis while offering fast temporary storage for frequently accessed data. This implementation leverages a global cache instance initialized at boot time, making it accessible across all service components through a simple API.

## Cache Package Architecture and Dependencies

CasaOS does not implement a custom caching algorithm from scratch. Instead, it creates a thin abstraction over the well-established `patrickmn/go-cache` library to handle expiration and garbage collection.

### The Wrapper Implementation in [`pkg/cache/cache.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/pkg/cache/cache.go)

The core initialization logic resides in [`pkg/cache/cache.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/pkg/cache/cache.go), which imports `github.com/patrickmn/go-cache` and exposes a single helper function:

```go
// pkg/cache/cache.go
import (
    "github.com/patrickmn/go-cache"
    "time"
)

// Init creates a global cache instance with a default
// expiration of 5 minutes and a cleanup interval of 60 seconds.
func Init() *cache.Cache {
    return cache.New(5*time.Minute, 60*time.Second)
}

```

This function establishes the default **time-to-live (TTL)** of 5 minutes for all cache entries, coupled with a background cleanup routine that purges expired items every 60 seconds.

### Global Cache Variable in [`service/service.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/service/service.go)

To ensure the cache is accessible throughout the application without dependency injection complexity, CasaOS declares a global pointer in the service layer:

```go
// service/service.go
import "github.com/patrickmn/go-cache"

var Cache *cache.Cache

```

This global variable acts as the single source of truth for all caching operations, allowing any component to read from or write to the cache directly.

## Boot-Time Initialization and Configuration

The cache follows a singleton pattern established during application startup, ensuring consistent behavior across the lifespan of the CasaOS process.

### Initializing the Cache in [`main.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/main.go)

When the CasaOS application launches, the `Init()` function is called and the result is assigned to the global variable:

```go
// main.go
import "github.com/IceWhaleTech/CasaOS/pkg/cache"

func main() {
    // ...
    service.Cache = cache.Init()
    // ...
}

```

This initialization sequence ensures the cache is ready before any service components attempt to store or retrieve data, preventing nil pointer dereferences.

### Configuring Cache Expiration in [`model/storage.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/model/storage.go)

While the global cache uses fixed defaults, CasaOS exposes configuration flexibility through struct definitions. The [`model/storage.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/model/storage.go) file includes a `CacheExpiration` field that allows specific storage backends to define their own TTL values:

```go
// model/storage.go (simplified)
type Storage struct {
    CacheExpiration time.Duration
    // ... other fields
}

```

Although the global cache instance maintains its 5-minute default, individual components can override expiration times per-entry using the `Set` method's duration parameter.

## Usage Patterns and Thread Safety

The underlying `go-cache` library handles all concurrency concerns with internal mutex locks, making `service.Cache` safe for concurrent access across goroutines without additional synchronization.

### Standard Get-Set Pattern

Components interact with the cache using a straightforward check-store-retrieve flow:

```go
package main

import (
    "fmt"
    "github.com/IceWhaleTech/CasaOS/pkg/cache"
    "github.com/IceWhaleTech/CasaOS/service"
    "time"
)

func main() {
    // Initialize the global cache (normally done in main.go)
    service.Cache = cache.Init()
    
    // Store a value with a custom 2-minute expiration
    service.Cache.Set("user:123", "John Doe", 2*time.Minute)
    
    // Retrieve the value later
    if v, found := service.Cache.Get("user:123"); found {
        fmt.Println("Cached user:", v)
    } else {
        fmt.Println("Cache miss - compute and store")
    }
}

```

Entries not explicitly assigned a TTL inherit the 5-minute default expiration established during initialization. The automatic cleanup mechanism removes expired objects every 60 seconds, preventing memory leaks from stale data.

## Summary

CasaOS implements caching through a deliberate, minimalist approach:

- **Single global instance**: A singleton `*cache.Cache` created at startup in [`main.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/main.go) and exposed via `service.Cache`
- **Sensible defaults**: 5-minute default expiration with 60-second garbage collection cycles
- **Thread-safe access**: Leverages `patrickmn/go-cache` internal mutexes for concurrent safety
- **Zero external dependencies**: Requires no Redis or Memcached servers, reducing operational complexity
- **Configurable per-entry**: Supports custom TTLs via the `Set` method while maintaining global defaults

This design prioritizes simplicity and performance for a single-node operating system deployment.

## Frequently Asked Questions

### How does CasaOS handle cache expiration?

CasaOS relies on the `patrickmn/go-cache` library's built-in expiration mechanism. When initialized in [`pkg/cache/cache.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/pkg/cache/cache.go), the cache uses a default expiration of 5 minutes and runs a cleanup interval of 60 seconds to automatically purge stale entries. Developers can override the TTL for individual items using the `Set` method's duration parameter.

### Is the CasaOS cache safe for concurrent access?

Yes, the cache is fully thread-safe. The underlying `go-cache` library implements internal read-write mutexes (`sync.RWMutex`) to protect the cache map. Since CasaOS exposes a single global instance via `service.Cache`, multiple goroutines can safely call `Get`, `Set`, and `Delete` operations without implementing additional synchronization logic.

### Why does CasaOS use a global variable for caching instead of dependency injection?

CasaOS opts for a global `Cache` variable declared in [`service/service.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/service/service.go) to simplify the architecture and reduce boilerplate across the codebase. This approach eliminates the need to pass cache references through multiple layers of constructors, making it easier for various service components to access temporary storage while the application maintains a single cache instance initialized at boot time.

### Can I configure the default cache TTL in CasaOS?

The default TTL of 5 minutes and cleanup interval of 60 seconds are hardcoded in the `Init()` function within [`pkg/cache/cache.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/pkg/cache/cache.go). While you cannot change these global defaults without modifying the source code, you can specify custom durations when calling `service.Cache.Set("key", value, customDuration)` for individual entries. The [`model/storage.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/model/storage.go) file also defines `CacheExpiration` fields for storage-specific configuration, though these require manual integration with the global cache instance.