Views

Caching

Cache controller views, partials, and Turbo frame bodies.

By Guillermo Alvarez - Published - Updated

Use the app cache

Every lazyapp.New application has a cache:

app := lazyapp.New(lazyapp.Config{
    Name:   "sample_app",
    Drawer: Draw,
    Views:  app.Views,
})

When Cache.Backend is omitted, lazyapp uses the in-memory backend from golazy.dev/lazycache/inmemorycache. Direct lazycache.New calls must pass a backend explicitly.

You can use the cache from the app value:

err := lazycache.Set(app.Cache, post, "post", post.ID, post.UpdatedAt)

and read typed values:

post, err := lazycache.Get[Post](app.Cache, "post", id, updatedAt)

The cache key is built by joining key parts with -. time.Time values use UTC RFC3339Nano, so timestamps are stable across time zones.

Cache controller renders

Controllers opt a rendered response body into caching with CacheKey:

func (c *PostsController) Show(postID int) error {
    post, err := c.posts.Get(postID)
    if err != nil {
        return err
    }

    c.Set("post", post)
    return c.CacheKey(post.ID, post.UpdatedAt)
}

The key includes the namespace when present, controller, action, request format, and the parts you pass:

admin-posts-show-html-42-2026-06-25T10:30:00Z

Use CacheKeyF when the complete key should come from the action:

return c.CacheKeyF("post", post.ID, post.UpdatedAt)

Only the rendered body is cached. Headers and status codes still come from the current request.

Cache partials

Use cache around a partial:

{{ cache "featured" "post_card" .post }}

That key is scoped to the namespace, controller, action, format, partial name, and local name.

Use cache_key for a full explicit key:

{{ cache (cache_key "post" .post.ID .post.UpdatedAt) "post_card" .post }}

cachef is the same idea without a nested helper call:

{{ cachef "post" .post.ID .post.UpdatedAt "post_card" .post }}

Cache Turbo frame bodies

Turbo frames can cache the rendered frame body while keeping current frame attributes:

{{ turbo_frame "post" .post (cache_key "post" .post.ID .post.UpdatedAt) (turbo_src .post.URL) }}

If the same key is reused later, GoLazy reuses the body and applies the current turbo_frame options again.

Switch caching

Use Off to bypass reads and turn writes into no-ops:

app.Cache.Off()

Use On to resume backend reads and writes. Stats returns the standardized backend counters:

stats := app.Cache.Stats()

In lazy development mode, the development panel exposes the same cache state, stats, keys, and On/Off switch through the app's lazydev control plane.

The first backend is in-process and stores Go values. It is useful for a single running process; choose a different backend when multiple app processes must share cached values.