Skip to content

Configuration

Basic setup

CACHES = {
    "default": {
        "BACKEND": "django_vcache.backend.ValkeyCache",
        "LOCATION": "valkey://your-valkey-host:6379/1",
    },
}

URL schemes

Scheme Description
valkey:// Standard Valkey connection
redis:// Standard Redis connection
valkeys:// TLS-encrypted Valkey connection
rediss:// TLS-encrypted Redis connection
sentinel:// Valkey/Redis Sentinel

Options

Options are set in the OPTIONS dictionary:

CACHES = {
    "default": {
        "BACKEND": "django_vcache.backend.ValkeyCache",
        "LOCATION": "valkey://your-valkey-host:6379/1",
        "OPTIONS": {
            "SERIALIZER": "msgpack",
            "COMPRESS_MIN_LEN": 1024,
        },
    },
}

SERIALIZER

Default: "msgpack"

Choose the serialization format:

  • "msgpack" (default) — Fast and secure. Uses ormsgpack. Cannot execute arbitrary code on deserialization.
  • "pickle" — For projects that need to cache arbitrary Python objects (Django models, custom classes, etc.).

Warning

Pickle can execute arbitrary code on deserialization. Only use it if you trust all data in your cache.

COMPRESS_MIN_LEN

Default: 1024

Values larger than this threshold (in bytes) are automatically compressed with zstd. Set to 0 to disable compression.

"OPTIONS": {
    "COMPRESS_MIN_LEN": 2048,  # compress values larger than 2KB
}

IGNORE_EXCEPTIONS

Default: False

When True, connection failures degrade to cache misses instead of raising: get returns the default, set/delete/touch return False, incr returns 0, get_many returns {}, and set_many reports every key as failed. Use this when a down cache server should degrade gracefully rather than take requests down with it.

"OPTIONS": {
    "IGNORE_EXCEPTIONS": True,
}

Only connection-level errors are swallowed — data errors (e.g. incr on a non-integer value) always raise.

Note

With the default IGNORE_EXCEPTIONS: False, the resilience wrapper is stripped from the hot path at init time by rebinding the undecorated methods onto the cache instance. A side effect: patching methods on the ValkeyCache class (e.g. mock.patch.object(ValkeyCache, "get")) does not affect already-created instances. Patch the instance instead (mock.patch.object(cache, "get")), which works and restores correctly.

CLIENT_SIDE_CACHE

Default: disabled

Opt-in server-assisted client-side caching (requires Valkey/Redis 6.0+ and RESP3). Repeated gets of hot keys are served from an in-process cache that the server invalidates on writes:

"OPTIONS": {
    "CLIENT_SIDE_CACHE": {
        "ENABLED": True,
        "MAX_SIZE": 10_000,   # cached entries (default)
        "TTL": 300,           # seconds (default)
    },
}

cache.get_raw_client().cache_statistics() returns (hits, misses, invalidations) or None when disabled. Not supported in cluster mode.

DRIVER_CLASS

Default: the bundled RustValkeyDriver

Advanced hook for downstream Rust extensions: accepts a driver class or a dotted-path string implementing ValkeyDriverProtocol (see django_vcache/backend.py). Lets an application that ships its own Rust extension route the cache through a driver living in that extension's .so, so the cache shares one tokio runtime and connection with the app's other Rust I/O instead of running two runtimes side by side.

"OPTIONS": {
    "DRIVER_CLASS": "myapp._rust.ValkeyDriver",
}

Pick one driver source per process — the bundled driver and a downstream .so each carry their own tokio runtime, so mixing them runs two runtimes.

CLUSTER_MODE

Default: False

Enable for Valkey/Redis Cluster deployments. The LOCATION should point to one of the cluster's nodes; the driver automatically discovers the rest.

CACHES = {
    "default": {
        "BACKEND": "django_vcache.backend.ValkeyCache",
        "LOCATION": "valkey://your-cluster-node-1:6379/0",
        "OPTIONS": {
            "CLUSTER_MODE": True,
        },
    },
}

Note

Distributed locking (cache.lock() and cache.alock()) is not supported in cluster mode. Attempting to use these methods will raise NotImplementedError.

Sentinel

Use a sentinel:// URL to connect via Valkey/Redis Sentinel. The URL format is:

sentinel://sentinel-host:26379/master-name/db

Example:

CACHES = {
    "default": {
        "BACKEND": "django_vcache.backend.ValkeyCache",
        "LOCATION": "sentinel://sentinel-host:26379/mymaster/1",
    },
}

The driver automatically re-discovers the master on failover.

Authentication

Sentinel returns only the master's host and port on discovery — never its credentials — so a password-protected master must be authenticated separately. The URL userinfo carries the master's credentials:

sentinel://:master-password@sentinel-host:26379/master-name/db
sentinel://master-user:master-password@sentinel-host:26379/master-name/db

This covers the common topology of unauthenticated Sentinels in front of a password-protected master. When the Sentinel nodes themselves require authentication, supply their credentials separately with the sentinel_username / sentinel_password query parameters — these are distinct from the master credentials:

sentinel://:master-password@sentinel-host:26379/master-name/db?sentinel_password=sentinel-password

Credentials in the URL must be percent-encoded if they contain reserved characters (@, :, /, etc.).

IPv6 Sentinel hosts must be bracketed:

sentinel://[2001:db8::1]:26379,[2001:db8::2]:26379/master-name/db

TLS certificates

Use a valkeys:// or rediss:// URL scheme with ssl_ca_certs to connect over TLS:

CACHES = {
    "default": {
        "BACKEND": "django_vcache.backend.ValkeyCache",
        "LOCATION": "valkeys://your-valkey-host:6380/1",
        "OPTIONS": {
            "ssl_ca_certs": "/path/to/ca.crt",
            "ssl_certfile": "/path/to/client.crt",  # optional, for mTLS
            "ssl_keyfile": "/path/to/client.key",    # optional, for mTLS
        },
    },
}

ssl_ca_certs

Path to a PEM file containing the CA certificate used to verify the server's certificate. This is required for TLS connections — mount your CA certificate into the container and reference it here.

ssl_certfile / ssl_keyfile

Paths to PEM files for mutual TLS (mTLS) client authentication. Both must be provided together. Only needed when the server requires client certificate authentication.

ssl_cert_reqs

Default: "required"

Set to "none" to skip certificate verification entirely (uses TLS encryption without validating the server's certificate). This is useful for self-signed certificates when you don't have access to the CA cert:

"OPTIONS": {
    "ssl_cert_reqs": "none",
}

Environment variables

VCACHE_TOKIO_WORKER_THREADS

Default: 1

Worker-thread count for the driver's tokio runtime. One thread is optimal for the driver's own workload (I/O-bound tasks on a multiplexed connection); raise it only if you push additional CPU-heavy work onto this runtime from Rust.

Applies only to vcache's own runtime. When a downstream extension installs a runtime provider (set_runtime_provider, see DRIVER_CLASS), that shared runtime's own configuration governs sizing — for combined workloads (cache + database pool + app I/O on one pool) a larger, CPU-count-sized pool is the sensible default, and this variable has no effect.

VCACHE_COMMAND_RETRIES

Default: 1

How many times a transport failure re-issues a command before the error reaches the caller. Server errors (WRONGTYPE, OOM, NOSCRIPT) are answers, not lost connections, and are never retried.

One retry is the default because the failure usually says nothing about the command that hit it: a pooled connection whose peer went away while it sat idle (server restart, failover, a load balancer reaping an idle socket) fails on the first write. For a Django cache backend that lands on a request — a silent miss with IGNORE_EXCEPTIONS, a 500 without it.

There is no sleep between attempts: the driver reconnects in the background and the retry awaits that reconnect, which carries its own backoff.

Only operations whose repeated application is indistinguishable from a single application are retried — reads, SET, DEL, EXPIRE, PERSIST, SCAN, FLUSHDB, SCRIPT LOAD. These are not retried, because a second application would be observable:

Not retried Why
INCRBY / DECRBY (incr/decr) double-counts if the first reply was lost
SET NX (add) the boolean is the result; a retry reports False after a successful set
lock acquire / release / extend same — the boolean is the mutual-exclusion answer
EVAL / EVALSHA arbitrary script side effects
arbitrary pipelines (pipeline_exec) may have partially applied
LPUSH / RPUSH / RPOP / LREM / LTRIM queue semantics; a retry duplicates or over-removes
BLMOVE / BLMPOP a retry can orphan an element into the processing list

Set to 0 to restore raise-on-first-failure.

Note that a disconnect happening between commands needs no retry at all — the driver reconnects in the background and the next command transparently waits for the new connection. The retry matters for a connection that dies with a command already in flight.

VCACHE_MAX_IDLE_BLOCKING_CONNS

Default: 4

Each in-flight blocking operation (BLMOVE/BLMPOP, used by task queues such as django-vtasks) holds a dedicated connection, checked out of an idle pool. This caps how many idle connections are retained for reuse. If you run more than this many concurrent blocking consumers per process, raise it to match, or completions beyond the cap will drop and recreate connections on every cycle.