You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/content/docs/durable-objects/api/storage-api.mdx
+58-99Lines changed: 58 additions & 99 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,5 +1,5 @@
1
1
---
2
-
title: Durable Object storage
2
+
title: Durable Object Storage
3
3
pcx_content_type: concept
4
4
sidebar:
5
5
order: 6
@@ -15,7 +15,34 @@ import {
15
15
16
16
The Durable Object Storage API allows <GlossaryTooltipterm="Durable Object">Durable Objects</GlossaryTooltip> 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.
17
17
18
-
<Renderfile="storage-intro-text"/>
18
+
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).
We recommend all new Durable Object classes use the [SQLite storage backend](/durable-objects/best-practices/access-durable-objects-storage/#create-sqlite-backed-durable-object-class).
22
+
23
+
The KV storage backend remains for backwards compatibility, and a migration path from KV storage to SQLite storage for existing Durable Object classes will be available in the future.
24
+
:::
25
+
26
+
<Renderfile="do-sqlite-storage-no-bill-note"/>
27
+
28
+
| Methods <sup>1</sup> | SQLite-backed Durable Object class | KV-backed Durable Object class |
<sup>1</sup> 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.
38
+
39
+
<sup>2</sup> KV API methods like `get()`, `put()`, `delete()`, or `list()` store data in a hidden SQLite table.
40
+
41
+
<sup>3</sup> 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.
42
+
43
+
## Access Storage
44
+
45
+
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.
19
46
20
47
The following code snippet shows you how to store and retrieve data using the Durable Object Storage API.
21
48
@@ -34,25 +61,13 @@ export class Counter extends DurableObject {
34
61
}
35
62
36
63
}
37
-
38
64
```
39
65
</TypeScriptExample>
40
66
41
-
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 <GlossaryTooltipterm="input gate">input gates</GlossaryTooltip> and <GlossaryTooltipterm="output gate">output gates</GlossaryTooltip> to avoid this type of concurrency bug when performing storage operations.
42
-
43
-
:::note[Scope of Durable Object storage]
44
-
Note that Durable Object storage is scoped by individual <GlossaryTooltipterm="Durable Object">Durable Objects</GlossaryTooltip>.
45
-
46
-
- An account can have many Durable Object <GlossaryTooltipterm="namespace">namespaces</GlossaryTooltip>.
47
-
- A namespace can have many Durable Objects.
48
-
49
-
However, storage is scoped per individual Durable Object.
50
-
:::
67
+
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 <GlossaryTooltipterm="input gate">input gates</GlossaryTooltip> and <GlossaryTooltipterm="output gate">output gates</GlossaryTooltip> to avoid this type of concurrency bug when performing storage operations. Learn more with our [blog post](https://blog.cloudflare.com/durable-objects-easy-fast-correct-choose-three/)
51
68
52
69
## SQL API
53
70
54
-
<Renderfile="do-sqlite-storage-no-bill-note"/>
55
-
56
71
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/#) of `DurableObjectStorage` class.
57
72
58
73
For example, using `sql.exec()`, a user can create a table, then insert rows into the table.
@@ -78,15 +93,9 @@ export class MyDurableObject extends DurableObject {
78
93
}
79
94
```
80
95
81
-
:::note[SQLite in Durable Objects]
82
-
SQL API methods accessed with `ctx.storage.sql` are only allowed on [Durable Object classes with SQLite storage backend](/durable-objects/reference/durable-objects-migrations/#enable-sqlite-storage-backend-on-new-durable-object-class-migration) and will return an error if called on Durable Object classes with a key-value storage backend.
83
-
:::
84
-
85
-
:::note[Writing to indexes or virtual tables]
86
-
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).
87
-
88
-
Writing data to [SQLite virtual tables](https://www.sqlite.org/vtab.html) also counts towards rows written.
89
-
:::
96
+
* 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.
97
+
* 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).
98
+
* Writing data to [SQLite virtual tables](https://www.sqlite.org/vtab.html) also counts towards rows written.
* 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).
140
149
150
+
:::note[SQL transactions]
141
151
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.
152
+
:::
142
153
143
154
#### Examples
144
155
@@ -160,7 +171,7 @@ let size = ctx.storage.sql.databaseSize;
160
171
161
172
-`transactionSync(callback)`: <Typetext='any' />
162
173
163
-
- Only available when using [the SQLite-backed storage engine](/durable-objects/best-practices/access-durable-objects-storage/#sqlite-storage-backend).
174
+
- Only available when using SQLite-backed Durable Objects.
164
175
165
176
- Invokes `callback()` wrapped in a transaction, and returns its result.
166
177
@@ -170,7 +181,7 @@ let size = ctx.storage.sql.databaseSize;
170
181
171
182
## PITR (Point In Time Recovery) API
172
183
173
-
For [Durable Objects classes with SQL storage](/durable-objects/reference/durable-objects-migrations/#enable-sqlite-storage-backend-on-new-durable-object-class-migration), 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.
184
+
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.
174
185
175
186
The PITR API represents points in times 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.
- 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/#sqlite-storage-backend), `deleteAll()` removes the entire contents of a Durable Object's private SQLite database, including both SQL data and key-value data.
254
-
- 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).
255
-
-`deleteAll()` does not proactively delete [Alarms](/durable-objects/api/alarms/). Use [`deleteAlarm()`](/durable-objects/api/alarms/#deletealarm) to delete an alarm.
256
-
257
260
#### Supported options
258
261
259
262
-`put()`, `delete()` and `deleteAll()` support the following options:
@@ -331,28 +334,6 @@ The `put()` method returns a `Promise`, but most applications can discard this p
- Runs the sequence of storage operations called on `txn` in a single transaction that either commits successfully or aborts.
339
-
340
-
- 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.
341
-
342
-
-`txn`
343
-
344
-
- 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.<br/><br/>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.
345
-
346
-
* 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.
347
-
348
-
### `sync`
349
-
350
-
-`sync()`: <Typetext='Promise' />
351
-
352
-
- Synchronizes any pending writes to disk.
353
-
354
-
- 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.
355
-
356
337
## Alarms
357
338
358
339
### `getAlarm`
@@ -383,65 +364,43 @@ The `put()` method returns a `Promise`, but most applications can discard this p
383
364
384
365
-`setAlarm()` and `deleteAlarm()` support the same options as [`put()`](/durable-objects/api/storage-api/#put), but without `noCache`.
385
366
386
-
## Storage properties
367
+
## Other
387
368
388
-
### `sql`
369
+
### `deleteAll`
389
370
390
-
`sql` is a readonly property of type `DurableObjectStorage` encapsulating the [SQL API](/durable-objects/api/storage-api/#sql-api).
- 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.
374
+
- 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).
375
+
-`deleteAll()` does not proactively delete [alarms](/durable-objects/api/alarms/). Use [`deleteAlarm()`](/durable-objects/api/alarms/#deletealarm) to delete an alarm.
393
376
394
-
You can use TypeScript [type parameters](https://www.typescriptlang.org/docs/handbook/2/generics.html#working-with-generic-type-variables) to provide a type for your results, allowing you to benefit from type hints and checks when iterating over the results of a query.
Providing a type parameter does _not_ validate that the query result matches your type definition. In TypeScript, properties (fields) that do not exist in your result type will be silently dropped.
381
+
- Runs the sequence of storage operations called on `txn` in a single transaction that either commits successfully or aborts.
399
382
400
-
:::
383
+
- 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.
401
384
402
-
Your type must conform to the shape of a TypeScript [Record](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type) type representing the name (`string`) of the column and the type of the column. The column type must be a valid `SqlStorageValue`: one of `ArrayBuffer | string | number | null`.
385
+
-`txn`
403
386
404
-
For example,
387
+
- 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.<br/><br/>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.
405
388
406
-
```ts
407
-
typeUser= {
408
-
id:string;
409
-
name:string;
410
-
email_address:string;
411
-
version:number;
412
-
}
413
-
```
389
+
* 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.
414
390
415
-
This type can then be passed as the type parameter to a `sql.exec` call:
391
+
### `sync`
416
392
417
-
```ts
418
-
// The type parameter is passed between the "pointy brackets" before the function argument:
419
-
const result =this.ctx.storage.sql.exec<User>("SELECT id, name, email_address, version FROM users WHERE id = ?", user_id).one()
420
-
// result will now have a type of "User"
421
-
422
-
// Alternatively, if you are iterating over results using a cursor
423
-
let cursor =this.sql.exec<User>("SELECT id, name, email_address, version FROM users WHERE id = ?", user_id)
424
-
for (let row ofcursor) {
425
-
// Each row object will be of type User
426
-
}
393
+
-`sync()`: <Typetext='Promise' />
427
394
428
-
// Or, if you are using raw() to convert results into an array, define an array type:
429
-
typeUserRow= [
430
-
id: string,
431
-
name: string,
432
-
email_address: string,
433
-
version: number,
434
-
];
395
+
- Synchronizes any pending writes to disk.
435
396
436
-
// ... and then pass it as the type argument to the raw() method:
437
-
let cursor =sql.exec("SELECT id, name, email_address, version FROM users WHERE id = ?", user_id).raw<UserRow>();
397
+
- 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.
438
398
439
-
for (let row ofcursor) {
440
-
// row is of type User
441
-
}
442
-
```
399
+
## Storage properties
400
+
401
+
### `sql`
443
402
444
-
You can represent the shape of any result type you wish, including more complex types. If you are performing a JOIN across multiple tables, you can compose a type that reflects the results of your queries.
403
+
`sql` is a readonly property of type `DurableObjectStorage` encapsulating the [SQL API](/durable-objects/api/storage-api/#sql-api).
0 commit comments