From c21989fb1142284b429e807c737d28b8489c642d Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Fri, 5 Sep 2025 16:49:48 +0100 Subject: [PATCH 01/12] Splitting Storage API chapter into two --- .../api/legacy-kv-backed-storage.mdx | 88 ++++ .../api/sqlite-backed-storage.mdx | 210 +++++++++ .../docs/durable-objects/api/storage-api.mdx | 400 ------------------ .../durable-objects/api-async-kv-legacy.mdx | 110 +++++ .../durable-objects/api-storage-alarms.mdx | 30 ++ .../api-storage-introduction.mdx | 29 ++ .../api-storage-other-methods.mdx | 41 ++ .../partials/durable-objects/api-sync-kv.mdx | 110 +++++ 8 files changed, 618 insertions(+), 400 deletions(-) create mode 100644 src/content/docs/durable-objects/api/legacy-kv-backed-storage.mdx create mode 100644 src/content/docs/durable-objects/api/sqlite-backed-storage.mdx delete mode 100644 src/content/docs/durable-objects/api/storage-api.mdx create mode 100644 src/content/partials/durable-objects/api-async-kv-legacy.mdx create mode 100644 src/content/partials/durable-objects/api-storage-alarms.mdx create mode 100644 src/content/partials/durable-objects/api-storage-introduction.mdx create mode 100644 src/content/partials/durable-objects/api-storage-other-methods.mdx create mode 100644 src/content/partials/durable-objects/api-sync-kv.mdx diff --git a/src/content/docs/durable-objects/api/legacy-kv-backed-storage.mdx b/src/content/docs/durable-objects/api/legacy-kv-backed-storage.mdx new file mode 100644 index 000000000000000..ba5d947c1d0990e --- /dev/null +++ b/src/content/docs/durable-objects/api/legacy-kv-backed-storage.mdx @@ -0,0 +1,88 @@ +--- +title: KV-backed Durable Object Storage (Legacy) +pcx_content_type: concept +sidebar: + order: 7 +--- + +import { Render, Type, MetaInfo, GlossaryTooltip, TypeScriptExample, Details } from "~/components"; + +:::note +This page documents storage API for legacy KV-backed Durable Objects. + +For the newer SQLite-backed Durable Object storage API, refer to [SQLite-backed Durable Object Storage](/durable-objects/api/sqlite-backed-storage). +::: + + + + + +## Access storage + +Durable Objects gain access to Storage API via the `DurableObjectStorage` interface and accessed by the `DurableObjectState::storage` property. This is frequently accessed via `this.ctx.storage` with the `ctx` parameter passed to the Durable Object constructor. + +The following code snippet shows you how to store and retrieve data using the Durable Object Storage API. + + +```ts +export class Counter extends DurableObject { + constructor(ctx: DurableObjectState, env: Env) { + super(ctx, env); + } + + async increment(): Promise { + let value: number = (await this.ctx.storage.get('value')) || 0; + value += 1; + await this.ctx.storage.put('value', value); + return value; + } + +} + +``` + + +JavaScript is a single-threaded and event-driven programming language. This means that JavaScript runtimes, by default, allow requests to interleave with each other which can lead to concurrency bugs. The Durable Objects runtime uses a combination of input gates and output gates to avoid this type of concurrency bug when performing storage operations. Learn more in our [blog post](https://blog.cloudflare.com/durable-objects-easy-fast-correct-choose-three/). + +## Asynchronous KV API + +KV-backed Durable Objects use KV API methods which are asynchronous. + + + +## Alarms + +### `getAlarm` + +- getAlarm(options ): + - Retrieves the current alarm time (if set) as integer milliseconds since epoch. The alarm is considered to be set if it has not started, or if it has failed and any retry has not begun. If no alarm is set, `getAlarm()` returns `null`. + +#### Supported options + +- Same options as [`get()`](/durable-objects/api/storage-api/#get), but without `noCache`. + +### `setAlarm` + +- setAlarm(scheduledTime , options ): + - Sets the current alarm time, accepting either a JavaScript `Date`, or integer milliseconds since epoch. + + If `setAlarm()` is called with a time equal to or before `Date.now()`, the alarm will be scheduled for asynchronous execution in the immediate future. If the alarm handler is currently executing in this case, it will not be canceled. Alarms can be set to millisecond granularity and will usually execute within a few milliseconds after the set time, but can be delayed by up to a minute due to maintenance or failures while failover takes place. + +### `deleteAlarm` + +- deleteAlarm(options ): + - Deletes the alarm if one exists. Does not cancel the alarm handler if it is currently executing. + +#### Supported options + +- `setAlarm()` and `deleteAlarm()` support the same options as [`put()`](/durable-objects/api/storage-api/#put), but without `noCache`. + +## Other + + + +## Related resources + +- [Durable Objects: Easy, Fast, Correct Choose Three](https://blog.cloudflare.com/durable-objects-easy-fast-correct-choose-three/) +- [Zero-latency SQLite storage in every Durable Object blog](https://blog.cloudflare.com/sqlite-in-durable-objects/) +- [WebSockets API](/durable-objects/best-practices/websockets/) diff --git a/src/content/docs/durable-objects/api/sqlite-backed-storage.mdx b/src/content/docs/durable-objects/api/sqlite-backed-storage.mdx new file mode 100644 index 000000000000000..d3108e617af215a --- /dev/null +++ b/src/content/docs/durable-objects/api/sqlite-backed-storage.mdx @@ -0,0 +1,210 @@ +--- +title: SQLite-backed Durable Object Storage +pcx_content_type: concept +sidebar: + order: 6 +--- + +import { Render, Type, MetaInfo, GlossaryTooltip, TypeScriptExample, Details } from "~/components"; + +:::note +This page documents storage API for the newer SQLite-backed Durable Objects. + +For the legacy KV-backed Durable Object storage API, see [KV-backed Durable Object Storage (Legacy)](/durable-objects/api/legacy-kv-backed-storage/). +::: + + + + + + + +## Access storage + +Durable Objects gain access to Storage API via the `DurableObjectStorage` interface and accessed by the `DurableObjectState::storage` property. This is frequently accessed via `this.ctx.storage` with the `ctx` parameter passed to the Durable Object constructor. + +The following code snippet shows you how to store and retrieve data using the Durable Object Storage API. + + +```ts +export class Counter extends DurableObject { + constructor(ctx: DurableObjectState, env: Env) { + super(ctx, env); + } + + async increment(): Promise { + let value: number = (await this.ctx.storage.get('value')) || 0; + value += 1; + await this.ctx.storage.put('value', value); + return value; + } + +} + +``` + + +JavaScript is a single-threaded and event-driven programming language. This means that JavaScript runtimes, by default, allow requests to interleave with each other which can lead to concurrency bugs. The Durable Objects runtime uses a combination of input gates and output gates to avoid this type of concurrency bug when performing storage operations. Learn more in our [blog post](https://blog.cloudflare.com/durable-objects-easy-fast-correct-choose-three/). + +## SQL API + +The `SqlStorage` interface encapsulates methods that modify the SQLite database embedded within a Durable Object. The `SqlStorage` interface is accessible via the [`sql` property](/durable-objects/api/storage-api/#sql) of `DurableObjectStorage` class. + +For example, using `sql.exec()`, a user can create a table, then insert rows into the table. + +```ts +import { DurableObject } from "cloudflare:workers"; + +export class MyDurableObject extends DurableObject { + sql: SqlStorage; + constructor(ctx: DurableObjectState, env: Env) { + super(ctx, env); + this.sql = ctx.storage.sql; + + this.sql.exec(` + CREATE TABLE IF NOT EXISTS artist( + artistid INTEGER PRIMARY KEY, + artistname TEXT + ); + INSERT INTO artist (artistid, artistname) VALUES + (123, 'Alice'), + (456, 'Bob'), + (789, 'Charlie'); + `); + } +} +``` + +- SQL API methods accessed with `ctx.storage.sql` are only allowed on [Durable Object classes with SQLite storage backend](/durable-objects/best-practices/access-durable-objects-storage/#create-sqlite-backed-durable-object-class) and will return an error if called on Durable Object classes with a key-value storage backend. +- When writing data, every index counts as an additional row. However, indexes may be beneficial for read-heavy use cases. Refer to [Index for SQLite Durable Objects](/durable-objects/best-practices/access-durable-objects-storage/#index-for-sqlite-durable-objects). +- Writing data to [SQLite virtual tables](https://www.sqlite.org/vtab.html) also counts towards rows written. + + + +### `exec` + +exec(query: , ...bindings: ): + +#### Parameters + +- `query`: + - The SQL query string to be executed. `query` can contain `?` placeholders for parameter bindings. Multiple SQL statements, separated with a semicolon, can be executed in the `query`. With multiple SQL statements, any parameter bindings are applied to the last SQL statement in the `query`, and the returned cursor is only for the last SQL statement. +- `...bindings`: + - Optional variable number of arguments that correspond to the `?` placeholders in `query`. + +#### Returns + +A cursor (`SqlStorageCursor`) to iterate over query row results as objects. `SqlStorageCursor` is a JavaScript [Iterable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterable_protocol), which supports iteration using `for (let row of cursor)`. `SqlStorageCursor` is also a JavaScript [Iterator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterator_protocol), which supports iteration using `cursor.next()`. + +`SqlStorageCursor` supports the following methods: + +- `next()` + - Returns an object representing the next value of the cursor. The returned object has `done` and `value` properties adhering to the JavaScript [Iterator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterator_protocol). `done` is set to `false` when a next value is present, and `value` is set to the next row object in the query result. `done` is set to `true` when the entire cursor is consumed, and no `value` is set. +- `toArray()` + - Iterates through remaining cursor value(s) and returns an array of returned row objects. +- `one()` + - Returns a row object if query result has exactly one row. If query result has zero rows or more than one row, `one()` throws an exception. +- `raw()`: + - Returns an Iterator over the same query results, with each row as an array of column values (with no column names) rather than an object. + - Returned Iterator supports `next()` and `toArray()` methods above. + - Returned cursor and `raw()` iterator iterate over the same query results and can be combined. For example: + +```ts +let cursor = this.sql.exec("SELECT * FROM artist ORDER BY artistname ASC;"); +let rawResult = cursor.raw().next(); + +if (!rawResult.done) { + console.log(rawResult.value); // prints [ 123, 'Alice' ] +} else { + // query returned zero results +} + +console.log(cursor.toArray()); // prints [{ artistid: 456, artistname: 'Bob' },{ artistid: 789, artistname: 'Charlie' }] +``` + +`SqlStorageCursor` has the following properties: + +- `columnNames`: + - The column names of the query in the order they appear in each row array returned by the `raw` iterator. +- `rowsRead`: + - The number of rows read so far as part of this SQL `query`. This may increase as you iterate the cursor. The final value is used for [SQL billing](/durable-objects/platform/pricing/#sqlite-storage-backend). +- `rowsWritten`: + - The number of rows written so far as part of this SQL `query`. This may increase as you iterate the cursor. The final value is used for [SQL billing](/durable-objects/platform/pricing/#sqlite-storage-backend). +- Any numeric value in a column is affected by JavaScript's 52-bit precision for numbers. If you store a very large number (in `int64`), then retrieve the same value, the returned value may be less precise than your original number. + +:::note[SQL transactions] +Note that `sql.exec()` cannot execute transaction-related statements like `BEGIN TRANSACTION` or `SAVEPOINT`. Instead, use the [`ctx.storage.transaction()`](/durable-objects/api/storage-api/#transaction) or [`ctx.storage.transactionSync()`](/durable-objects/api/storage-api/#transactionsync) APIs to start a transaction, and then execute SQL queries in your callback. +::: + +#### Examples + + + +### `databaseSize` + +`databaseSize`: + +#### Returns + +The current SQLite database size in bytes. + +```ts +let size = ctx.storage.sql.databaseSize; +``` + +## PITR (Point In Time Recovery) API + +For [SQLite-backed Durable Objects](/durable-objects/best-practices/access-durable-objects-storage/#create-sqlite-backed-durable-object-class), the following point-in-time-recovery (PITR) API methods are available to restore a Durable Object's embedded SQLite database to any point in time in the past 30 days. These methods apply to the entire SQLite database contents, including both the object's stored SQL data and stored key-value data using the key-value `put()` API. The PITR API is not supported in local development because a durable log of data changes is not stored locally. + +The PITR API represents points in time using 'bookmarks'. A bookmark is a mostly alphanumeric string like `0000007b-0000b26e-00001538-0c3e87bb37b3db5cc52eedb93cd3b96b`. Bookmarks are designed to be lexically comparable: a bookmark representing an earlier point in time compares less than one representing a later point, using regular string comparison. + +### `getCurrentBookmark` + +ctx.storage.getCurrentBookmark(): + +- Returns a bookmark representing the current point in time in the object's history. + +### `getBookmarkForTime` + +ctx.storage.getBookmarkForTime(timestamp: ): + +- Returns a bookmark representing approximately the given point in time, which must be within the last 30 days. If the timestamp is represented as a number, it is converted to a date as if using `new Date(timestamp)`. + +### `onNextSessionRestoreBookmark` + +ctx.storage.onNextSessionRestoreBookmark(bookmark: ): + +- Configures the Durable Object so that the next time it restarts, it should restore its storage to exactly match what the storage contained at the given bookmark. After calling this, the application should typically invoke `ctx.abort()` to restart the Durable Object, thus completing the point-in-time recovery. + +This method returns a special bookmark representing the point in time immediately before the recovery takes place (even though that point in time is still technically in the future). Thus, after the recovery completes, it can be undone by performing a second recovery to this bookmark. + +```ts +let now = new Date(); +// restore to 2 days ago +let bookmark = ctx.storage.getBookmarkForTime(now - 2); +ctx.storage.onNextSessionRestoreBookmark(bookmark); +``` + +## Synchronous KV API + + + +## Alarms + + + +## Other + + + +## Storage properties + +### `sql` + +`sql` is a readonly property of type `DurableObjectStorage` encapsulating the [SQL API](/durable-objects/api/sqlite-backed-storage/#sql-api). + +## Related resources + +- [Durable Objects: Easy, Fast, Correct Choose Three](https://blog.cloudflare.com/durable-objects-easy-fast-correct-choose-three/) +- [Zero-latency SQLite storage in every Durable Object blog](https://blog.cloudflare.com/sqlite-in-durable-objects/) +- [WebSockets API](/durable-objects/best-practices/websockets/) diff --git a/src/content/docs/durable-objects/api/storage-api.mdx b/src/content/docs/durable-objects/api/storage-api.mdx deleted file mode 100644 index 737156b069864ee..000000000000000 --- a/src/content/docs/durable-objects/api/storage-api.mdx +++ /dev/null @@ -1,400 +0,0 @@ ---- -title: Durable Object Storage -pcx_content_type: concept -sidebar: - order: 6 ---- - -import { - Render, - Type, - MetaInfo, - GlossaryTooltip, - TypeScriptExample, - Details, -} from "~/components"; - -The Durable Object Storage API allows Durable Objects to access transactional and strongly consistent storage. A Durable Object's attached storage is private to its unique instance and cannot be accessed by other objects. - -The Durable Object Storage API comes with several methods, including SQL, point-in-time recovery (PITR), key-value (KV), and alarm APIs. Available API methods depend on the storage backend for a Durable Objects class, either [SQLite](/durable-objects/best-practices/access-durable-objects-storage/#create-sqlite-backed-durable-object-class) or [KV](/durable-objects/reference/durable-objects-migrations/#create-durable-object-class-with-key-value-storage). - -| Methods 1 | SQLite-backed Durable Object class | KV-backed Durable Object class | -| -------------------- | ---------------------------------- | ------------------------------ | -| SQL API | ✅ | ❌ | -| PITR API | ✅ | ❌ | -| KV API | ✅ 2, 3 | ✅ | -| Alarms API | ✅ | ✅ | - -
- -1 Each method is implicitly wrapped inside a transaction, such that -its results are atomic and isolated from all other storage operations, even when -accessing multiple key-value pairs. - -2 KV API methods like `get()`, `put()`, `delete()`, or `list()` store -data in a hidden SQLite table. - -3 KV methods which were previously asynchronous with KV storage (for -example, [`get`](/durable-objects/api/storage-api/#get), -[`put`](/durable-objects/api/storage-api/#put), -[`delete`](/durable-objects/api/storage-api/#delete), -[`deleteAll`](/durable-objects/api/storage-api/#deleteall), -[`list`](/durable-objects/api/storage-api/#list)) are synchronous, even though -they return promises. These methods will have completed their operations before -they return the promise. - -
- - - - - -## Access storage - -Durable Objects gain access to Storage API via the `DurableObjectStorage` interface and accessed by the `DurableObjectState::storage` property. This is frequently accessed via `this.ctx.storage` with the `ctx` parameter passed to the Durable Object constructor. - -The following code snippet shows you how to store and retrieve data using the Durable Object Storage API. - - -```ts -export class Counter extends DurableObject { - constructor(ctx: DurableObjectState, env: Env) { - super(ctx, env); - } - - async increment(): Promise { - let value: number = (await this.ctx.storage.get('value')) || 0; - value += 1; - await this.ctx.storage.put('value', value); - return value; - } - -} - -``` - - -JavaScript is a single-threaded and event-driven programming language. This means that JavaScript runtimes, by default, allow requests to interleave with each other which can lead to concurrency bugs. The Durable Objects runtime uses a combination of input gates and output gates to avoid this type of concurrency bug when performing storage operations. Learn more in our [blog post](https://blog.cloudflare.com/durable-objects-easy-fast-correct-choose-three/). - -## SQL API - -The `SqlStorage` interface encapsulates methods that modify the SQLite database embedded within a Durable Object. The `SqlStorage` interface is accessible via the [`sql` property](/durable-objects/api/storage-api/#sql) of `DurableObjectStorage` class. - -For example, using `sql.exec()`, a user can create a table, then insert rows into the table. - -```ts -import { DurableObject } from "cloudflare:workers"; - -export class MyDurableObject extends DurableObject { - sql: SqlStorage; - constructor(ctx: DurableObjectState, env: Env) { - super(ctx, env); - this.sql = ctx.storage.sql; - - this.sql.exec(` - CREATE TABLE IF NOT EXISTS artist( - artistid INTEGER PRIMARY KEY, - artistname TEXT - ); - INSERT INTO artist (artistid, artistname) VALUES - (123, 'Alice'), - (456, 'Bob'), - (789, 'Charlie'); - `); - } -} -``` - -- SQL API methods accessed with `ctx.storage.sql` are only allowed on [Durable Object classes with SQLite storage backend](/durable-objects/best-practices/access-durable-objects-storage/#create-sqlite-backed-durable-object-class) and will return an error if called on Durable Object classes with a key-value storage backend. -- When writing data, every index counts as an additional row. However, indexes may be beneficial for read-heavy use cases. Refer to [Index for SQLite Durable Objects](/durable-objects/best-practices/access-durable-objects-storage/#index-for-sqlite-durable-objects). -- Writing data to [SQLite virtual tables](https://www.sqlite.org/vtab.html) also counts towards rows written. - - - -### `exec` - -exec(query: , ...bindings: ): - -#### Parameters - -- `query`: - - The SQL query string to be executed. `query` can contain `?` placeholders for parameter bindings. Multiple SQL statements, separated with a semicolon, can be executed in the `query`. With multiple SQL statements, any parameter bindings are applied to the last SQL statement in the `query`, and the returned cursor is only for the last SQL statement. -- `...bindings`: - - Optional variable number of arguments that correspond to the `?` placeholders in `query`. - -#### Returns - -A cursor (`SqlStorageCursor`) to iterate over query row results as objects. `SqlStorageCursor` is a JavaScript [Iterable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterable_protocol), which supports iteration using `for (let row of cursor)`. `SqlStorageCursor` is also a JavaScript [Iterator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterator_protocol), which supports iteration using `cursor.next()`. - -`SqlStorageCursor` supports the following methods: - -- `next()` - - Returns an object representing the next value of the cursor. The returned object has `done` and `value` properties adhering to the JavaScript [Iterator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterator_protocol). `done` is set to `false` when a next value is present, and `value` is set to the next row object in the query result. `done` is set to `true` when the entire cursor is consumed, and no `value` is set. -- `toArray()` - - Iterates through remaining cursor value(s) and returns an array of returned row objects. -- `one()` - - Returns a row object if query result has exactly one row. If query result has zero rows or more than one row, `one()` throws an exception. -- `raw()`: - - Returns an Iterator over the same query results, with each row as an array of column values (with no column names) rather than an object. - - Returned Iterator supports `next()` and `toArray()` methods above. - - Returned cursor and `raw()` iterator iterate over the same query results and can be combined. For example: - -```ts -let cursor = this.sql.exec("SELECT * FROM artist ORDER BY artistname ASC;"); -let rawResult = cursor.raw().next(); - -if (!rawResult.done) { - console.log(rawResult.value); // prints [ 123, 'Alice' ] -} else { - // query returned zero results -} - -console.log(cursor.toArray()); // prints [{ artistid: 456, artistname: 'Bob' },{ artistid: 789, artistname: 'Charlie' }] -``` - -`SqlStorageCursor` has the following properties: - -- `columnNames`: - - The column names of the query in the order they appear in each row array returned by the `raw` iterator. -- `rowsRead`: - - The number of rows read so far as part of this SQL `query`. This may increase as you iterate the cursor. The final value is used for [SQL billing](/durable-objects/platform/pricing/#sqlite-storage-backend). -- `rowsWritten`: - - The number of rows written so far as part of this SQL `query`. This may increase as you iterate the cursor. The final value is used for [SQL billing](/durable-objects/platform/pricing/#sqlite-storage-backend). -- Any numeric value in a column is affected by JavaScript's 52-bit precision for numbers. If you store a very large number (in `int64`), then retrieve the same value, the returned value may be less precise than your original number. - -:::note[SQL transactions] -Note that `sql.exec()` cannot execute transaction-related statements like `BEGIN TRANSACTION` or `SAVEPOINT`. Instead, use the [`ctx.storage.transaction()`](/durable-objects/api/storage-api/#transaction) or [`ctx.storage.transactionSync()`](/durable-objects/api/storage-api/#transactionsync) APIs to start a transaction, and then execute SQL queries in your callback. -::: - -#### Examples - - - -### `databaseSize` - -`databaseSize`: - -#### Returns - -The current SQLite database size in bytes. - -```ts -let size = ctx.storage.sql.databaseSize; -``` - -## PITR (Point In Time Recovery) API - -For [SQLite-backed Durable Objects](/durable-objects/best-practices/access-durable-objects-storage/#create-sqlite-backed-durable-object-class), the following point-in-time-recovery (PITR) API methods are available to restore a Durable Object's embedded SQLite database to any point in time in the past 30 days. These methods apply to the entire SQLite database contents, including both the object's stored SQL data and stored key-value data using the key-value `put()` API. The PITR API is not supported in local development because a durable log of data changes is not stored locally. - -The PITR API represents points in time using 'bookmarks'. A bookmark is a mostly alphanumeric string like `0000007b-0000b26e-00001538-0c3e87bb37b3db5cc52eedb93cd3b96b`. Bookmarks are designed to be lexically comparable: a bookmark representing an earlier point in time compares less than one representing a later point, using regular string comparison. - -### `getCurrentBookmark` - -ctx.storage.getCurrentBookmark(): - -- Returns a bookmark representing the current point in time in the object's history. - -### `getBookmarkForTime` - -ctx.storage.getBookmarkForTime(timestamp: ): - -- Returns a bookmark representing approximately the given point in time, which must be within the last 30 days. If the timestamp is represented as a number, it is converted to a date as if using `new Date(timestamp)`. - -### `onNextSessionRestoreBookmark` - -ctx.storage.onNextSessionRestoreBookmark(bookmark: ): - -- Configures the Durable Object so that the next time it restarts, it should restore its storage to exactly match what the storage contained at the given bookmark. After calling this, the application should typically invoke `ctx.abort()` to restart the Durable Object, thus completing the point-in-time recovery. - -This method returns a special bookmark representing the point in time immediately before the recovery takes place (even though that point in time is still technically in the future). Thus, after the recovery completes, it can be undone by performing a second recovery to this bookmark. - -```ts -let now = new Date(); -// restore to 2 days ago -let bookmark = ctx.storage.getBookmarkForTime(now - 2); -ctx.storage.onNextSessionRestoreBookmark(bookmark); -``` - -## KV API - -### `get` - -- ctx.storage.get(key , options {" "}): - - Retrieves the value associated with the given key. The type of the returned value will be whatever was previously written for the key, or undefined if the key does not exist. - -- ctx.storage.get(keys , options ): - - Retrieves the values associated with each of the provided keys. The type of each returned value in the [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) will be whatever was previously written for the corresponding key. Results in the `Map` will be sorted in increasing order of their UTF-8 encodings, with any requested keys that do not exist being omitted. Supports up to 128 keys at a time. - -#### Supported options - -- `allowConcurrency`: - - By default, the system will pause delivery of I/O events to the Object while a storage operation is in progress, in order to avoid unexpected race conditions. Pass `allowConcurrency: true` to opt out of this behavior and allow concurrent events to be delivered. - -- `noCache`: - - If true, then the key/value will not be inserted into the in-memory cache. If the key is already in the cache, the cached value will be returned, but its last-used time will not be updated. Use this when you expect this key will not be used again in the near future. This flag is only a hint. This flag will never change the semantics of your code, but it may affect performance. - -### `put` - -- put(key , value , options ): - - Stores the value and associates it with the given key. The value can be any type supported by the [structured clone algorithm](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm), which is true of most types. - - The size of keys and values have different limits depending on the Durable Object storage backend you are using. Refer to either: - - [SQLite-backed Durable Object limits](/durable-objects/platform/limits/#sqlite-backed-durable-objects-general-limits) - - [KV-backed Durable Object limits](/durable-objects/platform/limits/#key-value-backed-durable-objects-general-limits).

- -- put(entries , options ): - - Takes an Object and stores each of its keys and values to storage. - - Each value can be any type supported by the [structured clone algorithm](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm), which is true of most types. - - Supports up to 128 key-value pairs at a time. The size of keys and values have different limits depending on the flavor of Durable Object you are using. Refer to either: - - [SQLite-backed Durable Object limits](/durable-objects/platform/limits/#sqlite-backed-durable-objects-general-limits) - - [KV-backed Durable Object limits](/durable-objects/platform/limits/#key-value-backed-durable-objects-general-limits) - -### `delete` - -- delete(key , options ): - - Deletes the key and associated value. Returns `true` if the key existed or `false` if it did not. - -- delete(keys , options ): - - Deletes the provided keys and their associated values. Supports up to 128 keys at a time. Returns a count of the number of key-value pairs deleted. - -#### Supported options - -- `put()`, `delete()` and `deleteAll()` support the following options: - -- `allowUnconfirmed` - - By default, the system will pause outgoing network messages from the Durable Object until all previous writes have been confirmed flushed to disk. If the write fails, the system will reset the Object, discard all outgoing messages, and respond to any clients with errors instead. - - - This way, Durable Objects can continue executing in parallel with a write operation, without having to worry about prematurely confirming writes, because it is impossible for any external party to observe the Object's actions unless the write actually succeeds. - - - After any write, subsequent network messages may be slightly delayed. Some applications may consider it acceptable to communicate on the basis of unconfirmed writes. Some programs may prefer to allow network traffic immediately. In this case, set `allowUnconfirmed` to `true` to opt out of the default behavior. - - - If you want to allow some outgoing network messages to proceed immediately but not others, you can use the allowUnconfirmed option to avoid blocking the messages that you want to proceed and then separately call the [`sync()`](/durable-objects/api/storage-api/#sync) method, which returns a promise that only resolves once all previous writes have successfully been persisted to disk. - -- `noCache` - - If true, then the key/value will be discarded from memory as soon as it has completed writing to disk. - - - Use `noCache` if the key will not be used again in the near future. `noCache` will never change the semantics of your code, but it may affect performance. - - - If you use `get()` to retrieve the key before the write has completed, the copy from the write buffer will be returned, thus ensuring consistency with the latest call to `put()`. - -:::note[Automatic write coalescing] - -If you invoke `put()` (or `delete()`) multiple times without performing any `await` in the meantime, the operations will automatically be combined and submitted atomically. In case of a machine failure, either all of the writes will have been stored to disk or none of the writes will have been stored to disk. -::: - -:::note[Write buffer behavior] - -The `put()` method returns a `Promise`, but most applications can discard this promise without using `await`. The `Promise` usually completes immediately, because `put()` writes to an in-memory write buffer that is flushed to disk asynchronously. However, if an application performs a large number of `put()` without waiting for any I/O, the write buffer could theoretically grow large enough to cause the isolate to exceed its 128 MB memory limit. To avoid this scenario, such applications should use `await` on the `Promise` returned by `put()`. The system will then apply backpressure onto the application, slowing it down so that the write buffer has time to flush. Using `await` will disable automatic write coalescing. -::: - -### `list` - -- list(options ): - - Returns all keys and values associated with the current Durable Object in ascending sorted order based on the keys' UTF-8 encodings. - - The type of each returned value in the [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) will be whatever was previously written for the corresponding key. - - - Be aware of how much data may be stored in your Durable Object before calling this version of `list` without options because all the data will be loaded into the Durable Object's memory, potentially hitting its [limit](/durable-objects/platform/limits/). If that is a concern, pass options to `list` as documented below. - -#### Supported options - -- `start` - - Key at which the list results should start, inclusive. - -- `startAfter` - - Key after which the list results should start, exclusive. Cannot be used simultaneously with `start`. - -- `end` - - Key at which the list results should end, exclusive. - -- `prefix` - - Restricts results to only include key-value pairs whose keys begin with the prefix. - -- `reverse` - - If true, return results in descending order instead of the default ascending order. - - Enabling `reverse` does not change the meaning of `start`, `startKey`, or `endKey`. `start` still defines the smallest key in lexicographic order that can be returned (inclusive), effectively serving as the endpoint for a reverse-order list. `end` still defines the largest key in lexicographic order that the list should consider (exclusive), effectively serving as the starting point for a reverse-order list. - -- `limit` - - Maximum number of key-value pairs to return. - -- `allowConcurrency` - - Same as the option to `get()`, above. - -- `noCache` - - Same as the option to `get()`, above. - -## Alarms - -### `getAlarm` - -- getAlarm(options ): - - Retrieves the current alarm time (if set) as integer milliseconds since epoch. The alarm is considered to be set if it has not started, or if it has failed and any retry has not begun. If no alarm is set, `getAlarm()` returns `null`. - -#### Supported options - -- Same options as [`get()`](/durable-objects/api/storage-api/#get), but without `noCache`. - -### `setAlarm` - -- setAlarm(scheduledTime , options ): - - Sets the current alarm time, accepting either a JavaScript `Date`, or integer milliseconds since epoch. - - If `setAlarm()` is called with a time equal to or before `Date.now()`, the alarm will be scheduled for asynchronous execution in the immediate future. If the alarm handler is currently executing in this case, it will not be canceled. Alarms can be set to millisecond granularity and will usually execute within a few milliseconds after the set time, but can be delayed by up to a minute due to maintenance or failures while failover takes place. - -### `deleteAlarm` - -- deleteAlarm(options ): - - Deletes the alarm if one exists. Does not cancel the alarm handler if it is currently executing. - -#### Supported options - -- `setAlarm()` and `deleteAlarm()` support the same options as [`put()`](/durable-objects/api/storage-api/#put), but without `noCache`. - -## Other - -### `deleteAll` - -- deleteAll(options ): - - Deletes all stored data, effectively deallocating all storage used by the Durable Object. For Durable Objects with a key-value storage backend, `deleteAll()` removes all keys and associated values for an individual Durable Object. For Durable Objects with a [SQLite storage backend](/durable-objects/best-practices/access-durable-objects-storage/#create-sqlite-backed-durable-object-class), `deleteAll()` removes the entire contents of a Durable Object's private SQLite database, including both SQL data and key-value data. - - For Durable Objects with a key-value storage backend, an in-progress `deleteAll()` operation can fail, which may leave a subset of data undeleted. Durable Objects with a SQLite storage backend do not have a partial `deleteAll()` issue because `deleteAll()` operations are atomic (all or nothing). - - `deleteAll()` does not proactively delete [alarms](/durable-objects/api/alarms/). Use [`deleteAlarm()`](/durable-objects/api/alarms/#deletealarm) to delete an alarm. - -### `transactionSync` - -- `transactionSync(callback)`: - - Only available when using SQLite-backed Durable Objects. - - - Invokes `callback()` wrapped in a transaction, and returns its result. - - - If `callback()` throws an exception, the transaction will be rolled back. - * The callback must complete synchronously, that is, it should not be declared `async` nor otherwise return a Promise. Only synchronous storage operations can be part of the transaction. This is intended for use with SQL queries using [`ctx.storage.sql.exec()`](/durable-objects/api/storage-api/#exec), which complete sychronously. - -### `transaction` - -- `transaction(closureFunction(txn))`: - - Runs the sequence of storage operations called on `txn` in a single transaction that either commits successfully or aborts. - - - Explicit transactions are no longer necessary. Any series of write operations with no intervening `await` will automatically be submitted atomically, and the system will prevent concurrent events from executing while `await` a read operation (unless you use `allowConcurrency: true`). Therefore, a series of reads followed by a series of writes (with no other intervening I/O) are automatically atomic and behave like a transaction. - -- `txn` - - Provides access to the `put()`, `get()`, `delete()` and `list()` methods documented above to run in the current transaction context. In order to get transactional behavior within a transaction closure, you must call the methods on the `txn` Object instead of on the top-level `ctx.storage` Object.

Also supports a `rollback()` function that ensures any changes made during the transaction will be rolled back rather than committed. After `rollback()` is called, any subsequent operations on the `txn` Object will fail with an exception. `rollback()` takes no parameters and returns nothing to the caller. - - - When using [the SQLite-backed storage engine](/durable-objects/best-practices/access-durable-objects-storage/#sqlite-storage-backend), the `txn` object is obsolete. Any storage operations performed directly on the `ctx.storage` object, including SQL queries using [`ctx.storage.sql.exec()`](/durable-objects/api/storage-api/#exec), will be considered part of the transaction. - -### `sync` - -- `sync()`: - - Synchronizes any pending writes to disk. - - - This is similar to normal behavior from automatic write coalescing. If there are any pending writes in the write buffer (including those submitted with [the `allowUnconfirmed` option](/durable-objects/api/storage-api/#supported-options-1)), the returned promise will resolve when they complete. If there are no pending writes, the returned promise will be already resolved. - -## Storage properties - -### `sql` - -`sql` is a readonly property of type `DurableObjectStorage` encapsulating the [SQL API](/durable-objects/api/storage-api/#sql-api). - -## Related resources - -- [Durable Objects: Easy, Fast, Correct Choose Three](https://blog.cloudflare.com/durable-objects-easy-fast-correct-choose-three/) -- [Zero-latency SQLite storage in every Durable Object blog](https://blog.cloudflare.com/sqlite-in-durable-objects/) -- [WebSockets API](/durable-objects/best-practices/websockets/) diff --git a/src/content/partials/durable-objects/api-async-kv-legacy.mdx b/src/content/partials/durable-objects/api-async-kv-legacy.mdx new file mode 100644 index 000000000000000..1875c5e91ccc78f --- /dev/null +++ b/src/content/partials/durable-objects/api-async-kv-legacy.mdx @@ -0,0 +1,110 @@ +--- +{} +--- + +import {Type, MetaInfo} from "~/components"; + +### `get` + +- ctx.storage.get(key , options {" "}): + - Retrieves the value associated with the given key. The type of the returned value will be whatever was previously written for the key, or undefined if the key does not exist. + +- ctx.storage.get(keys , options ): + - Retrieves the values associated with each of the provided keys. The type of each returned value in the [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) will be whatever was previously written for the corresponding key. Results in the `Map` will be sorted in increasing order of their UTF-8 encodings, with any requested keys that do not exist being omitted. Supports up to 128 keys at a time. + +#### Supported options + +- `allowConcurrency`: + - By default, the system will pause delivery of I/O events to the Object while a storage operation is in progress, in order to avoid unexpected race conditions. Pass `allowConcurrency: true` to opt out of this behavior and allow concurrent events to be delivered. + +- `noCache`: + - If true, then the key/value will not be inserted into the in-memory cache. If the key is already in the cache, the cached value will be returned, but its last-used time will not be updated. Use this when you expect this key will not be used again in the near future. This flag is only a hint. This flag will never change the semantics of your code, but it may affect performance. + +### `put` + +- put(key , value , options ): + - Stores the value and associates it with the given key. The value can be any type supported by the [structured clone algorithm](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm), which is true of most types. + + The size of keys and values have different limits depending on the Durable Object storage backend you are using. Refer to either: + - [SQLite-backed Durable Object limits](/durable-objects/platform/limits/#sqlite-backed-durable-objects-general-limits) + - [KV-backed Durable Object limits](/durable-objects/platform/limits/#key-value-backed-durable-objects-general-limits).

+ +- put(entries , options ): + - Takes an Object and stores each of its keys and values to storage. + - Each value can be any type supported by the [structured clone algorithm](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm), which is true of most types. + - Supports up to 128 key-value pairs at a time. The size of keys and values have different limits depending on the flavor of Durable Object you are using. Refer to either: + - [SQLite-backed Durable Object limits](/durable-objects/platform/limits/#sqlite-backed-durable-objects-general-limits) + - [KV-backed Durable Object limits](/durable-objects/platform/limits/#key-value-backed-durable-objects-general-limits) + +### `delete` + +- delete(key , options ): + - Deletes the key and associated value. Returns `true` if the key existed or `false` if it did not. + +- delete(keys , options ): + - Deletes the provided keys and their associated values. Supports up to 128 keys at a time. Returns a count of the number of key-value pairs deleted. + +#### Supported options + +- `put()`, `delete()` and `deleteAll()` support the following options: + +- `allowUnconfirmed` + - By default, the system will pause outgoing network messages from the Durable Object until all previous writes have been confirmed flushed to disk. If the write fails, the system will reset the Object, discard all outgoing messages, and respond to any clients with errors instead. + + - This way, Durable Objects can continue executing in parallel with a write operation, without having to worry about prematurely confirming writes, because it is impossible for any external party to observe the Object's actions unless the write actually succeeds. + + - After any write, subsequent network messages may be slightly delayed. Some applications may consider it acceptable to communicate on the basis of unconfirmed writes. Some programs may prefer to allow network traffic immediately. In this case, set `allowUnconfirmed` to `true` to opt out of the default behavior. + + - If you want to allow some outgoing network messages to proceed immediately but not others, you can use the allowUnconfirmed option to avoid blocking the messages that you want to proceed and then separately call the [`sync()`](/durable-objects/api/storage-api/#sync) method, which returns a promise that only resolves once all previous writes have successfully been persisted to disk. + +- `noCache` + - If true, then the key/value will be discarded from memory as soon as it has completed writing to disk. + + - Use `noCache` if the key will not be used again in the near future. `noCache` will never change the semantics of your code, but it may affect performance. + + - If you use `get()` to retrieve the key before the write has completed, the copy from the write buffer will be returned, thus ensuring consistency with the latest call to `put()`. + +:::note[Automatic write coalescing] + +If you invoke `put()` (or `delete()`) multiple times without performing any `await` in the meantime, the operations will automatically be combined and submitted atomically. In case of a machine failure, either all of the writes will have been stored to disk or none of the writes will have been stored to disk. +::: + +:::note[Write buffer behavior] + +The `put()` method returns a `Promise`, but most applications can discard this promise without using `await`. The `Promise` usually completes immediately, because `put()` writes to an in-memory write buffer that is flushed to disk asynchronously. However, if an application performs a large number of `put()` without waiting for any I/O, the write buffer could theoretically grow large enough to cause the isolate to exceed its 128 MB memory limit. To avoid this scenario, such applications should use `await` on the `Promise` returned by `put()`. The system will then apply backpressure onto the application, slowing it down so that the write buffer has time to flush. Using `await` will disable automatic write coalescing. +::: + +### `list` + +- list(options ): + - Returns all keys and values associated with the current Durable Object in ascending sorted order based on the keys' UTF-8 encodings. + - The type of each returned value in the [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) will be whatever was previously written for the corresponding key. + + - Be aware of how much data may be stored in your Durable Object before calling this version of `list` without options because all the data will be loaded into the Durable Object's memory, potentially hitting its [limit](/durable-objects/platform/limits/). If that is a concern, pass options to `list` as documented below. + +#### Supported options + +- `start` + - Key at which the list results should start, inclusive. + +- `startAfter` + - Key after which the list results should start, exclusive. Cannot be used simultaneously with `start`. + +- `end` + - Key at which the list results should end, exclusive. + +- `prefix` + - Restricts results to only include key-value pairs whose keys begin with the prefix. + +- `reverse` + - If true, return results in descending order instead of the default ascending order. + - Enabling `reverse` does not change the meaning of `start`, `startKey`, or `endKey`. `start` still defines the smallest key in lexicographic order that can be returned (inclusive), effectively serving as the endpoint for a reverse-order list. `end` still defines the largest key in lexicographic order that the list should consider (exclusive), effectively serving as the starting point for a reverse-order list. + +- `limit` + - Maximum number of key-value pairs to return. + +- `allowConcurrency` + - Same as the option to `get()`, above. + +- `noCache` + - Same as the option to `get()`, above. \ No newline at end of file diff --git a/src/content/partials/durable-objects/api-storage-alarms.mdx b/src/content/partials/durable-objects/api-storage-alarms.mdx new file mode 100644 index 000000000000000..770e852ba50e392 --- /dev/null +++ b/src/content/partials/durable-objects/api-storage-alarms.mdx @@ -0,0 +1,30 @@ +--- +{} +--- + +import { Type, MetaInfo, Render } from "~/components"; + +### `getAlarm` + +- getAlarm(options ): + - Retrieves the current alarm time (if set) as integer milliseconds since epoch. The alarm is considered to be set if it has not started, or if it has failed and any retry has not begun. If no alarm is set, `getAlarm()` returns `null`. + +#### Supported options + +- Same options as [`get()`](/durable-objects/api/storage-api/#get), but without `noCache`. + +### `setAlarm` + +- setAlarm(scheduledTime , options ): + - Sets the current alarm time, accepting either a JavaScript `Date`, or integer milliseconds since epoch. + + If `setAlarm()` is called with a time equal to or before `Date.now()`, the alarm will be scheduled for asynchronous execution in the immediate future. If the alarm handler is currently executing in this case, it will not be canceled. Alarms can be set to millisecond granularity and will usually execute within a few milliseconds after the set time, but can be delayed by up to a minute due to maintenance or failures while failover takes place. + +### `deleteAlarm` + +- deleteAlarm(options ): + - Deletes the alarm if one exists. Does not cancel the alarm handler if it is currently executing. + +#### Supported options + +- `setAlarm()` and `deleteAlarm()` support the same options as [`put()`](/durable-objects/api/storage-api/#put), but without `noCache`. \ No newline at end of file diff --git a/src/content/partials/durable-objects/api-storage-introduction.mdx b/src/content/partials/durable-objects/api-storage-introduction.mdx new file mode 100644 index 000000000000000..52e05e8506a8b16 --- /dev/null +++ b/src/content/partials/durable-objects/api-storage-introduction.mdx @@ -0,0 +1,29 @@ +--- +{} +--- + +import { GlossaryTooltip, Details } from "~/components"; + +The Durable Object Storage API allows Durable Objects to access transactional and strongly consistent storage. A Durable Object's attached storage is private to its unique instance and cannot be accessed by other objects. + +The Durable Object Storage API comes with several methods, including SQL, point-in-time recovery (PITR), key-value (KV), and alarm APIs. Available API methods depend on the storage backend for a Durable Objects class, either [SQLite](/durable-objects/best-practices/access-durable-objects-storage/#create-sqlite-backed-durable-object-class) or [KV](/durable-objects/reference/durable-objects-migrations/#create-durable-object-class-with-key-value-storage). + +| Methods 1 | SQLite-backed Durable Object class | KV-backed Durable Object class | +| -------------------- | ---------------------------------- | ------------------------------ | +| SQL API | ✅ | ❌ | +| PITR API | ✅ | ❌ | +| KV API | ✅ 2, 3 | ✅ | +| Alarms API | ✅ | ✅ | + +
+ +1 Each method is implicitly wrapped inside a transaction, such that +its results are atomic and isolated from all other storage operations, even when +accessing multiple key-value pairs. + +2 KV API methods like `get()`, `put()`, `delete()`, or `list()` store +data in a hidden SQLite table. + +3 For SQLite-backed Durable Objects, you can use [synchronous KV API methods](/durable-objects/api/sqlite-backed-storage/#synchronous-kv-api) using `ctx.storage.kv`. KV-backed Durable Objects use [asynchronous KV API methods](/durable-objects/api/legacy-kv-backed-storage/#asynchronous-kv-api). + +
\ No newline at end of file diff --git a/src/content/partials/durable-objects/api-storage-other-methods.mdx b/src/content/partials/durable-objects/api-storage-other-methods.mdx new file mode 100644 index 000000000000000..104295299cda294 --- /dev/null +++ b/src/content/partials/durable-objects/api-storage-other-methods.mdx @@ -0,0 +1,41 @@ +--- +{} +--- + +import { Type, MetaInfo } from "~/components"; + +### `deleteAll` + +- deleteAll(options ): + - Deletes all stored data, effectively deallocating all storage used by the Durable Object. For Durable Objects with a key-value storage backend, `deleteAll()` removes all keys and associated values for an individual Durable Object. For Durable Objects with a [SQLite storage backend](/durable-objects/best-practices/access-durable-objects-storage/#create-sqlite-backed-durable-object-class), `deleteAll()` removes the entire contents of a Durable Object's private SQLite database, including both SQL data and key-value data. + - For Durable Objects with a key-value storage backend, an in-progress `deleteAll()` operation can fail, which may leave a subset of data undeleted. Durable Objects with a SQLite storage backend do not have a partial `deleteAll()` issue because `deleteAll()` operations are atomic (all or nothing). + - `deleteAll()` does not proactively delete [alarms](/durable-objects/api/alarms/). Use [`deleteAlarm()`](/durable-objects/api/alarms/#deletealarm) to delete an alarm. + +### `transactionSync` + +- `transactionSync(callback)`: + - Only available when using SQLite-backed Durable Objects. + + - Invokes `callback()` wrapped in a transaction, and returns its result. + + - If `callback()` throws an exception, the transaction will be rolled back. + * The callback must complete synchronously, that is, it should not be declared `async` nor otherwise return a Promise. Only synchronous storage operations can be part of the transaction. This is intended for use with SQL queries using [`ctx.storage.sql.exec()`](/durable-objects/api/storage-api/#exec), which complete sychronously. + +### `transaction` + +- `transaction(closureFunction(txn))`: + - Runs the sequence of storage operations called on `txn` in a single transaction that either commits successfully or aborts. + + - Explicit transactions are no longer necessary. Any series of write operations with no intervening `await` will automatically be submitted atomically, and the system will prevent concurrent events from executing while `await` a read operation (unless you use `allowConcurrency: true`). Therefore, a series of reads followed by a series of writes (with no other intervening I/O) are automatically atomic and behave like a transaction. + +- `txn` + - Provides access to the `put()`, `get()`, `delete()` and `list()` methods documented above to run in the current transaction context. In order to get transactional behavior within a transaction closure, you must call the methods on the `txn` Object instead of on the top-level `ctx.storage` Object.

Also supports a `rollback()` function that ensures any changes made during the transaction will be rolled back rather than committed. After `rollback()` is called, any subsequent operations on the `txn` Object will fail with an exception. `rollback()` takes no parameters and returns nothing to the caller. + + - When using [the SQLite-backed storage engine](/durable-objects/best-practices/access-durable-objects-storage/#sqlite-storage-backend), the `txn` object is obsolete. Any storage operations performed directly on the `ctx.storage` object, including SQL queries using [`ctx.storage.sql.exec()`](/durable-objects/api/storage-api/#exec), will be considered part of the transaction. + +### `sync` + +- `sync()`: + - Synchronizes any pending writes to disk. + + - This is similar to normal behavior from automatic write coalescing. If there are any pending writes in the write buffer (including those submitted with [the `allowUnconfirmed` option](/durable-objects/api/storage-api/#supported-options-1)), the returned promise will resolve when they complete. If there are no pending writes, the returned promise will be already resolved. \ No newline at end of file diff --git a/src/content/partials/durable-objects/api-sync-kv.mdx b/src/content/partials/durable-objects/api-sync-kv.mdx new file mode 100644 index 000000000000000..1875c5e91ccc78f --- /dev/null +++ b/src/content/partials/durable-objects/api-sync-kv.mdx @@ -0,0 +1,110 @@ +--- +{} +--- + +import {Type, MetaInfo} from "~/components"; + +### `get` + +- ctx.storage.get(key , options {" "}): + - Retrieves the value associated with the given key. The type of the returned value will be whatever was previously written for the key, or undefined if the key does not exist. + +- ctx.storage.get(keys , options ): + - Retrieves the values associated with each of the provided keys. The type of each returned value in the [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) will be whatever was previously written for the corresponding key. Results in the `Map` will be sorted in increasing order of their UTF-8 encodings, with any requested keys that do not exist being omitted. Supports up to 128 keys at a time. + +#### Supported options + +- `allowConcurrency`: + - By default, the system will pause delivery of I/O events to the Object while a storage operation is in progress, in order to avoid unexpected race conditions. Pass `allowConcurrency: true` to opt out of this behavior and allow concurrent events to be delivered. + +- `noCache`: + - If true, then the key/value will not be inserted into the in-memory cache. If the key is already in the cache, the cached value will be returned, but its last-used time will not be updated. Use this when you expect this key will not be used again in the near future. This flag is only a hint. This flag will never change the semantics of your code, but it may affect performance. + +### `put` + +- put(key , value , options ): + - Stores the value and associates it with the given key. The value can be any type supported by the [structured clone algorithm](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm), which is true of most types. + + The size of keys and values have different limits depending on the Durable Object storage backend you are using. Refer to either: + - [SQLite-backed Durable Object limits](/durable-objects/platform/limits/#sqlite-backed-durable-objects-general-limits) + - [KV-backed Durable Object limits](/durable-objects/platform/limits/#key-value-backed-durable-objects-general-limits).

+ +- put(entries , options ): + - Takes an Object and stores each of its keys and values to storage. + - Each value can be any type supported by the [structured clone algorithm](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm), which is true of most types. + - Supports up to 128 key-value pairs at a time. The size of keys and values have different limits depending on the flavor of Durable Object you are using. Refer to either: + - [SQLite-backed Durable Object limits](/durable-objects/platform/limits/#sqlite-backed-durable-objects-general-limits) + - [KV-backed Durable Object limits](/durable-objects/platform/limits/#key-value-backed-durable-objects-general-limits) + +### `delete` + +- delete(key , options ): + - Deletes the key and associated value. Returns `true` if the key existed or `false` if it did not. + +- delete(keys , options ): + - Deletes the provided keys and their associated values. Supports up to 128 keys at a time. Returns a count of the number of key-value pairs deleted. + +#### Supported options + +- `put()`, `delete()` and `deleteAll()` support the following options: + +- `allowUnconfirmed` + - By default, the system will pause outgoing network messages from the Durable Object until all previous writes have been confirmed flushed to disk. If the write fails, the system will reset the Object, discard all outgoing messages, and respond to any clients with errors instead. + + - This way, Durable Objects can continue executing in parallel with a write operation, without having to worry about prematurely confirming writes, because it is impossible for any external party to observe the Object's actions unless the write actually succeeds. + + - After any write, subsequent network messages may be slightly delayed. Some applications may consider it acceptable to communicate on the basis of unconfirmed writes. Some programs may prefer to allow network traffic immediately. In this case, set `allowUnconfirmed` to `true` to opt out of the default behavior. + + - If you want to allow some outgoing network messages to proceed immediately but not others, you can use the allowUnconfirmed option to avoid blocking the messages that you want to proceed and then separately call the [`sync()`](/durable-objects/api/storage-api/#sync) method, which returns a promise that only resolves once all previous writes have successfully been persisted to disk. + +- `noCache` + - If true, then the key/value will be discarded from memory as soon as it has completed writing to disk. + + - Use `noCache` if the key will not be used again in the near future. `noCache` will never change the semantics of your code, but it may affect performance. + + - If you use `get()` to retrieve the key before the write has completed, the copy from the write buffer will be returned, thus ensuring consistency with the latest call to `put()`. + +:::note[Automatic write coalescing] + +If you invoke `put()` (or `delete()`) multiple times without performing any `await` in the meantime, the operations will automatically be combined and submitted atomically. In case of a machine failure, either all of the writes will have been stored to disk or none of the writes will have been stored to disk. +::: + +:::note[Write buffer behavior] + +The `put()` method returns a `Promise`, but most applications can discard this promise without using `await`. The `Promise` usually completes immediately, because `put()` writes to an in-memory write buffer that is flushed to disk asynchronously. However, if an application performs a large number of `put()` without waiting for any I/O, the write buffer could theoretically grow large enough to cause the isolate to exceed its 128 MB memory limit. To avoid this scenario, such applications should use `await` on the `Promise` returned by `put()`. The system will then apply backpressure onto the application, slowing it down so that the write buffer has time to flush. Using `await` will disable automatic write coalescing. +::: + +### `list` + +- list(options ): + - Returns all keys and values associated with the current Durable Object in ascending sorted order based on the keys' UTF-8 encodings. + - The type of each returned value in the [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) will be whatever was previously written for the corresponding key. + + - Be aware of how much data may be stored in your Durable Object before calling this version of `list` without options because all the data will be loaded into the Durable Object's memory, potentially hitting its [limit](/durable-objects/platform/limits/). If that is a concern, pass options to `list` as documented below. + +#### Supported options + +- `start` + - Key at which the list results should start, inclusive. + +- `startAfter` + - Key after which the list results should start, exclusive. Cannot be used simultaneously with `start`. + +- `end` + - Key at which the list results should end, exclusive. + +- `prefix` + - Restricts results to only include key-value pairs whose keys begin with the prefix. + +- `reverse` + - If true, return results in descending order instead of the default ascending order. + - Enabling `reverse` does not change the meaning of `start`, `startKey`, or `endKey`. `start` still defines the smallest key in lexicographic order that can be returned (inclusive), effectively serving as the endpoint for a reverse-order list. `end` still defines the largest key in lexicographic order that the list should consider (exclusive), effectively serving as the starting point for a reverse-order list. + +- `limit` + - Maximum number of key-value pairs to return. + +- `allowConcurrency` + - Same as the option to `get()`, above. + +- `noCache` + - Same as the option to `get()`, above. \ No newline at end of file From 7ec7875f675c7932e5000f62c506d7d35b588548 Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Fri, 5 Sep 2025 17:16:23 +0100 Subject: [PATCH 02/12] Fixing links --- public/__redirects | 5 ++-- ...025-04-07-sqlite-in-durable-objects-ga.mdx | 2 +- .../agents/api-reference/schedule-tasks.mdx | 2 +- .../api-reference/store-and-sync-state.mdx | 2 +- .../docs/durable-objects/api/alarms.mdx | 2 +- ...-storage.mdx => legacy-kv-storage-api.mdx} | 25 +------------------ ...ked-storage.mdx => sqlite-storage-api.mdx} | 4 +-- .../access-durable-objects-storage.mdx | 10 ++++---- .../best-practices/websockets.mdx | 4 +-- .../concepts/what-are-durable-objects.mdx | 6 ++--- .../durable-object-in-memory-state.mdx | 2 +- .../docs/durable-objects/get-started.mdx | 2 +- src/content/docs/durable-objects/index.mdx | 4 +-- .../docs/durable-objects/platform/limits.mdx | 2 +- .../reference/in-memory-state.mdx | 2 +- src/content/glossary/durable-objects.yaml | 2 +- .../durable-objects/api-async-kv-legacy.mdx | 2 +- .../durable-objects/api-storage-alarms.mdx | 4 +-- .../api-storage-other-methods.mdx | 6 ++--- .../partials/durable-objects/api-sync-kv.mdx | 2 +- .../durable-objects/do-faq-limits.mdx | 2 +- .../durable-objects/do-faq-pricing.mdx | 2 +- .../durable-objects-pricing.mdx | 4 +-- .../durable-objects/durable-objects-sql.mdx | 2 +- .../durable-objects/recommend-sqlite-do.mdx | 2 +- .../durable-objects/storage-intro-text.mdx | 3 +-- .../release-notes/durable-objects.yaml | 4 +-- 27 files changed, 43 insertions(+), 66 deletions(-) rename src/content/docs/durable-objects/api/{legacy-kv-backed-storage.mdx => legacy-kv-storage-api.mdx} (60%) rename src/content/docs/durable-objects/api/{sqlite-backed-storage.mdx => sqlite-storage-api.mdx} (97%) diff --git a/public/__redirects b/public/__redirects index c8db578b55029a4..38bc3d6b46ee729 100644 --- a/public/__redirects +++ b/public/__redirects @@ -516,7 +516,7 @@ /durable-objects/api/hibernatable-websockets-api/ /durable-objects/best-practices/websockets/ 301 /durable-objects/api/alarms-in-durable-objects/ /durable-objects/api/alarms/ 301 /durable-objects/api/websockets/ /durable-objects/best-practices/websockets/ 301 -/durable-objects/api/sql-storage/ /durable-objects/api/storage-api/ 301 +/durable-objects/api/sql-storage/ /durable-objects/api/sqlite-storage-api/ 301 /durable-objects/platform/data-location/ /durable-objects/reference/data-location/ 301 /durable-objects/platform/environments/ /durable-objects/reference/environments/ 301 /durable-objects/platform/troubleshooting/ /durable-objects/observability/troubleshooting/ 301 @@ -531,7 +531,7 @@ /durable-objects/reference/error-handling/ /durable-objects/best-practices/error-handling/ 301 /durable-objects/reference/troubleshooting/ /durable-objects/observability/troubleshooting/ 301 /durable-objects/reference/websockets/ /durable-objects/best-practices/websockets/ 301 -/durable-objects/api/transactional-storage-api/ /durable-objects/api/storage-api/ 301 +/durable-objects/api/transactional-storage-api/ /durable-objects/api/sqlite-storage-api/ 301 /durable-objects/platform/changelog/ /durable-objects/release-notes/ 301 /durable-objects/changelog/ /durable-objects/release-notes/ 301 /durable-objects/glossary/ /durable-objects/reference/glossary/ 301 @@ -549,6 +549,7 @@ /durable-objects/get-started/video-series/ /durable-objects/video-tutorials/ 301 /durable-objects/what-are-durable-objects/ /durable-objects/concepts/what-are-durable-objects/ 301 +/durable-objects/api/storage-api /durable-objects/api/sqlite-storage-api/ 301 # email-routing /email-routing/enable-email-routing/ /email-routing/get-started/enable-email-routing/ 301 diff --git a/src/content/changelog/durable-objects/2025-04-07-sqlite-in-durable-objects-ga.mdx b/src/content/changelog/durable-objects/2025-04-07-sqlite-in-durable-objects-ga.mdx index 89022b7bf7a61b6..51e938bc3159a05 100644 --- a/src/content/changelog/durable-objects/2025-04-07-sqlite-in-durable-objects-ga.mdx +++ b/src/content/changelog/durable-objects/2025-04-07-sqlite-in-durable-objects-ga.mdx @@ -9,7 +9,7 @@ date: 2025-04-07 SQLite in Durable Objects is now generally available (GA) with 10GB SQLite database per Durable Object. Since the [public beta](https://blog.cloudflare.com/sqlite-in-durable-objects/) in September 2024, we've added feature parity and robustness for the SQLite storage backend compared to the preexisting key-value (KV) storage backend for Durable Objects. -SQLite-backed Durable Objects are recommended for all new Durable Object classes, using `new_sqlite_classes` [Wrangler configuration](/durable-objects/best-practices/access-durable-objects-storage/#create-sqlite-backed-durable-object-class). Only SQLite-backed Durable Objects have access to Storage API's [SQL](/durable-objects/api/storage-api/#sql-api) and [point-in-time recovery](/durable-objects/api/storage-api/#pitr-point-in-time-recovery-api) methods, which provide relational data modeling, SQL querying, and better data management. +SQLite-backed Durable Objects are recommended for all new Durable Object classes, using `new_sqlite_classes` [Wrangler configuration](/durable-objects/best-practices/access-durable-objects-storage/#create-sqlite-backed-durable-object-class). Only SQLite-backed Durable Objects have access to Storage API's [SQL](/durable-objects/api/sqlite-storage-api/#sql-api) and [point-in-time recovery](/durable-objects/api/sqlite-storage-api/#pitr-point-in-time-recovery-api) methods, which provide relational data modeling, SQL querying, and better data management. ```js export class MyDurableObject extends DurableObject { diff --git a/src/content/docs/agents/api-reference/schedule-tasks.mdx b/src/content/docs/agents/api-reference/schedule-tasks.mdx index 90fd71ccc0984a5..0174d45792a1e4f 100644 --- a/src/content/docs/agents/api-reference/schedule-tasks.mdx +++ b/src/content/docs/agents/api-reference/schedule-tasks.mdx @@ -70,7 +70,7 @@ Calling `await this.schedule` returns a `Schedule`, which includes the task's ra :::note[Maximum scheduled tasks] -Each task is mapped to a row in the Agent's underlying [SQLite database](/durable-objects/api/storage-api/), which means that each task can be up to 2 MB in size. The maximum number of tasks must be `(task_size * tasks) + all_other_state < maximum_database_size` (currently 1GB per Agent). +Each task is mapped to a row in the Agent's underlying [SQLite database](/durable-objects/api/sqlite-storage-api/), which means that each task can be up to 2 MB in size. The maximum number of tasks must be `(task_size * tasks) + all_other_state < maximum_database_size` (currently 1GB per Agent). ::: diff --git a/src/content/docs/agents/api-reference/store-and-sync-state.mdx b/src/content/docs/agents/api-reference/store-and-sync-state.mdx index d625c6c8a507c17..12711a3e0a10e6b 100644 --- a/src/content/docs/agents/api-reference/store-and-sync-state.mdx +++ b/src/content/docs/agents/api-reference/store-and-sync-state.mdx @@ -227,7 +227,7 @@ Learn more about the zero-latency SQL storage that powers both Agents and Durabl ::: -The SQL API exposed to an Agent is similar to the one [within Durable Objects](/durable-objects/api/storage-api/#sql-api): Durable Object SQL methods available on `this.ctx.storage.sql`. You can use the same SQL queries with the Agent's database, create tables, and query data, just as you would with Durable Objects or [D1](/d1/). +The SQL API exposed to an Agent is similar to the one [within Durable Objects](/durable-objects/api/sqlite-storage-api/#sql-api): Durable Object SQL methods available on `this.ctx.storage.sql`. You can use the same SQL queries with the Agent's database, create tables, and query data, just as you would with Durable Objects or [D1](/d1/). ### Use Agent state as model context diff --git a/src/content/docs/durable-objects/api/alarms.mdx b/src/content/docs/durable-objects/api/alarms.mdx index e55c094cbb4d14c..a6fcf26fe792c08 100644 --- a/src/content/docs/durable-objects/api/alarms.mdx +++ b/src/content/docs/durable-objects/api/alarms.mdx @@ -133,4 +133,4 @@ class MyDurableObject extends DurableObject { - Understand how to [use the Alarms API](/durable-objects/examples/alarms-api/) in an end-to-end example. - Read the [Durable Objects alarms announcement blog post](https://blog.cloudflare.com/durable-objects-alarms/). -- Review the [Storage API](/durable-objects/api/storage-api/) documentation for Durable Objects. +- Review the [Storage API](/durable-objects/api/sqlite-storage-api/) documentation for Durable Objects. diff --git a/src/content/docs/durable-objects/api/legacy-kv-backed-storage.mdx b/src/content/docs/durable-objects/api/legacy-kv-storage-api.mdx similarity index 60% rename from src/content/docs/durable-objects/api/legacy-kv-backed-storage.mdx rename to src/content/docs/durable-objects/api/legacy-kv-storage-api.mdx index ba5d947c1d0990e..1f293274fa1ee2b 100644 --- a/src/content/docs/durable-objects/api/legacy-kv-backed-storage.mdx +++ b/src/content/docs/durable-objects/api/legacy-kv-storage-api.mdx @@ -52,30 +52,7 @@ KV-backed Durable Objects use KV API methods which are asynchronous. ## Alarms -### `getAlarm` - -- getAlarm(options ): - - Retrieves the current alarm time (if set) as integer milliseconds since epoch. The alarm is considered to be set if it has not started, or if it has failed and any retry has not begun. If no alarm is set, `getAlarm()` returns `null`. - -#### Supported options - -- Same options as [`get()`](/durable-objects/api/storage-api/#get), but without `noCache`. - -### `setAlarm` - -- setAlarm(scheduledTime , options ): - - Sets the current alarm time, accepting either a JavaScript `Date`, or integer milliseconds since epoch. - - If `setAlarm()` is called with a time equal to or before `Date.now()`, the alarm will be scheduled for asynchronous execution in the immediate future. If the alarm handler is currently executing in this case, it will not be canceled. Alarms can be set to millisecond granularity and will usually execute within a few milliseconds after the set time, but can be delayed by up to a minute due to maintenance or failures while failover takes place. - -### `deleteAlarm` - -- deleteAlarm(options ): - - Deletes the alarm if one exists. Does not cancel the alarm handler if it is currently executing. - -#### Supported options - -- `setAlarm()` and `deleteAlarm()` support the same options as [`put()`](/durable-objects/api/storage-api/#put), but without `noCache`. + ## Other diff --git a/src/content/docs/durable-objects/api/sqlite-backed-storage.mdx b/src/content/docs/durable-objects/api/sqlite-storage-api.mdx similarity index 97% rename from src/content/docs/durable-objects/api/sqlite-backed-storage.mdx rename to src/content/docs/durable-objects/api/sqlite-storage-api.mdx index d3108e617af215a..44eba5d3674834e 100644 --- a/src/content/docs/durable-objects/api/sqlite-backed-storage.mdx +++ b/src/content/docs/durable-objects/api/sqlite-storage-api.mdx @@ -48,7 +48,7 @@ JavaScript is a single-threaded and event-driven programming language. This mean ## SQL API -The `SqlStorage` interface encapsulates methods that modify the SQLite database embedded within a Durable Object. The `SqlStorage` interface is accessible via the [`sql` property](/durable-objects/api/storage-api/#sql) of `DurableObjectStorage` class. +The `SqlStorage` interface encapsulates methods that modify the SQLite database embedded within a Durable Object. The `SqlStorage` interface is accessible via the [`sql` property](/durable-objects/api/sqlite-storage-api/#sql) of `DurableObjectStorage` class. For example, using `sql.exec()`, a user can create a table, then insert rows into the table. @@ -133,7 +133,7 @@ console.log(cursor.toArray()); // prints [{ artistid: 456, artistname: 'Bob' },{ - Any numeric value in a column is affected by JavaScript's 52-bit precision for numbers. If you store a very large number (in `int64`), then retrieve the same value, the returned value may be less precise than your original number. :::note[SQL transactions] -Note that `sql.exec()` cannot execute transaction-related statements like `BEGIN TRANSACTION` or `SAVEPOINT`. Instead, use the [`ctx.storage.transaction()`](/durable-objects/api/storage-api/#transaction) or [`ctx.storage.transactionSync()`](/durable-objects/api/storage-api/#transactionsync) APIs to start a transaction, and then execute SQL queries in your callback. +Note that `sql.exec()` cannot execute transaction-related statements like `BEGIN TRANSACTION` or `SAVEPOINT`. Instead, use the [`ctx.storage.transaction()`](/durable-objects/api/sqlite-storage-api/#transaction) or [`ctx.storage.transactionSync()`](/durable-objects/api/sqlite-storage-api/#transactionsync) APIs to start a transaction, and then execute SQL queries in your callback. ::: #### Examples diff --git a/src/content/docs/durable-objects/best-practices/access-durable-objects-storage.mdx b/src/content/docs/durable-objects/best-practices/access-durable-objects-storage.mdx index 47a190a43f1516c..8f23c7ce6e281c6 100644 --- a/src/content/docs/durable-objects/best-practices/access-durable-objects-storage.mdx +++ b/src/content/docs/durable-objects/best-practices/access-durable-objects-storage.mdx @@ -22,7 +22,7 @@ A Durable Object's [in-memory state](/durable-objects/reference/in-memory-state/ -[Storage API methods](/durable-objects/api/storage-api/#methods) are available on `ctx.storage` parameter passed to the Durable Object constructor. Storage API has several methods, including SQL, point-in-time recovery (PITR), key-value (KV), and alarm APIs. +[Storage API methods](/durable-objects/api/sqlite-storage-api/) are available on `ctx.storage` parameter passed to the Durable Object constructor. Storage API has several methods, including SQL, point-in-time recovery (PITR), key-value (KV), and alarm APIs. Only Durable Object classes with a SQLite storage backend can access SQL API. @@ -40,13 +40,13 @@ new_sqlite_classes = ["MyDurableObject"] # Array of new classes -[SQL API](/durable-objects/api/storage-api/#exec) is available on `ctx.storage.sql` parameter passed to the Durable Object constructor. +[SQL API](/durable-objects/api/sqlite-storage-api/#exec) is available on `ctx.storage.sql` parameter passed to the Durable Object constructor. -SQLite-backed Durable Objects also offer [point-in-time recovery API](/durable-objects/api/storage-api/#pitr-point-in-time-recovery-api), which uses bookmarks to allow you to restore a Durable Object's embedded SQLite database to any point in time in the past 30 days. +SQLite-backed Durable Objects also offer [point-in-time recovery API](/durable-objects/api/sqlite-storage-api/#pitr-point-in-time-recovery-api), which uses bookmarks to allow you to restore a Durable Object's embedded SQLite database to any point in time in the past 30 days. ### Initialize instance variables from storage -A common pattern is to initialize a Durable Object from [persistent storage](/durable-objects/api/storage-api/) and set instance variables the first time it is accessed. Since future accesses are routed to the same Durable Object, it is then possible to return any initialized values without making further calls to persistent storage. +A common pattern is to initialize a Durable Object from [persistent storage](/durable-objects/api/sqlite-storage-api/) and set instance variables the first time it is accessed. Since future accesses are routed to the same Durable Object, it is then possible to return any initialized values without making further calls to persistent storage. ```ts import { DurableObject } from "cloudflare:workers"; @@ -75,7 +75,7 @@ export class Counter extends DurableObject { A Durable Object fully ceases to exist if, when it shuts down, its storage is empty. If you never write to a Durable Object's storage at all (including setting alarms), then storage remains empty, and so the Durable Object will no longer exist once it shuts down. -However if you ever write using [Storage API](/durable-objects/api/storage-api/), including setting alarms, then you must explicitly call [`storage.deleteAll()`](/durable-objects/api/storage-api/#deleteall) to empty storage and [`storage.deleteAlarm()`](/durable-objects/api/storage-api/#deletealarm) if you've configured an alarm. It is not sufficient to simply delete the specific data that you wrote, such as deleting a key or dropping a table, as some metadata may remain. The only way to remove all storage is to call `deleteAll()`. Calling `deleteAll()` ensures that a Durable Object will not be billed for storage. +However if you ever write using [Storage API](/durable-objects/api/sqlite-storage-api/), including setting alarms, then you must explicitly call [`storage.deleteAll()`](/durable-objects/api/sqlite-storage-api/#deleteall) to empty storage and [`storage.deleteAlarm()`](/durable-objects/api/sqlite-storage-api/#deletealarm) if you've configured an alarm. It is not sufficient to simply delete the specific data that you wrote, such as deleting a key or dropping a table, as some metadata may remain. The only way to remove all storage is to call `deleteAll()`. Calling `deleteAll()` ensures that a Durable Object will not be billed for storage. ```ts export class MyDurableObject extends DurableObject { diff --git a/src/content/docs/durable-objects/best-practices/websockets.mdx b/src/content/docs/durable-objects/best-practices/websockets.mdx index 93005813cbfd81b..9f191b3966a8198 100644 --- a/src/content/docs/durable-objects/best-practices/websockets.mdx +++ b/src/content/docs/durable-objects/best-practices/websockets.mdx @@ -174,9 +174,9 @@ The following are methods available on the **Native Durable Object WebSocket API : - - Keeps a copy of `value` associated with the WebSocket to survive hibernation. The value can be any type supported by the [structured clone algorithm](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm), which is true of most types. If the value needs to be durable please use [Durable Object Storage](/durable-objects/api/storage-api/). + - Keeps a copy of `value` associated with the WebSocket to survive hibernation. The value can be any type supported by the [structured clone algorithm](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm), which is true of most types. If the value needs to be durable please use [Durable Object Storage](/durable-objects/api/sqlite-storage-api/). - - If you modify `value` after calling this method, those changes will not be retained unless you call this method again. The serialized size of `value` is limited to 2,048 bytes, otherwise this method will throw an error. If you need larger values to survive hibernation, use the [Storage API](/durable-objects/api/storage-api/) and pass the corresponding key to this method so it can be retrieved later. + - If you modify `value` after calling this method, those changes will not be retained unless you call this method again. The serialized size of `value` is limited to 2,048 bytes, otherwise this method will throw an error. If you need larger values to survive hibernation, use the [Storage API](/durable-objects/api/sqlite-storage-api/) and pass the corresponding key to this method so it can be retrieved later. #### `WebSocket.deserializeAttachment()` diff --git a/src/content/docs/durable-objects/concepts/what-are-durable-objects.mdx b/src/content/docs/durable-objects/concepts/what-are-durable-objects.mdx index 6230639d64e669f..e3ef1e994026ff9 100644 --- a/src/content/docs/durable-objects/concepts/what-are-durable-objects.mdx +++ b/src/content/docs/durable-objects/concepts/what-are-durable-objects.mdx @@ -21,7 +21,7 @@ Durable Objects have properties that make them a great fit for distributed state **Storage colocated with compute** -- Each Durable Object has its own [durable, transactional, and strongly consistent storage](/durable-objects/api/storage-api/) (up to 10 GB[^1]), persisted across requests, and accessible only within that object. +- Each Durable Object has its own [durable, transactional, and strongly consistent storage](/durable-objects/api/sqlite-storage-api/) (up to 10 GB[^1]), persisted across requests, and accessible only within that object. **Single-threaded concurrency** @@ -46,9 +46,9 @@ In-memory state is reset when the Durable Object hibernates after being idle for ### Storage API -The [Durable Object Storage API](/durable-objects/api/storage-api/) allows Durable Objects to access fast, transactional, and strongly consistent storage. A Durable Object's attached storage is private to its unique instance and cannot be accessed by other objects. +The [Durable Object Storage API](/durable-objects/api/sqlite-storage-api/) allows Durable Objects to access fast, transactional, and strongly consistent storage. A Durable Object's attached storage is private to its unique instance and cannot be accessed by other objects. -There are two flavors of the storage API, a [key-value (KV) API](/durable-objects/api/storage-api/#kv-api) and an [SQL API](/durable-objects/api/storage-api/#sql-api). +There are two flavors of the storage API, a [key-value (KV) API](/durable-objects/api/legacy-kv-storage-api/) and an [SQL API](/durable-objects/api/sqlite-storage-api/). When using the [new SQLite in Durable Objects storage backend](/durable-objects/reference/durable-objects-migrations/#enable-sqlite-storage-backend-on-new-durable-object-class-migration), you have access to both the APIs. However, if you use the previous storage backend you only have access to the key-value API. diff --git a/src/content/docs/durable-objects/examples/durable-object-in-memory-state.mdx b/src/content/docs/durable-objects/examples/durable-object-in-memory-state.mdx index 0c1e518a9111498..a569bc87a5e1610 100644 --- a/src/content/docs/durable-objects/examples/durable-object-in-memory-state.mdx +++ b/src/content/docs/durable-objects/examples/durable-object-in-memory-state.mdx @@ -11,7 +11,7 @@ description: Create a Durable Object that stores the last location it was import { WranglerConfig } from "~/components"; -This example shows you how Durable Objects are stateful, meaning in-memory state can be retained between requests. After a brief period of inactivity, the Durable Object will be evicted, and all in-memory state will be lost. The next request will reconstruct the object, but instead of showing the city of the previous request, it will display a message indicating that the object has been reinitialized. If you need your applications state to survive eviction, write the state to storage by using the [Storage API](/durable-objects/api/storage-api/), or by storing your data elsewhere. +This example shows you how Durable Objects are stateful, meaning in-memory state can be retained between requests. After a brief period of inactivity, the Durable Object will be evicted, and all in-memory state will be lost. The next request will reconstruct the object, but instead of showing the city of the previous request, it will display a message indicating that the object has been reinitialized. If you need your applications state to survive eviction, write the state to storage by using the [Storage API](/durable-objects/api/sqlite-storage-api/), or by storing your data elsewhere. ```js import { DurableObject } from "cloudflare:workers"; diff --git a/src/content/docs/durable-objects/get-started.mdx b/src/content/docs/durable-objects/get-started.mdx index cef7cadf09c73a5..9c5cb07325aca85 100644 --- a/src/content/docs/durable-objects/get-started.mdx +++ b/src/content/docs/durable-objects/get-started.mdx @@ -185,7 +185,7 @@ class MyDurableObject(DurableObject): In the code above, you have: 1. Defined a RPC method, `sayHello()`, that can be called by a Worker to communicate with a Durable Object. -2. Accessed a Durable Object's attached storage, which is a private SQLite database only accessible to the object, using [SQL API](/durable-objects/api/storage-api/#exec) methods (`sql.exec()`) available on `ctx.storage` . +2. Accessed a Durable Object's attached storage, which is a private SQLite database only accessible to the object, using [SQL API](/durable-objects/api/sqlite-storage-api/#exec) methods (`sql.exec()`) available on `ctx.storage` . 3. Returned an object representing the single row query result using `one()`, which checks that the query result has exactly one row. 4. Return the `greeting` column from the row object result. diff --git a/src/content/docs/durable-objects/index.mdx b/src/content/docs/durable-objects/index.mdx index 7be9043a1a81c8f..8a80efada49b8d4 100644 --- a/src/content/docs/durable-objects/index.mdx +++ b/src/content/docs/durable-objects/index.mdx @@ -38,7 +38,7 @@ Use Durable Objects to build applications that need coordination among multiple :::note SQLite-backed Durable Objects are now available on the Workers Free plan with these [limits](/durable-objects/platform/pricing/). -[SQLite storage](/durable-objects/best-practices/access-durable-objects-storage/) and corresponding [Storage API](/durable-objects/api/storage-api/) methods like `sql.exec` have moved from beta to general availability. New Durable Object classes should use wrangler configuration for [SQLite storage](/durable-objects/best-practices/access-durable-objects-storage/#wrangler-configuration-for-sqlite-durable-objects). +[SQLite storage](/durable-objects/best-practices/access-durable-objects-storage/) and corresponding [Storage API](/durable-objects/api/sqlite-storage-api/) methods like `sql.exec` have moved from beta to general availability. New Durable Object classes should use wrangler configuration for [SQLite storage](/durable-objects/best-practices/access-durable-objects-storage/#wrangler-configuration-for-sqlite-durable-objects). ::: ### What are Durable Objects? @@ -57,7 +57,7 @@ Learn how Durable Objects coordinate connections among multiple clients or event - + Learn how Durable Objects provide transactional, strongly consistent, and serializable storage. diff --git a/src/content/docs/durable-objects/platform/limits.mdx b/src/content/docs/durable-objects/platform/limits.mdx index 520cb9361f57f79..a0ef91fd9ac74da 100644 --- a/src/content/docs/durable-objects/platform/limits.mdx +++ b/src/content/docs/durable-objects/platform/limits.mdx @@ -44,7 +44,7 @@ Durable Objects are a special kind of Worker, so [Workers Limits](/workers/platf ### SQL storage limits -For Durable Object classes with [SQLite storage](/durable-objects/api/storage-api/#sql-storage) these SQL limits apply: +For Durable Object classes with [SQLite storage](/durable-objects/api/sqlite-storage-api/) these SQL limits apply: | SQL | Limit | | -------------------------------------------------------- | ----------------------------------------------- | diff --git a/src/content/docs/durable-objects/reference/in-memory-state.mdx b/src/content/docs/durable-objects/reference/in-memory-state.mdx index c34016efc3f5e86..9e0e8ce39e737fa 100644 --- a/src/content/docs/durable-objects/reference/in-memory-state.mdx +++ b/src/content/docs/durable-objects/reference/in-memory-state.mdx @@ -11,7 +11,7 @@ In-memory state means that each Durable O Variables in a Durable Object will maintain state as long as your Durable Object is not evicted from memory. -A common pattern is to initialize a Durable Object from [persistent storage](/durable-objects/api/storage-api/) and set instance variables the first time it is accessed. Since future accesses are routed to the same Durable Object, it is then possible to return any initialized values without making further calls to persistent storage. +A common pattern is to initialize a Durable Object from [persistent storage](/durable-objects/api/sqlite-storage-api/) and set instance variables the first time it is accessed. Since future accesses are routed to the same Durable Object, it is then possible to return any initialized values without making further calls to persistent storage. ```js export class Counter { diff --git a/src/content/glossary/durable-objects.yaml b/src/content/glossary/durable-objects.yaml index e43f0bc58c3263c..f670314ce1c529e 100644 --- a/src/content/glossary/durable-objects.yaml +++ b/src/content/glossary/durable-objects.yaml @@ -34,7 +34,7 @@ entries: - term: "Storage API" general_definition: |- - The transactional and strongly consistent (serializable) [Storage API](/durable-objects/api/storage-api/) for persisting data within each Durable Object. State stored within a unique Durable Object is "private" to that Durable Object, and not accessible from other Durable Objects. + The transactional and strongly consistent (serializable) [Storage API](/durable-objects/api/sqlite-storage-api/) for persisting data within each Durable Object. State stored within a unique Durable Object is "private" to that Durable Object, and not accessible from other Durable Objects. Storage API includes key-value (KV) API, SQL API, and point-in-time-recovery (PITR) API. diff --git a/src/content/partials/durable-objects/api-async-kv-legacy.mdx b/src/content/partials/durable-objects/api-async-kv-legacy.mdx index 1875c5e91ccc78f..954a4799b2ba6bf 100644 --- a/src/content/partials/durable-objects/api-async-kv-legacy.mdx +++ b/src/content/partials/durable-objects/api-async-kv-legacy.mdx @@ -55,7 +55,7 @@ import {Type, MetaInfo} from "~/components"; - After any write, subsequent network messages may be slightly delayed. Some applications may consider it acceptable to communicate on the basis of unconfirmed writes. Some programs may prefer to allow network traffic immediately. In this case, set `allowUnconfirmed` to `true` to opt out of the default behavior. - - If you want to allow some outgoing network messages to proceed immediately but not others, you can use the allowUnconfirmed option to avoid blocking the messages that you want to proceed and then separately call the [`sync()`](/durable-objects/api/storage-api/#sync) method, which returns a promise that only resolves once all previous writes have successfully been persisted to disk. + - If you want to allow some outgoing network messages to proceed immediately but not others, you can use the allowUnconfirmed option to avoid blocking the messages that you want to proceed and then separately call the [`sync()`](#sync) method, which returns a promise that only resolves once all previous writes have successfully been persisted to disk. - `noCache` - If true, then the key/value will be discarded from memory as soon as it has completed writing to disk. diff --git a/src/content/partials/durable-objects/api-storage-alarms.mdx b/src/content/partials/durable-objects/api-storage-alarms.mdx index 770e852ba50e392..a46eac25d0dbed0 100644 --- a/src/content/partials/durable-objects/api-storage-alarms.mdx +++ b/src/content/partials/durable-objects/api-storage-alarms.mdx @@ -11,7 +11,7 @@ import { Type, MetaInfo, Render } from "~/components"; #### Supported options -- Same options as [`get()`](/durable-objects/api/storage-api/#get), but without `noCache`. +- Same options as [`get()`](#get), but without `noCache`. ### `setAlarm` @@ -27,4 +27,4 @@ import { Type, MetaInfo, Render } from "~/components"; #### Supported options -- `setAlarm()` and `deleteAlarm()` support the same options as [`put()`](/durable-objects/api/storage-api/#put), but without `noCache`. \ No newline at end of file +- `setAlarm()` and `deleteAlarm()` support the same options as [`put()`](#put), but without `noCache`. \ No newline at end of file diff --git a/src/content/partials/durable-objects/api-storage-other-methods.mdx b/src/content/partials/durable-objects/api-storage-other-methods.mdx index 104295299cda294..e6c651dbe5ccbf1 100644 --- a/src/content/partials/durable-objects/api-storage-other-methods.mdx +++ b/src/content/partials/durable-objects/api-storage-other-methods.mdx @@ -19,7 +19,7 @@ import { Type, MetaInfo } from "~/components"; - Invokes `callback()` wrapped in a transaction, and returns its result. - If `callback()` throws an exception, the transaction will be rolled back. - * The callback must complete synchronously, that is, it should not be declared `async` nor otherwise return a Promise. Only synchronous storage operations can be part of the transaction. This is intended for use with SQL queries using [`ctx.storage.sql.exec()`](/durable-objects/api/storage-api/#exec), which complete sychronously. + * The callback must complete synchronously, that is, it should not be declared `async` nor otherwise return a Promise. Only synchronous storage operations can be part of the transaction. This is intended for use with SQL queries using [`ctx.storage.sql.exec()`](/durable-objects/api/sqlite-storage-api/#exec), which complete sychronously. ### `transaction` @@ -31,11 +31,11 @@ import { Type, MetaInfo } from "~/components"; - `txn` - Provides access to the `put()`, `get()`, `delete()` and `list()` methods documented above to run in the current transaction context. In order to get transactional behavior within a transaction closure, you must call the methods on the `txn` Object instead of on the top-level `ctx.storage` Object.

Also supports a `rollback()` function that ensures any changes made during the transaction will be rolled back rather than committed. After `rollback()` is called, any subsequent operations on the `txn` Object will fail with an exception. `rollback()` takes no parameters and returns nothing to the caller. - - When using [the SQLite-backed storage engine](/durable-objects/best-practices/access-durable-objects-storage/#sqlite-storage-backend), the `txn` object is obsolete. Any storage operations performed directly on the `ctx.storage` object, including SQL queries using [`ctx.storage.sql.exec()`](/durable-objects/api/storage-api/#exec), will be considered part of the transaction. + - When using [the SQLite-backed storage engine](/durable-objects/best-practices/access-durable-objects-storage/#sqlite-storage-backend), the `txn` object is obsolete. Any storage operations performed directly on the `ctx.storage` object, including SQL queries using [`ctx.storage.sql.exec()`](/durable-objects/api/sqlite-storage-api/#exec), will be considered part of the transaction. ### `sync` - `sync()`: - Synchronizes any pending writes to disk. - - This is similar to normal behavior from automatic write coalescing. If there are any pending writes in the write buffer (including those submitted with [the `allowUnconfirmed` option](/durable-objects/api/storage-api/#supported-options-1)), the returned promise will resolve when they complete. If there are no pending writes, the returned promise will be already resolved. \ No newline at end of file + - This is similar to normal behavior from automatic write coalescing. If there are any pending writes in the write buffer (including those submitted with [the `allowUnconfirmed` option](#supported-options-1)), the returned promise will resolve when they complete. If there are no pending writes, the returned promise will be already resolved. \ No newline at end of file diff --git a/src/content/partials/durable-objects/api-sync-kv.mdx b/src/content/partials/durable-objects/api-sync-kv.mdx index 1875c5e91ccc78f..954a4799b2ba6bf 100644 --- a/src/content/partials/durable-objects/api-sync-kv.mdx +++ b/src/content/partials/durable-objects/api-sync-kv.mdx @@ -55,7 +55,7 @@ import {Type, MetaInfo} from "~/components"; - After any write, subsequent network messages may be slightly delayed. Some applications may consider it acceptable to communicate on the basis of unconfirmed writes. Some programs may prefer to allow network traffic immediately. In this case, set `allowUnconfirmed` to `true` to opt out of the default behavior. - - If you want to allow some outgoing network messages to proceed immediately but not others, you can use the allowUnconfirmed option to avoid blocking the messages that you want to proceed and then separately call the [`sync()`](/durable-objects/api/storage-api/#sync) method, which returns a promise that only resolves once all previous writes have successfully been persisted to disk. + - If you want to allow some outgoing network messages to proceed immediately but not others, you can use the allowUnconfirmed option to avoid blocking the messages that you want to proceed and then separately call the [`sync()`](#sync) method, which returns a promise that only resolves once all previous writes have successfully been persisted to disk. - `noCache` - If true, then the key/value will be discarded from memory as soon as it has completed writing to disk. diff --git a/src/content/partials/durable-objects/do-faq-limits.mdx b/src/content/partials/durable-objects/do-faq-limits.mdx index b479e389765f2eb..6d59aa5f3f1b36f 100644 --- a/src/content/partials/durable-objects/do-faq-limits.mdx +++ b/src/content/partials/durable-objects/do-faq-limits.mdx @@ -9,7 +9,7 @@ import {GlossaryTooltip, WranglerConfig} from "~/components"; Durable Objects can scale horizontally across many Durable Objects. Each individual Object is inherently single-threaded. - An individual Object has a soft limit of 1,000 requests per second. You can have an unlimited number of individual objects per namespace. -- A simple [storage](/durable-objects/api/storage-api/) `get()` on a small value that directly returns the response may realize a higher request throughput compared to a Durable Object that (for example) serializes and/or deserializes large JSON values. +- A simple [storage](/durable-objects/api/sqlite-storage-api/) `get()` on a small value that directly returns the response may realize a higher request throughput compared to a Durable Object that (for example) serializes and/or deserializes large JSON values. - Similarly, a Durable Object that performs multiple `list()` operations may be more limited in terms of request throughput. A Durable Object that receives too many requests will, after attempting to queue them, return an [overloaded](/durable-objects/observability/troubleshooting/#durable-object-is-overloaded) error to the caller. diff --git a/src/content/partials/durable-objects/do-faq-pricing.mdx b/src/content/partials/durable-objects/do-faq-pricing.mdx index a3204638e7ffe40..8c58c599fe4365a 100644 --- a/src/content/partials/durable-objects/do-faq-pricing.mdx +++ b/src/content/partials/durable-objects/do-faq-pricing.mdx @@ -19,4 +19,4 @@ Yes, although minimal. Empty tables can consume at least a few kilobytes, based All writes to a SQLite-backed Durable Object stores nominal amounts of metadata in internal tables in the Durable Object, which counts towards your billable storage. -The metadata remains in the Durable Object until you call [`deleteAll()`](/durable-objects/api/storage-api/#deleteall). +The metadata remains in the Durable Object until you call [`deleteAll()`](/durable-objects/api/sqlite-storage-api/#deleteall). diff --git a/src/content/partials/durable-objects/durable-objects-pricing.mdx b/src/content/partials/durable-objects/durable-objects-pricing.mdx index 2e080b82a458736..d4231fb4e7656e6 100644 --- a/src/content/partials/durable-objects/durable-objects-pricing.mdx +++ b/src/content/partials/durable-objects/durable-objects-pricing.mdx @@ -41,7 +41,7 @@ await durableObjectStub.cat(); // billed as a request { props.product === "durable-objects" && <> } { props.product === "workers" && <> } -The [Durable Objects Storage API](/durable-objects/api/storage-api/) is only accessible from within Durable Objects. Pricing depends on the storage backend of your Durable Objects. +The [Durable Objects Storage API](/durable-objects/api/sqlite-storage-api/) is only accessible from within Durable Objects. Pricing depends on the storage backend of your Durable Objects. - **SQLite-backed Durable Objects (recommended)**: [SQLite storage backend](/durable-objects/best-practices/access-durable-objects-storage/#create-sqlite-backed-durable-object-class) is recommended for all new Durable Object classes. Workers Free plan can only create and access SQLite-backed Durable Objects. - **Key-value backed Durable Objects**: [Key-value storage backend](/durable-objects/reference/durable-objects-migrations/#create-durable-object-class-with-key-value-storage) is only available on the Workers Paid plan. @@ -93,6 +93,6 @@ The [Durable Objects Storage API](/durable-objects/api/storage-api/) is only acc 5 Durable Objects will be billed for stored data until the data is removed. Once the data is removed, the object will be cleaned up automatically by the system. -Requests that hit the [Durable Objects in-memory cache](/durable-objects/reference/in-memory-state/) or that use the [multi-key versions of `get()`/`put()`/`delete()` methods](/durable-objects/api/storage-api/) are billed the same as if they were a normal, individual request for each key. +Requests that hit the [Durable Objects in-memory cache](/durable-objects/reference/in-memory-state/) or that use the [multi-key versions of `get()`/`put()`/`delete()` methods](/durable-objects/api/sqlite-storage-api/) are billed the same as if they were a normal, individual request for each key. diff --git a/src/content/partials/durable-objects/durable-objects-sql.mdx b/src/content/partials/durable-objects/durable-objects-sql.mdx index 2e3290f457cbbba..43eb7777f652040 100644 --- a/src/content/partials/durable-objects/durable-objects-sql.mdx +++ b/src/content/partials/durable-objects/durable-objects-sql.mdx @@ -4,7 +4,7 @@ import { Details } from "~/components" -[SQL API](/durable-objects/api/storage-api/#exec) examples below use the following SQL schema: +[SQL API](/durable-objects/api/sqlite-storage-api/#exec) examples below use the following SQL schema: ```ts import { DurableObject } from "cloudflare:workers"; diff --git a/src/content/partials/durable-objects/recommend-sqlite-do.mdx b/src/content/partials/durable-objects/recommend-sqlite-do.mdx index 4532f0a67f499a6..cbd46407febdb4f 100644 --- a/src/content/partials/durable-objects/recommend-sqlite-do.mdx +++ b/src/content/partials/durable-objects/recommend-sqlite-do.mdx @@ -3,7 +3,7 @@ --- :::note[Recommended SQLite-backed Durable Objects] -Cloudflare recommends all new Durable Object namespaces use the [SQLite storage backend](/durable-objects/best-practices/access-durable-objects-storage/#create-sqlite-backed-durable-object-class). These Durable Objects can continue to use storage [key-value API](/durable-objects/api/storage-api/#kv-api). +Cloudflare recommends all new Durable Object namespaces use the [SQLite storage backend](/durable-objects/best-practices/access-durable-objects-storage/#create-sqlite-backed-durable-object-class). These Durable Objects can continue to use storage [key-value API](/durable-objects/api/sqlite-storage-api/#synchronous-kv-api). Additionally, SQLite-backed Durable Objects allow you to store more types of data (such as tables), and offers Point In Time Recovery API which can restore a Durable Object's embedded SQLite database contents (both SQL data and key-value data) to any point in the past 30 days. diff --git a/src/content/partials/durable-objects/storage-intro-text.mdx b/src/content/partials/durable-objects/storage-intro-text.mdx index 3f765465ab4fe75..416f345e67e9c57 100644 --- a/src/content/partials/durable-objects/storage-intro-text.mdx +++ b/src/content/partials/durable-objects/storage-intro-text.mdx @@ -2,10 +2,9 @@ {} --- -The Durable Object Storage API comes with several methods, including [SQL API](/durable-objects/api/storage-api/#sql-api), [point-in-time-recovery (PITR) API](/durable-objects/api/storage-api/#pitr-point-in-time-recovery-api), and [key-value (KV) API](/durable-objects/api/storage-api/#kv-api). +The Durable Object Storage API comes with several methods, including [SQL API](/durable-objects/api/sqlite-storage-api/#sql-api), [point-in-time-recovery (PITR) API](/durable-objects/api/sqlite-storage-api/#pitr-point-in-time-recovery-api), and [key-value (KV) API](/durable-objects/api/sqlite-storage-api/#synchronous-kv-api). - Durable Object classes with the recommended, [SQLite storage backend](/durable-objects/best-practices/access-durable-objects-storage/#sqlite-storage-backend) can use SQL API, PITR API, and KV API. KV API methods like `get()`, `put()`, `delete()`, or `list()` store data in a hidden SQLite table. -- Specifically for Durable Object classes with SQLite storage backend, KV operations which were previously asynchronous (for example, [`get`](/durable-objects/api/storage-api/#get), [`put`](/durable-objects/api/storage-api/#put), [`delete`](/durable-objects/api/storage-api/#delete), [`deleteAll`](/durable-objects/api/storage-api/#deleteall), [`list`](/durable-objects/api/storage-api/#list)) are synchronous, even though they return promises. These methods will have completed their operations before they return the promise. - Durable Objects gain access to a persistent KV Durable Object Storage API via the `DurableObjectStorage` interface and accessed by the `DurableObjectState::storage` property. This is frequently accessed via `this.ctx.storage` when the `ctx` parameter passed to the Durable Object constructor. - Durable Object classes with the key-value storage backend can only use KV API. diff --git a/src/content/release-notes/durable-objects.yaml b/src/content/release-notes/durable-objects.yaml index bcae9dce5e6bd90..894747838276863 100644 --- a/src/content/release-notes/durable-objects.yaml +++ b/src/content/release-notes/durable-objects.yaml @@ -15,7 +15,7 @@ entries: - publish_date: "2025-04-07" title: SQLite in Durable Objects GA description: |- - [SQLite-backed Durable Objects](/durable-objects/best-practices/access-durable-objects-storage/#create-sqlite-backed-durable-object-class) and corresponding [Storage API](/durable-objects/api/storage-api/) methods like `sql.exec` have moved from beta to general availability. New Durable Object classes should use wrangler configuration for SQLite storage over key-value storage. + [SQLite-backed Durable Objects](/durable-objects/best-practices/access-durable-objects-storage/#create-sqlite-backed-durable-object-class) and corresponding [Storage API](/durable-objects/api/sqlite-storage-api/) methods like `sql.exec` have moved from beta to general availability. New Durable Object classes should use wrangler configuration for SQLite storage over key-value storage. SQLite storage per Durable Object has increased to 10GB for all existing and new objects. @@ -40,7 +40,7 @@ entries: - publish_date: "2024-09-26" title: (Beta) SQLite storage backend & SQL API available on new Durable Object classes description: |- - The new beta version of Durable Objects is available where each Durable Object has a private, embedded SQLite database. When deploying a new Durable Object class, users can [opt-in to a SQLite storage backend](/durable-objects/best-practices/access-durable-objects-storage/#sqlite-storage-backend) in order to access new [SQL API](/durable-objects/api/storage-api/#sql-api) and [point-in-time-recovery API](/durable-objects/api/storage-api/#pitr-point-in-time-recovery-api), part of Durable Objects Storage API. + The new beta version of Durable Objects is available where each Durable Object has a private, embedded SQLite database. When deploying a new Durable Object class, users can [opt-in to a SQLite storage backend](/durable-objects/best-practices/access-durable-objects-storage/#sqlite-storage-backend) in order to access new [SQL API](/durable-objects/api/sqlite-storage-api/#sql-api) and [point-in-time-recovery API](/durable-objects/api/sqlite-storage-api/#pitr-point-in-time-recovery-api), part of Durable Objects Storage API. You cannot enable a SQLite storage backend on an existing, deployed Durable Object class. Automatic migration of deployed classes from their key-value storage backend to SQLite storage backend will be available in the future. From 44b281053192ae92660c01f32d7372c9effa967b Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Mon, 8 Sep 2025 09:13:53 +0100 Subject: [PATCH 03/12] Fixing broken links --- .../docs/durable-objects/api/legacy-kv-storage-api.mdx | 2 +- src/content/docs/durable-objects/api/sqlite-storage-api.mdx | 4 ++-- src/content/docs/durable-objects/api/state.mdx | 6 +++--- .../partials/durable-objects/api-storage-introduction.mdx | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/content/docs/durable-objects/api/legacy-kv-storage-api.mdx b/src/content/docs/durable-objects/api/legacy-kv-storage-api.mdx index 1f293274fa1ee2b..4c04bdd0c7e462a 100644 --- a/src/content/docs/durable-objects/api/legacy-kv-storage-api.mdx +++ b/src/content/docs/durable-objects/api/legacy-kv-storage-api.mdx @@ -10,7 +10,7 @@ import { Render, Type, MetaInfo, GlossaryTooltip, TypeScriptExample, Details } f :::note This page documents storage API for legacy KV-backed Durable Objects. -For the newer SQLite-backed Durable Object storage API, refer to [SQLite-backed Durable Object Storage](/durable-objects/api/sqlite-backed-storage). +For the newer SQLite-backed Durable Object storage API, refer to [SQLite-backed Durable Object Storage](/durable-objects/api/sqlite-storage-api). ::: diff --git a/src/content/docs/durable-objects/api/sqlite-storage-api.mdx b/src/content/docs/durable-objects/api/sqlite-storage-api.mdx index 44eba5d3674834e..b6f66c363a17821 100644 --- a/src/content/docs/durable-objects/api/sqlite-storage-api.mdx +++ b/src/content/docs/durable-objects/api/sqlite-storage-api.mdx @@ -10,7 +10,7 @@ import { Render, Type, MetaInfo, GlossaryTooltip, TypeScriptExample, Details } f :::note This page documents storage API for the newer SQLite-backed Durable Objects. -For the legacy KV-backed Durable Object storage API, see [KV-backed Durable Object Storage (Legacy)](/durable-objects/api/legacy-kv-backed-storage/). +For the legacy KV-backed Durable Object storage API, see [KV-backed Durable Object Storage (Legacy)](/durable-objects/api/legacy-kv-storage-api/). ::: @@ -201,7 +201,7 @@ ctx.storage.onNextSessionRestoreBookmark(bookmark); ### `sql` -`sql` is a readonly property of type `DurableObjectStorage` encapsulating the [SQL API](/durable-objects/api/sqlite-backed-storage/#sql-api). +`sql` is a readonly property of type `DurableObjectStorage` encapsulating the [SQL API](/durable-objects/api/sqlite-storage-api/#synchronous-sql-api). ## Related resources diff --git a/src/content/docs/durable-objects/api/state.mdx b/src/content/docs/durable-objects/api/state.mdx index cbc391cc122946c..b0bd392a99c7396 100644 --- a/src/content/docs/durable-objects/api/state.mdx +++ b/src/content/docs/durable-objects/api/state.mdx @@ -11,7 +11,7 @@ import { Tabs, TabItem, GlossaryTooltip, Type, MetaInfo } from "~/components"; The `DurableObjectState` interface is accessible as an instance property on the Durable Object class. This interface encapsulates methods that modify the state of a Durable Object, for example which WebSockets are attached to a Durable Object or how the runtime should handle concurrent Durable Object requests. -The `DurableObjectState` interface is different from the Storage API in that it does not have top-level methods which manipulate persistent application data. These methods are instead encapsulated in the [`DurableObjectStorage`](/durable-objects/api/storage-api) interface and accessed by [`DurableObjectState::storage`](/durable-objects/api/state/#storage). +The `DurableObjectState` interface is different from the Storage API in that it does not have top-level methods which manipulate persistent application data. These methods are instead encapsulated in the [`DurableObjectStorage`](/durable-objects/api/sqlite-storage-api) interface and accessed by [`DurableObjectState::storage`](/durable-objects/api/state/#storage). @@ -285,8 +285,8 @@ export class MyDurableObject extends DurableObject { ### `storage` -`storage` is a readonly property of type `DurableObjectStorage` encapsulating the [Storage API](/durable-objects/api/storage-api). +`storage` is a readonly property of type `DurableObjectStorage` encapsulating the [Storage API](/durable-objects/api/sqlite-storage-api/). ## Related resources -- [Durable Objects: Easy, Fast, Correct – Choose Three](https://blog.cloudflare.com/durable-objects-easy-fast-correct-choose-three/). +- [Durable Objects: Easy, Fast, Correct - Choose Three](https://blog.cloudflare.com/durable-objects-easy-fast-correct-choose-three/). diff --git a/src/content/partials/durable-objects/api-storage-introduction.mdx b/src/content/partials/durable-objects/api-storage-introduction.mdx index 52e05e8506a8b16..ff88f6844852e61 100644 --- a/src/content/partials/durable-objects/api-storage-introduction.mdx +++ b/src/content/partials/durable-objects/api-storage-introduction.mdx @@ -24,6 +24,6 @@ accessing multiple key-value pairs. 2 KV API methods like `get()`, `put()`, `delete()`, or `list()` store data in a hidden SQLite table. -3 For SQLite-backed Durable Objects, you can use [synchronous KV API methods](/durable-objects/api/sqlite-backed-storage/#synchronous-kv-api) using `ctx.storage.kv`. KV-backed Durable Objects use [asynchronous KV API methods](/durable-objects/api/legacy-kv-backed-storage/#asynchronous-kv-api). +3 For SQLite-backed Durable Objects, you can use [synchronous KV API methods](/durable-objects/api/sqlite-storage-api/#synchronous-kv-api) using `ctx.storage.kv`. KV-backed Durable Objects use [asynchronous KV API methods](/durable-objects/api/legacy-kv-storage-api/#asynchronous-kv-api). \ No newline at end of file From e4a3ba5f9daa906eee44e7bad39c074541b5f1d1 Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Thu, 11 Sep 2025 12:02:52 +0100 Subject: [PATCH 04/12] Apply suggestions from code review Co-authored-by: Lambros Petrou --- .../api/legacy-kv-storage-api.mdx | 4 +- .../api/sqlite-storage-api.mdx | 8 ++-- .../partials/durable-objects/api-sync-kv.mdx | 45 ++----------------- 3 files changed, 10 insertions(+), 47 deletions(-) diff --git a/src/content/docs/durable-objects/api/legacy-kv-storage-api.mdx b/src/content/docs/durable-objects/api/legacy-kv-storage-api.mdx index 4c04bdd0c7e462a..f9da90abb9e78d9 100644 --- a/src/content/docs/durable-objects/api/legacy-kv-storage-api.mdx +++ b/src/content/docs/durable-objects/api/legacy-kv-storage-api.mdx @@ -8,7 +8,7 @@ sidebar: import { Render, Type, MetaInfo, GlossaryTooltip, TypeScriptExample, Details } from "~/components"; :::note -This page documents storage API for legacy KV-backed Durable Objects. +This page documents the storage API for legacy KV-backed Durable Objects. For the newer SQLite-backed Durable Object storage API, refer to [SQLite-backed Durable Object Storage](/durable-objects/api/sqlite-storage-api). ::: @@ -46,7 +46,7 @@ JavaScript is a single-threaded and event-driven programming language. This mean ## Asynchronous KV API -KV-backed Durable Objects use KV API methods which are asynchronous. +KV-backed Durable Objects provide KV API methods which are asynchronous. diff --git a/src/content/docs/durable-objects/api/sqlite-storage-api.mdx b/src/content/docs/durable-objects/api/sqlite-storage-api.mdx index b6f66c363a17821..406309208f65b16 100644 --- a/src/content/docs/durable-objects/api/sqlite-storage-api.mdx +++ b/src/content/docs/durable-objects/api/sqlite-storage-api.mdx @@ -8,7 +8,7 @@ sidebar: import { Render, Type, MetaInfo, GlossaryTooltip, TypeScriptExample, Details } from "~/components"; :::note -This page documents storage API for the newer SQLite-backed Durable Objects. +This page documents the storage API for the newer SQLite-backed Durable Objects. For the legacy KV-backed Durable Object storage API, see [KV-backed Durable Object Storage (Legacy)](/durable-objects/api/legacy-kv-storage-api/). ::: @@ -50,7 +50,7 @@ JavaScript is a single-threaded and event-driven programming language. This mean The `SqlStorage` interface encapsulates methods that modify the SQLite database embedded within a Durable Object. The `SqlStorage` interface is accessible via the [`sql` property](/durable-objects/api/sqlite-storage-api/#sql) of `DurableObjectStorage` class. -For example, using `sql.exec()`, a user can create a table, then insert rows into the table. +For example, using `sql.exec()` a user can create a table and insert rows. ```ts import { DurableObject } from "cloudflare:workers"; @@ -75,8 +75,8 @@ export class MyDurableObject extends DurableObject { } ``` -- SQL API methods accessed with `ctx.storage.sql` are only allowed on [Durable Object classes with SQLite storage backend](/durable-objects/best-practices/access-durable-objects-storage/#create-sqlite-backed-durable-object-class) and will return an error if called on Durable Object classes with a key-value storage backend. -- When writing data, every index counts as an additional row. However, indexes may be beneficial for read-heavy use cases. Refer to [Index for SQLite Durable Objects](/durable-objects/best-practices/access-durable-objects-storage/#index-for-sqlite-durable-objects). +- SQL API methods accessed with `ctx.storage.sql` are only allowed on [Durable Object classes with SQLite storage backend](/durable-objects/best-practices/access-durable-objects-storage/#create-sqlite-backed-durable-object-class) and will return an error if called on Durable Object classes with a KV-storage backend. +- When writing data, every row update of an index counts as an additional row. However, indexes may be beneficial for read-heavy use cases. Refer to [Index for SQLite Durable Objects](/durable-objects/best-practices/access-durable-objects-storage/#index-for-sqlite-durable-objects). - Writing data to [SQLite virtual tables](https://www.sqlite.org/vtab.html) also counts towards rows written. diff --git a/src/content/partials/durable-objects/api-sync-kv.mdx b/src/content/partials/durable-objects/api-sync-kv.mdx index 954a4799b2ba6bf..c6d2f35928e9294 100644 --- a/src/content/partials/durable-objects/api-sync-kv.mdx +++ b/src/content/partials/durable-objects/api-sync-kv.mdx @@ -22,7 +22,7 @@ import {Type, MetaInfo} from "~/components"; ### `put` -- put(key , value , options ): +- put(key , value ): - Stores the value and associates it with the given key. The value can be any type supported by the [structured clone algorithm](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm), which is true of most types. The size of keys and values have different limits depending on the Durable Object storage backend you are using. Refer to either: @@ -38,47 +38,16 @@ import {Type, MetaInfo} from "~/components"; ### `delete` -- delete(key , options ): +- delete(key ): - Deletes the key and associated value. Returns `true` if the key existed or `false` if it did not. -- delete(keys , options ): - - Deletes the provided keys and their associated values. Supports up to 128 keys at a time. Returns a count of the number of key-value pairs deleted. -#### Supported options - -- `put()`, `delete()` and `deleteAll()` support the following options: - -- `allowUnconfirmed` - - By default, the system will pause outgoing network messages from the Durable Object until all previous writes have been confirmed flushed to disk. If the write fails, the system will reset the Object, discard all outgoing messages, and respond to any clients with errors instead. - - - This way, Durable Objects can continue executing in parallel with a write operation, without having to worry about prematurely confirming writes, because it is impossible for any external party to observe the Object's actions unless the write actually succeeds. - - - After any write, subsequent network messages may be slightly delayed. Some applications may consider it acceptable to communicate on the basis of unconfirmed writes. Some programs may prefer to allow network traffic immediately. In this case, set `allowUnconfirmed` to `true` to opt out of the default behavior. - - - If you want to allow some outgoing network messages to proceed immediately but not others, you can use the allowUnconfirmed option to avoid blocking the messages that you want to proceed and then separately call the [`sync()`](#sync) method, which returns a promise that only resolves once all previous writes have successfully been persisted to disk. - -- `noCache` - - If true, then the key/value will be discarded from memory as soon as it has completed writing to disk. - - - Use `noCache` if the key will not be used again in the near future. `noCache` will never change the semantics of your code, but it may affect performance. - - - If you use `get()` to retrieve the key before the write has completed, the copy from the write buffer will be returned, thus ensuring consistency with the latest call to `put()`. - -:::note[Automatic write coalescing] - -If you invoke `put()` (or `delete()`) multiple times without performing any `await` in the meantime, the operations will automatically be combined and submitted atomically. In case of a machine failure, either all of the writes will have been stored to disk or none of the writes will have been stored to disk. -::: - -:::note[Write buffer behavior] - -The `put()` method returns a `Promise`, but most applications can discard this promise without using `await`. The `Promise` usually completes immediately, because `put()` writes to an in-memory write buffer that is flushed to disk asynchronously. However, if an application performs a large number of `put()` without waiting for any I/O, the write buffer could theoretically grow large enough to cause the isolate to exceed its 128 MB memory limit. To avoid this scenario, such applications should use `await` on the `Promise` returned by `put()`. The system will then apply backpressure onto the application, slowing it down so that the write buffer has time to flush. Using `await` will disable automatic write coalescing. -::: ### `list` -- list(options ): +- list(options ): - Returns all keys and values associated with the current Durable Object in ascending sorted order based on the keys' UTF-8 encodings. - - The type of each returned value in the [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) will be whatever was previously written for the corresponding key. + - The type of each returned value in the [`Iterable`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterable_protocol) will be whatever was previously written for the corresponding key. - Be aware of how much data may be stored in your Durable Object before calling this version of `list` without options because all the data will be loaded into the Durable Object's memory, potentially hitting its [limit](/durable-objects/platform/limits/). If that is a concern, pass options to `list` as documented below. @@ -102,9 +71,3 @@ The `put()` method returns a `Promise`, but most applications can discard this p - `limit` - Maximum number of key-value pairs to return. - -- `allowConcurrency` - - Same as the option to `get()`, above. - -- `noCache` - - Same as the option to `get()`, above. \ No newline at end of file From 48e79c00cfe20f56fecdc03371559a9d5023aa2f Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Thu, 11 Sep 2025 15:15:56 +0100 Subject: [PATCH 05/12] Implementing feedback --- .../api/legacy-kv-storage-api.mdx | 22 ++++++------- .../api-storage-introduction.mdx | 8 ++--- .../partials/durable-objects/api-sync-kv.mdx | 31 +++---------------- 3 files changed, 19 insertions(+), 42 deletions(-) diff --git a/src/content/docs/durable-objects/api/legacy-kv-storage-api.mdx b/src/content/docs/durable-objects/api/legacy-kv-storage-api.mdx index f9da90abb9e78d9..dc65312e32b12d9 100644 --- a/src/content/docs/durable-objects/api/legacy-kv-storage-api.mdx +++ b/src/content/docs/durable-objects/api/legacy-kv-storage-api.mdx @@ -26,19 +26,17 @@ The following code snippet shows you how to store and retrieve data using the Du ```ts export class Counter extends DurableObject { - constructor(ctx: DurableObjectState, env: Env) { - super(ctx, env); - } - - async increment(): Promise { - let value: number = (await this.ctx.storage.get('value')) || 0; - value += 1; - await this.ctx.storage.put('value', value); - return value; - } - + constructor(ctx: DurableObjectState, env: Env) { + super(ctx, env); + } + + async increment(): Promise { + let value: number = (await this.ctx.storage.get("value")) || 0; + value += 1; + await this.ctx.storage.put("value", value); + return value; + } } - ``` diff --git a/src/content/partials/durable-objects/api-storage-introduction.mdx b/src/content/partials/durable-objects/api-storage-introduction.mdx index ff88f6844852e61..5470b0ae4023e71 100644 --- a/src/content/partials/durable-objects/api-storage-introduction.mdx +++ b/src/content/partials/durable-objects/api-storage-introduction.mdx @@ -12,7 +12,8 @@ The Durable Object Storage API comes with several methods, including SQL, point- | -------------------- | ---------------------------------- | ------------------------------ | | SQL API | ✅ | ❌ | | PITR API | ✅ | ❌ | -| KV API | ✅ 2, 3 | ✅ | +| SynchronousKV API | ✅ 2, 3 | ❌ | +| AsynchronousKV API | ✅ 3 | ✅ | | Alarms API | ✅ | ✅ |
@@ -22,8 +23,7 @@ its results are atomic and isolated from all other storage operations, even when accessing multiple key-value pairs. 2 KV API methods like `get()`, `put()`, `delete()`, or `list()` store -data in a hidden SQLite table. - -3 For SQLite-backed Durable Objects, you can use [synchronous KV API methods](/durable-objects/api/sqlite-storage-api/#synchronous-kv-api) using `ctx.storage.kv`. KV-backed Durable Objects use [asynchronous KV API methods](/durable-objects/api/legacy-kv-storage-api/#asynchronous-kv-api). +data in a hidden SQLite table `__cf_kv`. Note that you will be able view this table when listing all tables, you will not be able to query it. +3 SQLite-backed Durable Objects also use [synchronous KV API methods](/durable-objects/api/sqlite-storage-api/#synchronous-kv-api) using `ctx.storage.kv`, whereas KV-backed Durable Objects only provide [asynchronous KV API methods](/durable-objects/api/legacy-kv-storage-api/#asynchronous-kv-api).
\ No newline at end of file diff --git a/src/content/partials/durable-objects/api-sync-kv.mdx b/src/content/partials/durable-objects/api-sync-kv.mdx index c6d2f35928e9294..f10872fa606fe2a 100644 --- a/src/content/partials/durable-objects/api-sync-kv.mdx +++ b/src/content/partials/durable-objects/api-sync-kv.mdx @@ -6,46 +6,25 @@ import {Type, MetaInfo} from "~/components"; ### `get` -- ctx.storage.get(key , options {" "}): +- ctx.storage.kv.get(key , options {" "}): - Retrieves the value associated with the given key. The type of the returned value will be whatever was previously written for the key, or undefined if the key does not exist. -- ctx.storage.get(keys , options ): - - Retrieves the values associated with each of the provided keys. The type of each returned value in the [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) will be whatever was previously written for the corresponding key. Results in the `Map` will be sorted in increasing order of their UTF-8 encodings, with any requested keys that do not exist being omitted. Supports up to 128 keys at a time. - -#### Supported options - -- `allowConcurrency`: - - By default, the system will pause delivery of I/O events to the Object while a storage operation is in progress, in order to avoid unexpected race conditions. Pass `allowConcurrency: true` to opt out of this behavior and allow concurrent events to be delivered. - -- `noCache`: - - If true, then the key/value will not be inserted into the in-memory cache. If the key is already in the cache, the cached value will be returned, but its last-used time will not be updated. Use this when you expect this key will not be used again in the near future. This flag is only a hint. This flag will never change the semantics of your code, but it may affect performance. - ### `put` -- put(key , value ): +- ctx.storage.kv.put(key , value ): - Stores the value and associates it with the given key. The value can be any type supported by the [structured clone algorithm](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm), which is true of most types. The size of keys and values have different limits depending on the Durable Object storage backend you are using. Refer to either: - - [SQLite-backed Durable Object limits](/durable-objects/platform/limits/#sqlite-backed-durable-objects-general-limits) - - [KV-backed Durable Object limits](/durable-objects/platform/limits/#key-value-backed-durable-objects-general-limits).

- -- put(entries , options ): - - Takes an Object and stores each of its keys and values to storage. - - Each value can be any type supported by the [structured clone algorithm](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm), which is true of most types. - - Supports up to 128 key-value pairs at a time. The size of keys and values have different limits depending on the flavor of Durable Object you are using. Refer to either: - - [SQLite-backed Durable Object limits](/durable-objects/platform/limits/#sqlite-backed-durable-objects-general-limits) - - [KV-backed Durable Object limits](/durable-objects/platform/limits/#key-value-backed-durable-objects-general-limits) + - [SQLite-backed Durable Object limits](/durable-objects/platform/limits/#sqlite-backed-durable-objects-general-limits)

### `delete` -- delete(key ): +- ctx.storage.kv.delete(key ): - Deletes the key and associated value. Returns `true` if the key existed or `false` if it did not. - - ### `list` -- list(options ): +- ctx.storage.kv.list(options ): - Returns all keys and values associated with the current Durable Object in ascending sorted order based on the keys' UTF-8 encodings. - The type of each returned value in the [`Iterable`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterable_protocol) will be whatever was previously written for the corresponding key. From 9b9a99165370f829da9fe8f17357aaced60f14ad Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Thu, 11 Sep 2025 16:40:10 +0100 Subject: [PATCH 06/12] Apply suggestions from code review Co-authored-by: Lambros Petrou --- .../partials/durable-objects/api-storage-introduction.mdx | 2 +- src/content/partials/durable-objects/api-sync-kv.mdx | 2 +- src/content/partials/durable-objects/recommend-sqlite-do.mdx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/content/partials/durable-objects/api-storage-introduction.mdx b/src/content/partials/durable-objects/api-storage-introduction.mdx index 5470b0ae4023e71..38cbe3422636483 100644 --- a/src/content/partials/durable-objects/api-storage-introduction.mdx +++ b/src/content/partials/durable-objects/api-storage-introduction.mdx @@ -23,7 +23,7 @@ its results are atomic and isolated from all other storage operations, even when accessing multiple key-value pairs. 2 KV API methods like `get()`, `put()`, `delete()`, or `list()` store -data in a hidden SQLite table `__cf_kv`. Note that you will be able view this table when listing all tables, you will not be able to query it. +data in a hidden SQLite table `__cf_kv`. Note that you will be able to view this table when listing all tables, but you will not be able to access it. 3 SQLite-backed Durable Objects also use [synchronous KV API methods](/durable-objects/api/sqlite-storage-api/#synchronous-kv-api) using `ctx.storage.kv`, whereas KV-backed Durable Objects only provide [asynchronous KV API methods](/durable-objects/api/legacy-kv-storage-api/#asynchronous-kv-api). \ No newline at end of file diff --git a/src/content/partials/durable-objects/api-sync-kv.mdx b/src/content/partials/durable-objects/api-sync-kv.mdx index f10872fa606fe2a..aee8e87744cbe7b 100644 --- a/src/content/partials/durable-objects/api-sync-kv.mdx +++ b/src/content/partials/durable-objects/api-sync-kv.mdx @@ -6,7 +6,7 @@ import {Type, MetaInfo} from "~/components"; ### `get` -- ctx.storage.kv.get(key , options {" "}): +- ctx.storage.kv.get(key ): - Retrieves the value associated with the given key. The type of the returned value will be whatever was previously written for the key, or undefined if the key does not exist. ### `put` diff --git a/src/content/partials/durable-objects/recommend-sqlite-do.mdx b/src/content/partials/durable-objects/recommend-sqlite-do.mdx index cbd46407febdb4f..dea8504982d30c4 100644 --- a/src/content/partials/durable-objects/recommend-sqlite-do.mdx +++ b/src/content/partials/durable-objects/recommend-sqlite-do.mdx @@ -5,7 +5,7 @@ :::note[Recommended SQLite-backed Durable Objects] Cloudflare recommends all new Durable Object namespaces use the [SQLite storage backend](/durable-objects/best-practices/access-durable-objects-storage/#create-sqlite-backed-durable-object-class). These Durable Objects can continue to use storage [key-value API](/durable-objects/api/sqlite-storage-api/#synchronous-kv-api). -Additionally, SQLite-backed Durable Objects allow you to store more types of data (such as tables), and offers Point In Time Recovery API which can restore a Durable Object's embedded SQLite database contents (both SQL data and key-value data) to any point in the past 30 days. +Additionally, SQLite-backed Durable Objects allow you to store more types of data (such as tables), and offer Point In Time Recovery API which can restore a Durable Object's embedded SQLite database contents (both SQL data and key-value data) to any point in the past 30 days. The [key-value storage backend](/durable-objects/reference/durable-objects-migrations/#create-durable-object-class-with-key-value-storage) remains for backwards compatibility, and a migration path from KV storage backend to SQLite storage backend for existing Durable Object namespaces will be available in the future. ::: \ No newline at end of file From 78733c170970f7c1bd0242decae259768e512d54 Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Thu, 11 Sep 2025 17:23:05 +0100 Subject: [PATCH 07/12] Apply suggestions from code review Co-authored-by: Pedro Sousa <680496+pedrosousa@users.noreply.github.com> --- public/__redirects | 2 +- src/content/docs/durable-objects/api/sqlite-storage-api.mdx | 2 +- src/content/docs/durable-objects/api/state.mdx | 2 +- .../partials/durable-objects/api-storage-other-methods.mdx | 5 +++-- src/content/partials/durable-objects/api-sync-kv.mdx | 2 +- src/content/partials/durable-objects/storage-intro-text.mdx | 2 +- 6 files changed, 8 insertions(+), 7 deletions(-) diff --git a/public/__redirects b/public/__redirects index 38bc3d6b46ee729..dd8abf9b209b3ae 100644 --- a/public/__redirects +++ b/public/__redirects @@ -549,7 +549,7 @@ /durable-objects/get-started/video-series/ /durable-objects/video-tutorials/ 301 /durable-objects/what-are-durable-objects/ /durable-objects/concepts/what-are-durable-objects/ 301 -/durable-objects/api/storage-api /durable-objects/api/sqlite-storage-api/ 301 +/durable-objects/api/storage-api/ /durable-objects/api/sqlite-storage-api/ 301 # email-routing /email-routing/enable-email-routing/ /email-routing/get-started/enable-email-routing/ 301 diff --git a/src/content/docs/durable-objects/api/sqlite-storage-api.mdx b/src/content/docs/durable-objects/api/sqlite-storage-api.mdx index 406309208f65b16..db5b7b6529a5eb6 100644 --- a/src/content/docs/durable-objects/api/sqlite-storage-api.mdx +++ b/src/content/docs/durable-objects/api/sqlite-storage-api.mdx @@ -10,7 +10,7 @@ import { Render, Type, MetaInfo, GlossaryTooltip, TypeScriptExample, Details } f :::note This page documents the storage API for the newer SQLite-backed Durable Objects. -For the legacy KV-backed Durable Object storage API, see [KV-backed Durable Object Storage (Legacy)](/durable-objects/api/legacy-kv-storage-api/). +For the legacy KV-backed Durable Object storage API, refer to [KV-backed Durable Object Storage (Legacy)](/durable-objects/api/legacy-kv-storage-api/). ::: diff --git a/src/content/docs/durable-objects/api/state.mdx b/src/content/docs/durable-objects/api/state.mdx index b0bd392a99c7396..bb2f6222e78e99f 100644 --- a/src/content/docs/durable-objects/api/state.mdx +++ b/src/content/docs/durable-objects/api/state.mdx @@ -11,7 +11,7 @@ import { Tabs, TabItem, GlossaryTooltip, Type, MetaInfo } from "~/components"; The `DurableObjectState` interface is accessible as an instance property on the Durable Object class. This interface encapsulates methods that modify the state of a Durable Object, for example which WebSockets are attached to a Durable Object or how the runtime should handle concurrent Durable Object requests. -The `DurableObjectState` interface is different from the Storage API in that it does not have top-level methods which manipulate persistent application data. These methods are instead encapsulated in the [`DurableObjectStorage`](/durable-objects/api/sqlite-storage-api) interface and accessed by [`DurableObjectState::storage`](/durable-objects/api/state/#storage). +The `DurableObjectState` interface is different from the Storage API in that it does not have top-level methods which manipulate persistent application data. These methods are instead encapsulated in the [`DurableObjectStorage`](/durable-objects/api/sqlite-storage-api/) interface and accessed by [`DurableObjectState::storage`](/durable-objects/api/state/#storage). diff --git a/src/content/partials/durable-objects/api-storage-other-methods.mdx b/src/content/partials/durable-objects/api-storage-other-methods.mdx index e6c651dbe5ccbf1..035241a0c600381 100644 --- a/src/content/partials/durable-objects/api-storage-other-methods.mdx +++ b/src/content/partials/durable-objects/api-storage-other-methods.mdx @@ -19,7 +19,8 @@ import { Type, MetaInfo } from "~/components"; - Invokes `callback()` wrapped in a transaction, and returns its result. - If `callback()` throws an exception, the transaction will be rolled back. - * The callback must complete synchronously, that is, it should not be declared `async` nor otherwise return a Promise. Only synchronous storage operations can be part of the transaction. This is intended for use with SQL queries using [`ctx.storage.sql.exec()`](/durable-objects/api/sqlite-storage-api/#exec), which complete sychronously. + + - The callback must complete synchronously, that is, it should not be declared `async` nor otherwise return a Promise. Only synchronous storage operations can be part of the transaction. This is intended for use with SQL queries using [`ctx.storage.sql.exec()`](/durable-objects/api/sqlite-storage-api/#exec), which complete sychronously. ### `transaction` @@ -29,7 +30,7 @@ import { Type, MetaInfo } from "~/components"; - Explicit transactions are no longer necessary. Any series of write operations with no intervening `await` will automatically be submitted atomically, and the system will prevent concurrent events from executing while `await` a read operation (unless you use `allowConcurrency: true`). Therefore, a series of reads followed by a series of writes (with no other intervening I/O) are automatically atomic and behave like a transaction. - `txn` - - Provides access to the `put()`, `get()`, `delete()` and `list()` methods documented above to run in the current transaction context. In order to get transactional behavior within a transaction closure, you must call the methods on the `txn` Object instead of on the top-level `ctx.storage` Object.

Also supports a `rollback()` function that ensures any changes made during the transaction will be rolled back rather than committed. After `rollback()` is called, any subsequent operations on the `txn` Object will fail with an exception. `rollback()` takes no parameters and returns nothing to the caller. + - Provides access to the `put()`, `get()`, `delete()`, and `list()` methods documented above to run in the current transaction context. In order to get transactional behavior within a transaction closure, you must call the methods on the `txn` Object instead of on the top-level `ctx.storage` Object.

Also supports a `rollback()` function that ensures any changes made during the transaction will be rolled back rather than committed. After `rollback()` is called, any subsequent operations on the `txn` Object will fail with an exception. `rollback()` takes no parameters and returns nothing to the caller. - When using [the SQLite-backed storage engine](/durable-objects/best-practices/access-durable-objects-storage/#sqlite-storage-backend), the `txn` object is obsolete. Any storage operations performed directly on the `ctx.storage` object, including SQL queries using [`ctx.storage.sql.exec()`](/durable-objects/api/sqlite-storage-api/#exec), will be considered part of the transaction. diff --git a/src/content/partials/durable-objects/api-sync-kv.mdx b/src/content/partials/durable-objects/api-sync-kv.mdx index aee8e87744cbe7b..694547a4ac0d020 100644 --- a/src/content/partials/durable-objects/api-sync-kv.mdx +++ b/src/content/partials/durable-objects/api-sync-kv.mdx @@ -14,7 +14,7 @@ import {Type, MetaInfo} from "~/components"; - ctx.storage.kv.put(key , value ): - Stores the value and associates it with the given key. The value can be any type supported by the [structured clone algorithm](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm), which is true of most types. - The size of keys and values have different limits depending on the Durable Object storage backend you are using. Refer to either: + The size of keys and values have different limits depending on the Durable Object storage backend you are using. Refer to: - [SQLite-backed Durable Object limits](/durable-objects/platform/limits/#sqlite-backed-durable-objects-general-limits)

### `delete` diff --git a/src/content/partials/durable-objects/storage-intro-text.mdx b/src/content/partials/durable-objects/storage-intro-text.mdx index 416f345e67e9c57..cfe9c89ac4bed04 100644 --- a/src/content/partials/durable-objects/storage-intro-text.mdx +++ b/src/content/partials/durable-objects/storage-intro-text.mdx @@ -4,7 +4,7 @@ The Durable Object Storage API comes with several methods, including [SQL API](/durable-objects/api/sqlite-storage-api/#sql-api), [point-in-time-recovery (PITR) API](/durable-objects/api/sqlite-storage-api/#pitr-point-in-time-recovery-api), and [key-value (KV) API](/durable-objects/api/sqlite-storage-api/#synchronous-kv-api). -- Durable Object classes with the recommended, [SQLite storage backend](/durable-objects/best-practices/access-durable-objects-storage/#sqlite-storage-backend) can use SQL API, PITR API, and KV API. KV API methods like `get()`, `put()`, `delete()`, or `list()` store data in a hidden SQLite table. +- Durable Object classes with the recommended [SQLite storage backend](/durable-objects/best-practices/access-durable-objects-storage/#sqlite-storage-backend) can use SQL API, PITR API, and KV API. KV API methods like `get()`, `put()`, `delete()`, or `list()` store data in a hidden SQLite table. - Durable Objects gain access to a persistent KV Durable Object Storage API via the `DurableObjectStorage` interface and accessed by the `DurableObjectState::storage` property. This is frequently accessed via `this.ctx.storage` when the `ctx` parameter passed to the Durable Object constructor. - Durable Object classes with the key-value storage backend can only use KV API. From 984bde8ddfdecdffd8c46fd7709cc7c9bd6f9958 Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Thu, 11 Sep 2025 17:32:44 +0100 Subject: [PATCH 08/12] Using spaces instead of tabs --- .../durable-objects/api/sqlite-storage-api.mdx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/content/docs/durable-objects/api/sqlite-storage-api.mdx b/src/content/docs/durable-objects/api/sqlite-storage-api.mdx index db5b7b6529a5eb6..a6380c84a045da3 100644 --- a/src/content/docs/durable-objects/api/sqlite-storage-api.mdx +++ b/src/content/docs/durable-objects/api/sqlite-storage-api.mdx @@ -28,15 +28,15 @@ The following code snippet shows you how to store and retrieve data using the Du ```ts export class Counter extends DurableObject { - constructor(ctx: DurableObjectState, env: Env) { - super(ctx, env); - } + constructor(ctx: DurableObjectState, env: Env) { + super(ctx, env); + } async increment(): Promise { - let value: number = (await this.ctx.storage.get('value')) || 0; - value += 1; - await this.ctx.storage.put('value', value); - return value; + let value: number = (await this.ctx.storage.get('value')) || 0; + value += 1; + await this.ctx.storage.put('value', value); + return value; } } @@ -114,9 +114,9 @@ let cursor = this.sql.exec("SELECT * FROM artist ORDER BY artistname ASC;"); let rawResult = cursor.raw().next(); if (!rawResult.done) { - console.log(rawResult.value); // prints [ 123, 'Alice' ] + console.log(rawResult.value); // prints [ 123, 'Alice' ] } else { - // query returned zero results + // query returned zero results } console.log(cursor.toArray()); // prints [{ artistid: 456, artistname: 'Bob' },{ artistid: 789, artistname: 'Charlie' }] From 44565d9a77b0c506f5c9850c3701a737ce0b1e87 Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Thu, 11 Sep 2025 17:42:03 +0100 Subject: [PATCH 09/12] Using anchorheadings and self-referencing links in partial --- .../durable-objects/api-async-kv-legacy.mdx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/content/partials/durable-objects/api-async-kv-legacy.mdx b/src/content/partials/durable-objects/api-async-kv-legacy.mdx index 954a4799b2ba6bf..1ef05ec94c61a03 100644 --- a/src/content/partials/durable-objects/api-async-kv-legacy.mdx +++ b/src/content/partials/durable-objects/api-async-kv-legacy.mdx @@ -2,9 +2,9 @@ {} --- -import {Type, MetaInfo} from "~/components"; +import {Type, MetaInfo, AnchorHeading} from "~/components"; -### `get` + - ctx.storage.get(key , options {" "}): - Retrieves the value associated with the given key. The type of the returned value will be whatever was previously written for the key, or undefined if the key does not exist. @@ -20,7 +20,7 @@ import {Type, MetaInfo} from "~/components"; - `noCache`: - If true, then the key/value will not be inserted into the in-memory cache. If the key is already in the cache, the cached value will be returned, but its last-used time will not be updated. Use this when you expect this key will not be used again in the near future. This flag is only a hint. This flag will never change the semantics of your code, but it may affect performance. -### `put` + - put(key , value , options ): - Stores the value and associates it with the given key. The value can be any type supported by the [structured clone algorithm](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm), which is true of most types. @@ -36,7 +36,7 @@ import {Type, MetaInfo} from "~/components"; - [SQLite-backed Durable Object limits](/durable-objects/platform/limits/#sqlite-backed-durable-objects-general-limits) - [KV-backed Durable Object limits](/durable-objects/platform/limits/#key-value-backed-durable-objects-general-limits) -### `delete` + - delete(key , options ): - Deletes the key and associated value. Returns `true` if the key existed or `false` if it did not. @@ -74,7 +74,7 @@ If you invoke `put()` (or `delete()`) multiple times without performing any `awa The `put()` method returns a `Promise`, but most applications can discard this promise without using `await`. The `Promise` usually completes immediately, because `put()` writes to an in-memory write buffer that is flushed to disk asynchronously. However, if an application performs a large number of `put()` without waiting for any I/O, the write buffer could theoretically grow large enough to cause the isolate to exceed its 128 MB memory limit. To avoid this scenario, such applications should use `await` on the `Promise` returned by `put()`. The system will then apply backpressure onto the application, slowing it down so that the write buffer has time to flush. Using `await` will disable automatic write coalescing. ::: -### `list` + - list(options ): - Returns all keys and values associated with the current Durable Object in ascending sorted order based on the keys' UTF-8 encodings. @@ -104,7 +104,7 @@ The `put()` method returns a `Promise`, but most applications can discard this p - Maximum number of key-value pairs to return. - `allowConcurrency` - - Same as the option to `get()`, above. + - Same as the option to [`get()`](#do-kv-async-get), above. - `noCache` - - Same as the option to `get()`, above. \ No newline at end of file + - Same as the option to [`get()`](#do-kv-async-get), above. \ No newline at end of file From d66204fe481973148d7c63e7fc8639713ac75499 Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Wed, 17 Sep 2025 12:03:37 +0100 Subject: [PATCH 10/12] Update src/content/partials/durable-objects/api-sync-kv.mdx Co-authored-by: Lambros Petrou --- src/content/partials/durable-objects/api-sync-kv.mdx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/content/partials/durable-objects/api-sync-kv.mdx b/src/content/partials/durable-objects/api-sync-kv.mdx index 694547a4ac0d020..816f231f927d279 100644 --- a/src/content/partials/durable-objects/api-sync-kv.mdx +++ b/src/content/partials/durable-objects/api-sync-kv.mdx @@ -14,8 +14,7 @@ import {Type, MetaInfo} from "~/components"; - ctx.storage.kv.put(key , value ): - Stores the value and associates it with the given key. The value can be any type supported by the [structured clone algorithm](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm), which is true of most types. - The size of keys and values have different limits depending on the Durable Object storage backend you are using. Refer to: - - [SQLite-backed Durable Object limits](/durable-objects/platform/limits/#sqlite-backed-durable-objects-general-limits)

+ For the size of keys and values refer to [SQLite-backed Durable Object limits](/durable-objects/platform/limits/#sqlite-backed-durable-objects-general-limits) ### `delete` From bee1e0bf6b04c1ec9a39614e7bf945aacb9810e7 Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Wed, 17 Sep 2025 12:03:53 +0100 Subject: [PATCH 11/12] Update src/content/partials/durable-objects/api-storage-introduction.mdx Co-authored-by: Lambros Petrou --- .../partials/durable-objects/api-storage-introduction.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/content/partials/durable-objects/api-storage-introduction.mdx b/src/content/partials/durable-objects/api-storage-introduction.mdx index 38cbe3422636483..d0f3f977811809b 100644 --- a/src/content/partials/durable-objects/api-storage-introduction.mdx +++ b/src/content/partials/durable-objects/api-storage-introduction.mdx @@ -12,8 +12,8 @@ The Durable Object Storage API comes with several methods, including SQL, point- | -------------------- | ---------------------------------- | ------------------------------ | | SQL API | ✅ | ❌ | | PITR API | ✅ | ❌ | -| SynchronousKV API | ✅ 2, 3 | ❌ | -| AsynchronousKV API | ✅ 3 | ✅ | +| Synchronous KV API | ✅ 2, 3 | ❌ | +| Asynchronous KV API | ✅ 3 | ✅ | | Alarms API | ✅ | ✅ |
From 5245cd2ef3a1780d94c7ba53749bbddbadfa0a94 Mon Sep 17 00:00:00 2001 From: Jun Lee Date: Wed, 17 Sep 2025 12:04:00 +0100 Subject: [PATCH 12/12] Update src/content/partials/durable-objects/api-storage-introduction.mdx Co-authored-by: Lambros Petrou --- .../partials/durable-objects/api-storage-introduction.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/partials/durable-objects/api-storage-introduction.mdx b/src/content/partials/durable-objects/api-storage-introduction.mdx index d0f3f977811809b..af12a2cd081fc01 100644 --- a/src/content/partials/durable-objects/api-storage-introduction.mdx +++ b/src/content/partials/durable-objects/api-storage-introduction.mdx @@ -23,7 +23,7 @@ its results are atomic and isolated from all other storage operations, even when accessing multiple key-value pairs. 2 KV API methods like `get()`, `put()`, `delete()`, or `list()` store -data in a hidden SQLite table `__cf_kv`. Note that you will be able to view this table when listing all tables, but you will not be able to access it. +data in a hidden SQLite table `__cf_kv`. Note that you will be able to view this table when listing all tables, but you will not be able to access its content through the SQL API. 3 SQLite-backed Durable Objects also use [synchronous KV API methods](/durable-objects/api/sqlite-storage-api/#synchronous-kv-api) using `ctx.storage.kv`, whereas KV-backed Durable Objects only provide [asynchronous KV API methods](/durable-objects/api/legacy-kv-storage-api/#asynchronous-kv-api).
\ No newline at end of file