Skip to main content
KVStore provides a way to share small string values across all your serverless runners. It supports two operations: get and set. Use it for caching computation results, sharing configuration between runners, or storing small pieces of state that multiple runners need to read. It requires no setup and uses automatic authentication with your fal credentials. Unlike persistent storage on /data (a distributed filesystem for large files like model weights), KVStore is a remote key-value API accessed over HTTP. It is best suited for small, frequently-read values where you need cross-runner consistency. It does not support deletion, expiration, listing keys, or atomic operations, so it is not appropriate for counters, locks, or anything requiring transactional guarantees.

API Reference

Initialize KVStore

from fal.toolkit.kv import KVStore

kv = KVStore("myapp")  # "myapp" is your namespace
Each namespace is isolated - different db_name values create separate key-value stores.

Methods

get(key: str) -> Optional[str] Retrieve a value from the store. Returns None if the key doesn’t exist.
value = kv.get("my-key")
if value is None:
    print("Key not found")
set(key: str, value: str) -> None Store a string value. The value must be a string - use json.dumps() for objects.
import json

# Store a string
kv.set("my-key", "my-value")

# Store an object as JSON
kv.set("config", json.dumps({"enabled": True, "limit": 100}))

Basic Example

import fal
import json
from fal.toolkit.kv import KVStore

class MyApp(fal.App):
    def setup(self):
        self.kv = KVStore("myapp")
    
    @fal.endpoint("/")
    def process(self, input: Input):
        # Check cache
        cache_key = f"result-{input.id}"
        cached = self.kv.get(cache_key)
        
        if cached:
            return json.loads(cached)
        
        # Compute and cache result
        result = self.expensive_operation(input)
        self.kv.set(cache_key, json.dumps(result))
        
        return result

Common Use Cases

Caching API Responses

Cache external API calls to reduce latency and costs:
class MyApp(fal.App):
    def setup(self):
        self.kv = KVStore("api-cache")
    
    @fal.endpoint("/")
    def process(self, input: Input):
        cache_key = f"weather:{input.city}"
        
        # Check cache
        cached = self.kv.get(cache_key)
        if cached:
            return json.loads(cached)
        
        # Fetch from external API
        weather = requests.get(f"https://api.weather.com/{input.city}").json()
        self.kv.set(cache_key, json.dumps(weather))
        
        return weather

Caching Computation Results

Store results of expensive operations to avoid recomputation:
class MyApp(fal.App):
    def setup(self):
        self.kv = KVStore("compute-cache")
    
    @fal.endpoint("/")
    def process(self, input: Input):
        cache_key = f"result:{input.video_id}"
        
        cached = self.kv.get(cache_key)
        if cached:
            return json.loads(cached)
        
        # Expensive video processing
        result = self.process_video(input.video_url)
        self.kv.set(cache_key, json.dumps(result))
        
        return result

Limitations

KVStore is deliberately simple. It only supports get and set on string values. There is no delete, no key listing/scanning, no TTL or expiration, and no atomic operations (no increment, no compare-and-swap). Values persist indefinitely until overwritten. If multiple runners write to the same key simultaneously, the last write wins with no conflict detection. This makes KVStore unsuitable for counters, locks, rate limiting, or anything requiring atomicity. For those use cases, use an external database like Redis or PostgreSQL. For large files (model weights, datasets), use the /data volume instead.