new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Drizzle ORM · all subjects

cache

52 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

Cache.put() method implementation

When implementing a custom Cache class, override put(key, response, tables, isTag, config) where key is hashed query+params, response is array of database values, tables are table names involved in the query (for invalidation), isTag indicates tag-based query, and config contains cache options.

Cache.onMutate() method implementation

When implementing a custom Cache class, override onMutate(params) which receives tags (string or string array for tag-based invalidation) and tables (table objects, table names, or arrays thereof affected by insert/update/delete). Use this to remove corresponding cache keys.

Using .$withCache() for opt-in caching

When using explicit caching (global: false), call .$withCache() on a select query to enable cache for that specific query. Without .$withCache(), queries won't read from cache.

.$withCache() options

.$withCache() accepts options: config (object to override cache config for this query), tag (string for custom cache key instead of hashing query and params), autoInvalidate (boolean to disable auto-invalidation for this query, leading to eventual consistency).

Manual cache invalidation

Use db.$cache.invalidate() to manually invalidate cached queries. Invalidation can be done by tables (pass table objects or table names as strings) or by tags (pass custom cache keys defined in .$withCache({ tag: 'key' })). Both tables and tags accept single values or arrays.

Eventual consistency with autoInvalidate disabled

When .$withCache({ autoInvalidate: false }) is set on a query, cache won't be invalidated immediately on mutations. The cached data remains until TTL expires, resulting in eventual consistency. This is useful for data that changes rarely and slight staleness is acceptable, like product listings or blog posts.

Custom cache implementation

Extend the Cache class and pass an instance to drizzle config's cache option. Implement strategy() to return 'explicit' or 'all', get(key) to retrieve cached data, put(key, response, tables, isTag, config) to store data and track tables, and onMutate(params) to handle cache invalidation on mutations.

Cache limitations - transactions

Cache extension does not work with transactions. Cache cannot be used inside db.transaction() blocks.

Cache.strategy() method implementation

When implementing a custom Cache class, override strategy() to return either 'explicit' (cache used only with .$withCache()) or 'all' (all queries cached globally). Default behavior is 'explicit'.

Cache.get() method implementation

When implementing a custom Cache class, override get(key) to accept a hashed query and parameters as the key parameter, and return the cached response values (as any[] or undefined) for that query.

Cache invalidation using db.$cache.invalidate()

Cached queries can be invalidated by tables or tags. Use db.$cache.invalidate({ tables: tableRef }) or db.$cache.invalidate({ tables: [table1, table2] }) to invalidate by table object. Use db.$cache.invalidate({ tables: 'tableName' }) or db.$cache.invalidate({ tables: ['tableName1', 'tableName2'] }) to invalidate by string table name. Use db.$cache.invalidate({ tags: 'tag_key' }) or db.$cache.invalidate({ tags: ['tag1', 'tag2'] }) to invalidate by custom tags.

Custom cache implementation extends Cache class

To create a custom cache, extend the Cache class and override methods: strategy() returns 'explicit' or 'all' (default is 'explicit'), get(key: string) retrieves cached data, put(key: string, response: any, tables: string[], isTag?: boolean, config?: CacheConfig) stores cache entries, and onMutate(params: {tags, tables}) handles cache invalidation on mutations.

Cache does not work with raw queries

The cache extension does not handle raw queries such as db.execute(sql`select 1`).

Cache does not work with transactions

Cache cannot be used within db.transaction() blocks. Mutations within transactions will not trigger cache invalidation.

upstashCache helper initialization with environment variables

The upstashCache() helper can be imported from 'drizzle-orm/cache/upstash' and used with the drizzle() function. By default, it uses Upstash Redis and can automatically pull url and token from environment variables (UPSTASH_URL and UPSTASH_TOKEN).

upstashCache configuration options

upstashCache accepts: url (Upstash URL, optional if in env vars), token (Upstash token, optional if in env vars), global (boolean to enable caching for all queries by default, optional), and config (object with cache behavior options like ex for expiration in seconds).

CacheConfig type for Upstash

The CacheConfig type includes: ex (expiration in seconds as positive integer, optional), hexOptions (string option for HEXPIRE command, accepts values 'NX', 'nx', 'XX', 'xx', 'GT', 'gt', 'LT', 'lt', optional).

autoInvalidate default behavior and eventual consistency

By default, autoInvalidate is enabled, so cache is invalidated immediately when mutations occur on cached tables. When autoInvalidate: false is set, cache invalidation is manual and the application accepts eventual consistency. This means old cached data may be served until its TTL expires, even after the underlying data has changed through mutations.

Cache not yet supported for relational queries

Cache is not yet supported for Drizzle relational queries like db.query.users.findMany(). This limitation is temporary and will be addressed in future versions.

Cache does not work inside transactions

The cache extension does not work inside transaction blocks. Queries executed within db.transaction(async (tx) => {...}) will not be cached.

Upstash cache with explicit configuration example

Complete Upstash setup example: const db = drizzle(process.env.DB_URL!, { cache: upstashCache({ url: '<UPSTASH_URL>', token: '<UPSTASH_TOKEN>', global: true, config: { ex: 60 } }) }); This enables global caching with 60-second TTL by default.

Cache not yet supported for views

Cache is not yet supported when querying views. This limitation is temporary and will be addressed in future versions.

Mutations trigger cache invalidation by default

Any insert, update, or delete operation automatically triggers the cache's onMutate handler, which attempts to invalidate cached queries that involved the affected tables. This ensures cache consistency unless autoInvalidate is explicitly disabled.

put() method receives table information for invalidation

When caching a query result, the put() method receives a tables array parameter containing all tables involved in the select query. This information enables cache invalidation tracking—when mutations occur on those tables, stored cache keys can be removed.

onMutate() receives tags and tables for invalidation

The onMutate(params) method receives an object with tags (string or array of custom cache tags) and tables (string, array of strings, or Table objects affected by mutations). Implementation should delete cache entries for these tags and table-based keys.

Enable global caching with global: true

When global: true is set in cache configuration, every select query will look in cache first by default, caching all queries automatically.

Upstash integration setup

Drizzle provides an upstashCache() helper that integrates with Upstash Redis. The helper automatically uses environment variables if available: UPSTASH_TOKEN and UPSTASH_URL. Example: const db = drizzle(process.env.DB_URL!, { cache: upstashCache({ token: process.env.UPSTASH_TOKEN, url: process.env.UPSTASH_URL }) });

Enable caching per-query with .$withCache()

When using explicit caching strategy (global: false), individual queries can opt into caching by calling .$withCache() at the end of the query chain.

.$withCache() options for individual queries

The .$withCache() method accepts an options object with three properties: config (object to override default cache behavior like TTL), tag (string for custom cache key instead of automatic hashing), and autoInvalidate (boolean to enable/disable automatic cache invalidation on mutations, default is true).

Cache invalidation via db.$cache.invalidate()

The drizzle instance provides db.$cache.invalidate() to manually invalidate cached queries. It accepts an object with either tables (string, array of strings, Table objects, or array of Table objects) or tags (string or array of strings) to invalidate by table name or custom tag.

Eventual consistency with autoInvalidate: false

When .$withCache({ autoInvalidate: false }) is used, cache invalidation is disabled for that query. This can reduce unnecessary invalidations for slowly-changing data (like product listings), but allows stale data until the TTL expires. By default, autoInvalidate is enabled for immediate consistency.

Custom cache implementation extends Cache class

Custom caches extend the Cache class and must implement four methods: strategy() returning 'explicit' or 'all', get(key: string) to retrieve cached data, put(key, response, tables, isTag, config) to store cached data, and onMutate(params) to handle cache invalidation on insert/update/delete statements.

Cache does not work with batch operations

The cache extension does not handle batch operations in d1 and libsql drivers. Queries within db.batch([...]) calls will not be cached.

Cache does not work with views

Using cache with database views is not currently supported. This is a temporary limitation.

Drizzle cache strategy default behavior

By default, Drizzle uses an explicit caching strategy (global: false), meaning nothing is cached unless explicitly requested via .$withCache(). This prevents surprises or hidden performance traps in applications.

Drizzle sends queries to database without automatic caching

Drizzle sends every query straight to your database by default. There are no hidden actions, no automatic caching or invalidation — you always see exactly what runs.

Upstash cache integration setup

Drizzle provides an upstashCache() helper that can be imported from 'drizzle-orm/cache/upstash'. By default, it uses Upstash Redis with automatic configuration if environment variables are set. It requires url and token parameters.

Upstash cache configuration options

Upstash cache configuration supports: ex (expiration in seconds as positive integer), hexOptions (hash field TTL options: 'NX', 'nx', 'XX', 'xx', 'GT', 'gt', 'LT', 'lt'), global (boolean to enable caching for all queries by default), and config object with cache behavior settings.

.$withCache() method for opt-in caching

When using global: false (default), call .$withCache() on a select query to enable caching for that specific query. .$withCache() accepts options including config (to rewrite config for the query), tag (custom cache key), and autoInvalidate (boolean to enable/disable auto-invalidation).

.$withCache(false) to disable cache on global mode

When using global: true, call .$withCache(false) to disable cache for a specific query.

Cache invalidation methods on db instance

Use db.$cache.invalidate() to manually invalidate cached queries. It accepts { tables: Table | string | (Table | string)[] } to invalidate all queries using specific tables, or { tags: string | string[] } to invalidate queries with custom tags.

Cache autoInvalidate default behavior

By default, autoInvalidate is enabled. When enabled, mutating operations (insert, update, delete) automatically trigger the cache's onMutate handler to invalidate cached queries involving affected tables.

Eventual consistency with autoInvalidate disabled

When autoInvalidate is set to false, cache is not invalidated on mutations. This means data may become stale until the TTL expires. This approach is suitable for data that changes infrequently and slight staleness is acceptable, such as product listings or blog posts.

Custom cache implementation interface

Custom cache extends Cache class and implements: strategy() returning 'explicit' or 'all', get(key: string) returning Promise<any[] | undefined>, put(key, response, tables, isTag, config) to store cached data, and onMutate(params: {tags, tables}) to handle invalidation on mutations.

Custom cache config options

Custom cache configuration supports: ex (expiration in seconds), px (expiration in milliseconds), exat (Unix time in seconds when key expires), pxat (Unix time in milliseconds when key expires), keepTtl (retain existing TTL when updating key), and hexOptions (hash-field TTL options).

Cache put() method parameters and purpose

The put() method accepts key (hashed query and parameters), response (array of values from database), tables (array of table names involved in query), isTag (boolean indicating if entry uses tag-based caching), and config (CacheConfig object). This allows tracking which tables are involved for later cache invalidation.

Cache onMutate() method receives affected tables and tags

The onMutate() method receives an object with tags (string or string[] for tag-based invalidation) and tables (Table object or string, or arrays of either, representing tables affected by insert/update/delete statements).

Cache does not work with raw queries

Cache extension does not handle raw queries executed via db.execute(sql`...`). Caching is not supported for raw SQL execution.

Cache does not work with transactions

Using cache inside transactions is not supported. Queries executed within db.transaction() will not be cached.

Cache does not work with Drizzle Relational Queries

Using cache with Drizzle Relational Queries such as db.query.users.findMany() is not currently supported. This is a temporary limitation.

Upstash cache example with explicit strategy

Example of opt-in caching with Upstash: await db.select().from(users).$withCache() reads from cache, while await db.select().from(users) does not. Mutations still trigger cache invalidation.

Upstash cache example with global strategy

Example of global caching: await db.select().from(users) reads from cache by default. To disable cache for specific query, use await db.select().from(users).$withCache(false).

Give your agent this brain