---
title: "Query Caching"
description: "Query caching in Drizzle provides an extensible caching infrastructure designed to intercept database execution, minimize redundant round-trips, and maintain synchronization between cached query re..."
last_updated: "2026-10-12T08:14:00.746407+00:00"
canonical_url: "https://www.doc0.dev/docs/e1b68fed-3c4e-4c95-b2ba-ebf050f78025/technical/core-architecture/query-caching"
---

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [drizzle-orm/src/cache/upstash/cache.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/cache/upstash/cache.ts)
- [drizzle-orm/src/cache/upstash/index.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/cache/upstash/index.ts)
- [drizzle-orm/src/singlestore-core/session.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/singlestore-core/session.ts)
- [drizzle-orm/src/singlestore/session.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/singlestore/session.ts)
- [drizzle-orm/src/mysql-core/session.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/mysql-core/session.ts)
- [drizzle-orm/src/planetscale-serverless/session.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/planetscale-serverless/session.ts)
- [drizzle-orm/src/sqlite-core/session.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/sqlite-core/session.ts)
- [drizzle-orm/src/sqlite-proxy/session.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/sqlite-proxy/session.ts)
- [drizzle-orm/src/tidb-serverless/session.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/tidb-serverless/session.ts)
- [drizzle-orm/src/gel-core/session.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/gel-core/session.ts)
- [drizzle-orm/src/neon-serverless/session.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/neon-serverless/session.ts)
- [drizzle-orm/src/mysql2/session.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/mysql2/session.ts)
- [drizzle-orm/src/cache/core/cache.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/cache/core/cache.ts)
- [drizzle-orm/src/libsql/session.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/libsql/session.ts)
- [drizzle-orm/src/node-postgres/session.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/node-postgres/session.ts)
- [drizzle-orm/src/vercel-postgres/session.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/vercel-postgres/session.ts)
- [drizzle-orm/src/bun-sql/session.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/bun-sql/session.ts)
- [drizzle-orm/src/pg-proxy/session.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/pg-proxy/session.ts)
- [drizzle-orm/src/xata-http/session.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/xata-http/session.ts)
- [drizzle-orm/src/pg-core/session.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/pg-core/session.ts)
- [drizzle-orm/src/gel/session.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/gel/session.ts)
- [drizzle-orm/src/pglite/session.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/pglite/session.ts)
- [drizzle-orm/src/mysql-proxy/session.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/mysql-proxy/session.ts)
- [drizzle-orm/src/op-sqlite/session.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/op-sqlite/session.ts)
- [drizzle-orm/src/neon-http/session.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/neon-http/session.ts)
- [drizzle-orm/src/singlestore-core/db.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/singlestore-core/db.ts)
- [drizzle-orm/src/cache/core/index.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/cache/core/index.ts)
- [drizzle-orm/src/aws-data-api/pg/session.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/aws-data-api/pg/session.ts)
- [drizzle-orm/src/cache/core/types.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/cache/core/types.ts)
- [drizzle-orm/src/durable-sqlite/session.ts](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/durable-sqlite/session.ts)
</details>

## Overview

Query caching in Drizzle provides an extensible caching infrastructure designed to intercept database execution, minimize redundant round-trips, and maintain synchronization between cached query results and underlying table mutations. By integrating caching abstractions directly into database sessions and prepared statements across supported SQL dialects, queries can be conditionally cached, retrieved via read-through patterns, and automatically invalidated when related tables undergo changes.

Sources: [drizzle-orm/src/cache/core/cache.ts:5-42](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/cache/core/cache.ts#L5-L42), [drizzle-orm/src/singlestore-core/session.ts:68-152](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/singlestore-core/session.ts#L68-L152), [drizzle-orm/src/mysql-core/session.ts:70-154](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/mysql-core/session.ts#L70-L154), [drizzle-orm/src/sqlite-core/session.ts:71-155](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/sqlite-core/session.ts#L71-L155), [drizzle-orm/src/pg-core/session.ts:64-147](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/pg-core/session.ts#L64-L147)

## Core Cache Abstractions and Contract

### Base Cache Class and Null Implementation

```typescript
export abstract class Cache {
	static readonly [entityKind]: string = 'Cache';

	abstract strategy(): 'explicit' | 'all';

	/**
	 * Invoked if we should check cache for cached response
	 * @param sql
	 * @param tables
	 */
	abstract get(
		key: string,
		tables: string[],
		isTag: boolean,
		isAutoInvalidate?: boolean,
	): Promise<any[] | undefined>;

	/**
	 * Invoked if new query should be inserted to cache
	 * @param sql
	 * @param tables
	 */
	abstract put(
		hashedQuery: string,
		response: any,
		tables: string[],
		isTag: boolean,
		config?: CacheConfig,
	): Promise<void>;

	/**
	 * Invoked if insert, update, delete was invoked
	 * @param tables
	 */
	abstract onMutate(
		params: MutationOption,
	): Promise<void>;
}

export class NoopCache extends Cache {
	override strategy() {
		return 'all' as const;
	}

	static override readonly [entityKind]: string = 'NoopCache';

	override async get(_key: string): Promise<any[] | undefined> {
		return undefined;
	}
	override async put(
		_hashedQuery: string,
		_response: any,
		_tables: string[],
		_config?: any,
	): Promise<void> {
		// noop
	}
	override async onMutate(_params: MutationOption): Promise<void> {
		// noop
	}
}
```
Sources: [drizzle-orm/src/cache/core/cache.ts:5-65](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/cache/core/cache.ts#L5-L65)

> [!NOTE]
> `NoopCache` inherits from the abstract `Cache` base class and resolves cache strategies as `'all'` while returning `undefined` for `get` operations, effectively bypassing caching when no active provider is configured.

### Mutation Options and Query Hashing

```typescript
export type MutationOption = { tags?: string | string[]; tables?: Table<any> | Table<any>[] | string | string[] };

export async function hashQuery(sql: string, params?: any[]) {
	const dataToHash = `${sql}-${JSON.stringify(params)}`;
	const encoder = new TextEncoder();
	const data = encoder.encode(dataToHash);
	const hashBuffer = await crypto.subtle.digest('SHA-256', data);
	const hashArray = [...new Uint8Array(hashBuffer)];
	const hashHex = hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');

	return hashHex;
}
```
Sources: [drizzle-orm/src/cache/core/cache.ts:67-78](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/cache/core/cache.ts#L67-L78)

> [!IMPORTANT]
> `hashQuery` serializes the SQL string and parameter array using `JSON.stringify`, encodes the combined payload via `TextEncoder`, and computes a SHA-256 digest using `crypto.subtle.digest`, converting the resulting buffer into a hexadecimal string representation.

### Configuration Interfaces

```typescript
export type CacheConfig = {
	/**
	 * expire time, in seconds (a positive integer)
	 */
	ex?: number;
	/**
	 * expire time, in milliseconds (a positive integer).
	 */
	px?: number;
	/**
	 * Unix time at which the key will expire, in seconds (a positive integer).
	 */
	exat?: number;
	/**
	 * Unix time at which the key will expire, in milliseconds (a positive integer)
	 */
	pxat?: number;
	/**
	 * Retain the time to live associated with the key.
	 */
	keepTtl?: boolean;
	/**
	 * Set an expiration (TTL or time to live) on one or more fields of a given hash key.
	 * Used for HEXPIRE command
	 */
	hexOptions?: 'NX' | 'nx' | 'XX' | 'xx' | 'GT' | 'gt' | 'LT' | 'lt';
};

export type WithCacheConfig = { enable: boolean; config?: CacheConfig; tag?: string; autoInvalidate?: boolean };
```
Sources: [drizzle-orm/src/cache/core/types.ts:1-29](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/cache/core/types.ts#L1-L29)

| Configuration Property | Type | Description |
| :--- | :--- | :--- |
| `ex` | `number` | Expire time in seconds (positive integer) |
| `px` | `number` | Expire time in milliseconds (positive integer) |
| `exat` | `number` | Unix time at which the key will expire, in seconds |
| `pxat` | `number` | Unix time at which the key will expire, in milliseconds |
| `keepTtl` | `boolean` | Retain the time to live associated with the key |
| `hexOptions` | `'NX' \| 'nx' \| 'XX' \| 'xx' \| 'GT' \| 'gt' \| 'LT' \| 'lt'` | Expiration options used for HEXPIRE commands |
| `enable` | `boolean` | Enables or disables query caching |
| `config` | `CacheConfig` | Underlying expiration and TTL configuration |
| `tag` | `string` | Custom cache tag for group invalidation |
| `autoInvalidate` | `boolean` | Automatically invalidate entries upon table mutation |

Sources: [drizzle-orm/src/cache/core/types.ts:1-29](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/cache/core/types.ts#L1-L29)

## Upstash Redis Storage Implementation

### UpstashCache Storage Architecture and Key Prefixes

The `UpstashCache` class extends the core `Cache` abstraction, utilizing the `@upstash/redis client package to implement distributed query caching with Lua scripting support. It relies on fixed naming prefixes and global key structures to manage cache entries, non-auto-invalidated queries, and relational table mappings.

| Constant Name | Value / Prefix | Description |
| :--- | :--- | :--- |
| `compositeTableSetPrefix` | `'__CTS__'` | Prefix for sets denoting composite table names for unique tables |
| `compositeTablePrefix` | `'__CT__'` | Prefix for Redis hashes mapping hash keys or tags to cache values |
| `tagsMapKey` | `'__tagsMap__'` | Redis key holding the mapping of tags to composite table names |
| `nonAutoInvalidateTablePrefix` | `'__nonAutoInvalidate__'` | Hash prefix storing queries whose auto-invalidation is disabled |

Sources: [drizzle-orm/src/cache/upstash/cache.ts:60-95](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/cache/upstash/cache.ts#L60-L95)

> [!NOTE]
> Queries configured with auto-invalidation disabled bypass composite table hashes entirely, preventing them from being swept away during table mutation triggers and instead residing inside the `__nonAutoInvalidate__` Redis hash.

Sources: [drizzle-orm/src/cache/upstash/cache.ts:87-94](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/cache/upstash/cache.ts#L87-L94)

### Lua Scripting for Retrieval and Mutation

```typescript
const getByTagScript = `
local tagsMapKey = KEYS[1] -- tags map key
local tag        = ARGV[1] -- tag

local compositeTableName = redis.call('HGET', tagsMapKey, tag)
if not compositeTableName then
  return nil
end

local value = redis.call('HGET', compositeTableName, tag)
return value
`;

const onMutateScript = `
local tagsMapKey = KEYS[1] -- tags map key
local tables     = {}      -- initialize tables array
local tags       = ARGV    -- tags array

for i = 2, #KEYS do
  tables[#tables + 1] = KEYS[i] -- add all keys except the first one to tables
end

if #tags > 0 then
  for _, tag in ipairs(tags) do
    if tag ~= nil and tag ~= '' then
      local compositeTableName = redis.call('HGET', tagsMapKey, tag)
      if compositeTableName then
        redis.call('HDEL', compositeTableName, tag)
      end
    end
  end
  redis.call('HDEL', tagsMapKey, unpack(tags))
end

local keysToDelete = {}

if #tables > 0 then
  local compositeTableNames = redis.call('SUNION', unpack(tables))
  for _, compositeTableName in ipairs(compositeTableNames) do
    keysToDelete[#keysToDelete + 1] = compositeTableName
  end
  for _, table in ipairs(tables) do
    keysToDelete[#keysToDelete + 1] = table
  end
  redis.call('DEL', unpack(keysToDelete))
end
`;
```
Sources: [drizzle-orm/src/cache/upstash/cache.ts:8-54](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/cache/upstash/cache.ts#L8-L54)

> [!IMPORTANT]
> `UpstashCache` registers two compiled Lua scripts during initialization: `getByTagScript` (marked readonly) which looks up tag mappings and fetches cached values in a single atomic round-trip, and `onMutateScript` which executes set unions (`SUNION`), table deletions (`DEL`), and hash field removals (`HDEL`) when database modifications occur.

Sources: [drizzle-orm/src/cache/upstash/cache.ts:8-54](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/cache/upstash/cache.ts#L8-L54), [drizzle-orm/src/cache/upstash/cache.ts:106-109](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/cache/upstash/cache.ts#L106-L109)

## Session Cache Lifecycle Coordination

### Execution Interception and Caching Mechanisms

Database sessions across SQLite, PostgreSQL, and MySQL proxy implementations coordinate caching through prepared query abstractions. When a query is executed via `SQLiteRemoteSession`, `PgRemoteSession`, or `MySqlRemoteSession`, parameters are filled, queries are logged via `Logger`, and execution flows through read-through wrapper methods like `queryWithCache`.

| Session Class | Driver Type | Cache Option Property | Default Cache Implementation |
| :--- | :--- | :--- | :--- |
| `SQLiteRemoteSession` | SQLite Proxy | `cache` | `NoopCache` |
| `PgRemoteSession` | PostgreSQL Proxy | `cache` | `NoopCache` |
| `MySqlRemoteSession` | MySQL Proxy | `cache` | `NoopCache` |

Sources: [drizzle-orm/src/sqlite-proxy/session.ts:22-41](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/sqlite-proxy/session.ts#L22-L41), [drizzle-orm/src/pg-proxy/session.ts:18-41](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/pg-proxy/session.ts#L18-L41), [drizzle-orm/src/mysql-proxy/session.ts:27-50](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/mysql-proxy/session.ts#L27-L50)

> [!NOTE]
> Sessions initialize their internal logger and cache instances during construction, falling back to `NoopLogger` and `NoopCache` when options are omitted from the session configuration object.

Sources: [drizzle-orm/src/sqlite-proxy/session.ts:38-41](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/sqlite-proxy/session.ts#L38-L41), [drizzle-orm/src/pg-proxy/session.ts:32-41](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/pg-proxy/session.ts#L32-L41), [drizzle-orm/src/mysql-proxy/session.ts:41-50](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/mysql-proxy/session.ts#L41-L50)

### Prepared Query Coordination

Prepared query classes wrap execution commands (`run`, `all`, `get`, `values`, `execute`) and interact directly with session-level caching hooks by passing query strings, parameters, and execution callbacks.

```typescript
async run(placeholderValues?: Record<string, unknown>): Promise<SqliteRemoteResult> {
	const params = fillPlaceholders(this.query.params, placeholderValues ?? {});
	this.logger.logQuery(this.query.sql, params);
	return await this.queryWithCache(this.query.sql, params, async () => {
		return await (this.client as AsyncRemoteCallback)(this.query.sql, params, 'run');
	});
}
```
Sources: [drizzle-orm/src/sqlite-proxy/session.ts:177-183](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/sqlite-proxy/session.ts#L177-L183)

> [!WARNING]
> In `PgRemoteSession`, query execution wrapped with OpenTelemetry spans (`drizzle.execute` and `drizzle.driver.execute`) records query text and parameter payloads as span attributes before delegating to `queryWithCache`.

Sources: [drizzle-orm/src/pg-proxy/session.ts:113-154](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/pg-proxy/session.ts#L113-L154)

## Cache Invalidation and Mutation Handling

### Mutation Options and Invalidation Triggers

The core cache abstract contract defines the `onMutate` lifecycle hook to handle database modification operations such as inserts, updates, and deletes [[Cache Invalidation and Mutation Handling](#)], accepting a `MutationOption` parameter [[Cache Invalidation and Mutation Handling](#)]. This parameter structure supports optional tags and tables specified as single items or arrays of strings, table objects, or table instances [[Cache Invalidation and Mutation Handling](#)].

```typescript
export type MutationOption = { tags?: string | string[]; tables?: Table<any> | Table<any>[] | string | string[] };
```
Sources: [drizzle-orm/src/cache/core/cache.ts:67-67](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/cache/core/cache.ts#L67-L67)

> [!NOTE]
> The `NoopCache` implementation provides an empty implementation for `onMutate`, safely ignoring table mutation events when caching is disabled or unconfigured [[Cache Invalidation and Mutation Handling](#)].

Sources: [drizzle-orm/src/cache/core/cache.ts:62-64](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/cache/core/cache.ts#L62-L64)

### Upstash Mutation Execution via Lua

When database modifications trigger cache invalidation in `UpstashCache`, execution delegates to a specialized Lua script (`onMutateScript`) deployed to Redis [[Cache Invalidation and Mutation Handling](#)]. This script evaluates keys and arguments atomically to prune obsolete cache entries across composite table hashes and tag mapping structures [[Cache Invalidation and Mutation Handling](#)].

Sources: [drizzle-orm/src/cache/upstash/cache.ts:21-54](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/cache/upstash/cache.ts#L21-L54)

> [!CAUTION]
> The `onMutateScript` executes a set union (`SUNION`) across specified table keys to gather all composite table names linked to modified tables, subsequently issuing batch `DEL` commands to purge stale query results from Redis in a single atomic operation [[Cache Invalidation and Mutation Handling](#)].

Sources: [drizzle-orm/src/cache/upstash/cache.ts:42-53](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/cache/upstash/cache.ts#L42-L53)

## Driver and Serverless Runtime Adapters

### Session Options and NoopCache Wiring

Serverless and lightweight driver sessions initialize their options by defaulting unconfigured cache properties to `NoopCache`. Across driver implementations including `TiDBServerlessSession`, `NeonSession`, `XataHttpSession`, `GelDbSession`, `PgliteSession`, `OPSQLiteSession`, and `AwsDataApiSession`, the session constructor extracts the optional cache from the session options object or instantiates a fresh `NoopCache` instance.

```typescript
	private options: TiDBServerlessSessionOptions = {},
) {
	super(dialect);
	this.client = tx ?? baseClient;
	this.logger = options.logger ?? new NoopLogger();
	this.cache = options.cache ?? new NoopCache();
}
```
Sources: [drizzle-orm/src/tidb-serverless/session.ts:124-130](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/tidb-serverless/session.ts#L124-L130)

```typescript
constructor(
	private client: XataHttpClient,
	dialect: PgDialect,
	private schema: RelationalSchemaConfig<TSchema> | undefined,
	private options: XataHttpSessionOptions = {},
) {
	super(dialect);
	this.logger = options.logger ?? new NoopLogger();
	this.cache = options.cache ?? new NoopCache();
}
```
Sources: [drizzle-orm/src/xata-http/session.ts:110-119](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/xata-http/session.ts#L110-L119)

```typescript
constructor(
	private client: GelClient,
	dialect: GelDialect,
	private schema: RelationalSchemaConfig<TSchema> | undefined,
	private options: GelSessionOptions = {},
) {
	super(dialect);
	this.logger = options.logger ?? new NoopLogger();
	this.cache = options.cache ?? new NoopCache();
}
```
Sources: [drizzle-orm/src/gel/session.ts:117-126](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/gel/session.ts#L117-L126)

```typescript

constructor(
	private client: PgliteClient | Transaction,
	dialect: PgDialect,
	private schema: RelationalSchemaConfig<TSchema> | undefined,
	private options: PgliteSessionOptions = {},
) {
	super(dialect);
	this.logger = options.logger ?? new NoopLogger();
	this.cache = options.cache ?? new NoopCache();
}
```
Sources: [drizzle-orm/src/pglite/session.ts:131-141](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/pglite/session.ts#L131-L141)

```typescript
constructor(
	private client: OPSQLiteConnection,
	dialect: SQLiteAsyncDialect,
	private schema: RelationalSchemaConfig<TSchema> | undefined,
	options: OPSQLiteSessionOptions = {},
) {
	super(dialect);
	this.logger = options.logger ?? new NoopLogger();
	this.cache = options.cache ?? new NoopCache();
}
```
Sources: [drizzle-orm/src/op-sqlite/session.ts:37-46](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/op-sqlite/session.ts#L37-L46)

```typescript
constructor(
	/** @internal */
	readonly client: AwsDataApiClient,
	dialect: PgDialect,
	private schema: RelationalSchemaConfig<TSchema> | undefined,
	private options: AwsDataApiSessionOptions,
	/** @internal */
	readonly transactionId: string | undefined,
) {
	super(dialect);
	this.rawQuery = {
		secretArn: options.secretArn,
		resourceArn: options.resourceArn,
		database: options.database,
	};
	this.cache = options.cache ?? new NoopCache();
}
```
Sources: [drizzle-orm/src/aws-data-api/pg/session.ts:175-191](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/aws-data-api/pg/session.ts#L175-L191)

```typescript
constructor(
	public client: TSQL,
	dialect: PgDialect,
	private schema: RelationalSchemaConfig<TSchema> | undefined,
	/** @internal */
	readonly options: BunSQLSessionOptions = {},
) {
	super(dialect);
	this.logger = options.logger ?? new NoopLogger();
	this.cache = options.cache ?? new NoopCache();
}
```
Sources: [drizzle-orm/src/bun-sql/session.ts:120-130](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/bun-sql/session.ts#L120-L130)

> [!NOTE]
> Synchronous storage environments such as `SQLiteDOSession` omit cache constructor arguments entirely within their prepared query initializers because synchronous runtime caching is unsupported.

Sources: [drizzle-orm/src/durable-sqlite/session.ts:100-111](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/durable-sqlite/session.ts#L100-L111)

### Prepared Query Cache Propagation

When sessions instantiate prepared queries, the session-level `cache` reference is passed directly into the query constructor. Prepared query classes such as `TiDBServerlessPreparedQuery`, `NeonPreparedQuery`, `LibSQLPreparedQuery`, `VercelPgPreparedQuery`, `XataHttpPreparedQuery`, `GelDbPreparedQuery`, `PglitePreparedQuery`, `OPSQLitePreparedQuery`, `NeonHttpPreparedQuery`, `AwsDataApiPreparedQuery`, and `BunSQLPreparedQuery` forward the cache instance, query metadata, and cache configuration objects up to base query classes.

| Driver Prepared Query | Client / Driver Type | Session Type | Cache Support |
| :--- | :--- | :--- | :--- |
| `TiDBServerlessPreparedQuery` | `Tx \| Connection` | `TiDBServerlessSession` | Yes |
| `NeonPreparedQuery` | `Pool \| PoolClient \| Client` | `NeonSession` | Yes |
| `LibSQLPreparedQuery` | `Client` | `LibSQLSession` | Yes |
| `VercelPgPreparedQuery` | `VercelPool \| VercelClient \| VercelPoolClient` | `VercelPgSession` | Yes |
| `XataHttpPreparedQuery` | `XataHttpClient` | `XataHttpSession` | Yes |
| `GelDbPreparedQuery` | `Client \| Transaction` | `GelDbSession` | Yes |
| `PglitePreparedQuery` | `PgliteClient \| Transaction` | `PgliteSession` | Yes |
| `OPSQLitePreparedQuery` | `OPSQLiteConnection` | `OPSQLiteSession` | Yes |
| `NeonHttpPreparedQuery` | `NeonHttpClient` | `NeonHttpSession` | Yes |
| `AwsDataApiPreparedQuery` | `AwsDataApiClient` | `AwsDataApiSession` | Yes |
| `BunSQLPreparedQuery` | `SQL` | `BunSQLSession` | Yes |
| `SQLiteDOPreparedQuery` | `DurableObjectStorage` | `SQLiteDOSession` | No (`undefined`) |

Sources: [drizzle-orm/src/tidb-serverless/session.ts:26-48](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/tidb-serverless/session.ts#L26-L48), [drizzle-orm/src/neon-serverless/session.ts:27-49](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/neon-serverless/session.ts#L27-L49), [drizzle-orm/src/libsql/session.ts:165-192](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/libsql/session.ts#L165-L192), [drizzle-orm/src/vercel-postgres/session.ts:26-48](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/vercel-postgres/session.ts#L26-L48), [drizzle-orm/src/xata-http/session.ts:27-45](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/xata-http/session.ts#L27-L45), [drizzle-orm/src/gel/session.ts:17-37](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/gel/session.ts#L17-L37), [drizzle-orm/src/pglite/session.ts:19-42](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/pglite/session.ts#L19-L42), [drizzle-orm/src/op-sqlite/session.ts:112-133](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/op-sqlite/session.ts#L112-L133), [drizzle-orm/src/neon-http/session.ts:29-48](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/neon-http/session.ts#L29-L48), [drizzle-orm/src/aws-data-api/pg/session.ts:30-55](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/aws-data-api/pg/session.ts#L30-L55), [drizzle-orm/src/bun-sql/session.ts:19-38](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/bun-sql/session.ts#L19-L38), [drizzle-orm/src/durable-sqlite/session.ts:90-111](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/durable-sqlite/session.ts#L90-L111)

> [!WARNING]
> When transaction boundaries are opened in serverless sessions—such as `TiDBServerlessSession.transaction`, `GelDbSession.transaction`, `PgliteSession.transaction`, and `AwsDataApiSession.transaction`—new session instances are created with native transaction handles while preserving reference to the parent session's configured `cache` instance.

Sources: [drizzle-orm/src/tidb-serverless/session.ts:173-191](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/tidb-serverless/session.ts#L173-L191), [drizzle-orm/src/gel/session.ts:154-162](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/gel/session.ts#L154-L162), [drizzle-orm/src/pglite/session.ts:170-187](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/pglite/session.ts#L170-L187), [drizzle-orm/src/aws-data-api/pg/session.ts:238-256](https://github.com/blade47/drizzle-orm/blob/48e5406027103a9fca6eb66417187c4a8b5c6aa3/drizzle-orm/src/aws-data-api/pg/session.ts#L238-L256)

## Related

- [Sessions and Transactions](https://www.doc0.dev/docs/e1b68fed-3c4e-4c95-b2ba-ebf050f78025/technical/core-architecture/sessions-and-transactions)
- [Query Builder Foundation](https://www.doc0.dev/docs/e1b68fed-3c4e-4c95-b2ba-ebf050f78025/technical/core-architecture/query-builder-foundation)


## Sitemap

See the full [sitemap](https://www.doc0.dev/docs/e1b68fed-3c4e-4c95-b2ba-ebf050f78025/llms.txt) for all pages in this wiki.
