<!-- # hard line break macro for HTML -->

# fiftyone.operators.cache.decorator

Execution cache decorator.

Copyright 2017-2026, Voxel51, Inc.
<br/>
[voxel51.com](https://voxel51.com/)
<br/>
<br/>

**Functions:**

| [`execution_cache`](#fiftyone.operators.cache.decorator.execution_cache)([_func, residency, ttl, ...])   | Decorator for caching function results in an [`ExecutionStore`](fiftyone.operators.store.md#fiftyone.operators.store.ExecutionStore).   |
|----------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------|

### fiftyone.operators.cache.decorator.execution_cache(\_func=None, , residency='hybrid', ttl=None, max_size=None, link_to_dataset=True, key_fn=None, store_name=None, version=None, operator_scoped=False, user_scoped=False, prompt_scoped=False, jwt_scoped=False, collection_name=None, serialize=None, deserialize=None)

Decorator for caching function results in an
[`ExecutionStore`](fiftyone.operators.store.md#fiftyone.operators.store.ExecutionStore).

The function being cached must:

- accept a [`ctx`](fiftyone.operators.executor.md#fiftyone.operators.executor.ExecutionContext)
  as the first parameter
- be idempotent, i.e., same inputs produce the same outputs
- have serializable function arguments and return values
- have no side effects

#### NOTE
When `residency != "ephemeral"`, cached values must be coerced to
JSON safe types in order to be stored. By default, a default JSON
converter is used that can handle many common types, but you can
override this behavior if necessary by providing custom `serialize`
and `deserialize` functions.

Examples:

```default
from fiftyone.operators import execution_cache

# Default behavior: cache for the life of a dataset
@execution_cache
def expensive_query(ctx, path):
    return ctx.dataset.count_values(path)

# Cache in-memory, and only while the current operator prompt modal is open
@execution_cache(prompt_scoped=True, residency="ephemeral")
def expensive_query(ctx, path):
    return ctx.dataset.count_values(path)

# Cache with a custom TTL and store name
class Processor:
    @execution_cache(ttl=60, store_name="processor_cache")
    def expensive_query(self, ctx, path):
        return ctx.dataset.count_values(path)

#
# Cache at the user-level
#

def custom_key_fn(ctx, path):
    return path, ctx.user_id

@execution_cache(ttl=90, key_fn=custom_key_fn, jwt_scoped=True)
def user_specific_query(ctx, path):
    return ctx.dataset.match(F("creator_id") == ctx.user_id).count_values(path)

#
# You can manually bypass/modify the cache if necessary
#

# Bypass the cache
result = expensive_query.uncached(ctx, path)

# Set the cache for the given arguments
expensive_query.set_cache(ctx, path, value_to_cache)

# Clear the cache for a specific input
expensive_query.clear_cache(ctx, path)

# Clear all cache entries for the function
expensive_query.clear_all_caches()
expensive_query.clear_all_caches(dataset_id=dataset._doc.id)
```

* **Parameters:**
  * **residency** ( *"hybrid"*) – 

    the residency of the cache. Can be one of:
    - `"transient"`: the cache is stored in the execution store
      with `policy="evict"`
    - `"ephemeral"`: the cache is stored in memory and is cleared
      when the process ends
    - `"hybrid"` (default): a combination of transient and
      ephemeral. The cache is stored in memory and in the execution
      store. The memory cache is used first, and if the value is not
      found, it falls back to the execution store
  * **ttl** (*None*) – a time-to-live for cached values, in seconds
  * **max_size** (*None*) – a maximum size for ephemeral caches. The default size
    is 1024. The cache will evict the least recently used items when
    the size exceeds this limit
  * **link_to_dataset** (*True*) – whether to namespace cache entries to the
    current dataset. If True, any cached values are automatically
    deleted when the dataset is deleted
  * **key_fn** (*None*) – a custom function to generate cache keys. By default,
    the function arguments are used as the key by serializing them as
    JSON
  * **store_name** (*None*) – a custom name for the execution store backing the
    cache. Defaults to the function name
  * **version** (*None*) – a version number to prevent cache collisions when the
    function implementation changes
  * **operator_scoped** (*False*) – whether to tie the cache entry to the current
    operator
  * **user_scoped** (*False*) – whether to tie the cache entry to the current user
  * **prompt_scoped** (*False*) – whether to tie the cache entry to the current
    operator prompt
  * **jwt_scoped** (*False*) – whether to tie the cache entry to the current
    user’s JWT
  * **collection_name** (*None*) – override the default collection name for the
    execution store used by the cache. The default is
    `"execution_store"`
  * **serialize** (*None*) – a custom serialization function to use when caching
    values and function arguments
  * **deserialize** (*None*) – a custom deserialization function when retrieving
    cached values
