This document defines APIs for a database of records holding simple values and hierarchical objects. Each record consists of a key and some value. Moreover, the database maintains indexes over records it stores. An application developer directly uses an API to locate records either by their key or by using an index. A query language can be layered on this API. An indexed database can be implemented using a persistent B-tree data structure.
A Candidate Recommendation (CR) of the specification was published on 4 July 2013. Changes to this specification since the CR was published are summarized and enumerated in this document's Revision History appendix.
This specification's bugs and issues are managed in Bugzilla (new bug, open bugs). Feature requests for the next version of this specification are kept in the Indexed Database Features document.
User agents need to store large numbers of objects locally in order to satisfy off-line data requirements of Web applications. [[WEBSTORAGE]] is useful for storing pairs of keys and their corresponding values. However, it does not provide in-order retrieval of keys, efficient searching over values, or storage of duplicate values for a key.
This specification provides a concrete API to perform advanced key-value data management that is at the heart of most sophisticated query processors. It does so by using transactional databases to store keys and their corresponding values (one or more per key), and providing a means of traversing keys in a deterministic order. This is often implemented through the use of persistent B-tree data structures that are considered efficient for insertion and deletion as well as in-order traversal of very large numbers of data records.
This specification defines one class of products:
A user agent MUST behave as described in this specification in order to be considered conformant.
User agents MAY implement algorithms given in this specification in any way desired, so long as the end result is indistinguishable from the result that would be obtained by the specification's algorithms.
A conforming Indexed Database API user agent MUST also be a conforming implementation of the IDL fragments of this specification, as described in the “Web IDL” specification. [[!WEBIDL]]
This specification uses both the terms "conforming user agent(s)" and "user agent(s)" to refer to this product class.
This specification relies on several other underlying specifications.
DOMException
and
Event
are defined by the W3C DOM4 Specification [[!DOM4]].
Function
,
origin, same origin, structured clone,
structured clone algorithm, task, task source,
and queue a task are defined by the HTML 5
specification [[!HTML5]].
Worker
and
WorkerUtils
are defined by the WebWorkers specification [[!WEBWORKERS]].A database's origin is the same as the origin of the document or worker. Each origin has an associated set of databases.
The database origin is not affected by changes to document.domain
.
Every database has a name which identifies it within a specific origin. The name can be any string value, including the empty string, and stays constant for the lifetime of the database. Each database also has a current version. When a database is first created, its version is 0.
Implementations MUST support all names. If an implementation uses a storage mechanism which can't handle arbitrary database names, the implementation must use an escaping mechanism or something similar to map the provided name to a name that it can handle.
Each database has one version at a time; a database
can't exist in multiple versions at once. The only way to change the version is using a "versionchange"
transaction.
Databases has a delete pending flag which is used during deletion. When a database is requested to be deleted the flag is set to true and all attempts at opening the database are stalled until the database can be deleted.
The act of opening a database creates a connection. There MAY be multiple connections to a given database at any given time. Each connection has a closePending flag which initially is set to false.
When a connection is initially created it is in opened state. The connection can be closed through several means. If the connection is GCed or execution context where the connection is created is destroyed (for example due to the user navigating away from that page), the connection is closed. The connection can also be closed explicitly using the steps for closing a database connection. When the connection is closed the closePending flag is always set to true if it hasn't already been.
The IDBDatabase interface represents a connection to a database.
An object store is the primary storage mechanism for storing data in a database.
Each database has a set of object stores. The set of object stores can be changed,
but can only be changed using a "versionchange"
transaction, i.e. in response to a
upgradeneeded
event. When a new database is created it doesn't contain any object stores.
The object store has a list of records which hold the data stored in the object store. Each record consists of a key and a value. The list is sorted according to key in ascending order. There can never be multiple records in a given object store with the same key.
Every object store has a name. The name is unique within the database to which it belongs. Every object store also optionally has a key generator and an optional key path. If the object store has a key path it is said to use in-line keys. Otherwise it is said to use out-of-line keys.
The object store can derive the key from one of three sources:
The IDBObjectStore interface represents an object store. Note however that multiple instances of those interfaces representing the same object store can exist.
In order to efficiently retrieve records stored in an indexed database,
each record is organized according to its key. A value is said to be a valid key
if it is one of the following ECMAScript [[!ECMA-262]] types:
Number
primitive value,
String
primitive value,
Date
object, or
Array
object.
An Array
is only a valid key if every item in the array is defined and is
a valid key (i.e. sparse arrays can not be valid keys) and if the Array
doesn't directly or
indirectly contain itself.
Any non-numeric properties on an Array
are ignored, and thus do not affect whether the Array
is a valid key.
If the value is of type Number
, it is only a valid key if it is not NaN
.
If the value is of type Date
it is only a valid key if its [[PrimitiveValue]]
internal property, as defined by [[!ECMA-262]], is not NaN
.
Conforming user agents MUST support all valid keys as keys.
Infinite Number
values are valid keys. As are empty Array
s.
Operations that accept keys MUST perform as if each key parameter value, in order, is copied by the structured clone algorithm [[!HTML5]] and the copy is instead used as input to the operation, before proceding with rest of the operation.
This implicit copying step ensures that key values do not change after
the operation begins, due to side effects such as ECMAScript [[!ECMA-262]] getters,
setters and type conversion functions including toString()
and
valueOf()
.
For purposes of comparison, all Array
s are greater than all String
,
Date
and Number
values; all String
values are greater than all
Date
and Number
values; and all Date
values are greater than all
Number
values. Values of type Number
are compared to other Number
values
numerically. Values of type Date
are compared to other Date
values chronologically.
Values of type String
are compared to other values of type String
by using the algorithm defined by step 4 of section 11.8.5, The Abstract Relational Comparison Algorithm,
of the ECMAScript Language Specification [[!ECMA-262]].
Values of type Array
are compared to other values of type Array
as follows:
Array
value and B be the second Array
value.
Note that Array
s that contain other Array
s are allowed as valid keys.
In this case the algorithm above runs recursively when comparing the individual values in the arrays.
As a result of the above rules, negative infinity is the lowest possible value for a key.
There is no highest possible key value.
This is because an Array
of any candidate highest key followed by another valid key is even higher.
The terms greater than, less than and equal to are defined in the terms of the above comparisons.
The following examples illustrate the different behaviors when trying to use in-line keys and key generators to save an object to an object store.
Each record is associated with a value. Conforming user agents MUST support
any ECMAScript [[!ECMA-262]] value supported by the structured clone algorithm
[[!HTML5]]. This includes simple types such as String
primitive values
and Date
objects as well as Object
and Array
instances, File
objects, Blob
objects, ImageData
objects, and so on. Record values are stored and retrieved
by value rather than by reference; later changes to a value have no effect on
the record stored in the database.
A key path is a DOMString
or sequence<DOMString>
that defines how to extract a key
from a value. A valid key path is one of:
DOMString
.DOMString
matching
the IdentifierName
production from the ECMAScript Language Specification [[!ECMA-262]].DOMString
consisting of two or more identifiers separated by
periods (ASCII character code 46).sequence<DOMString>
containing only DOMString
s conforming to
the above requirements.Spaces are not allowed within a key path.
To evaluate a key path, run the steps for extracting a key from a value using a key path.
Key path values can only be accessed from properties explicitly copied by the structured clone algorithm, as well as the following properties:
Blob.size
Blob.type
File.name
File.lastModifiedDate
Array.length
String.length
It is sometimes useful to retrieve records in an object store through other means than their key. An index allows looking up records in an object store using properties of the values in the object stores records.
An index is a specialized persistent key-value storage and has a referenced object store. The index has a list of records which hold the data stored in the index. The records in an index are automatically populated whenever records in the referenced object store are inserted, updated or deleted. There can be several indexes referencing the same object store, in which changes to the object store cause all such indexes to get updated.
The values in the index's records are always values of keys in the index's referenced object store. The keys are derived from the referenced object store's values using a key path. If a given record with key X in the object store referenced by the index has the value A, and evaluating the index's key path on A yields the result Y, then the index will contain a record with key Y and value X.
Records in an index are said to have a referenced value. This is the value of the record in the index's referenced object store which has a key equal to the index's record's value. So in the example above, the record in the index whose key is Y and value is X has a referenced value of A.
Each record in an index references one and only one record in the index's referenced object store. However there can be multiple records in an index which reference the same record in the object store. And there can also be no records in an index which reference a given record in an object store.
The records in an index are always sorted according to the record's key. However unlike object stores, a given index can contain multiple records with the same key. Such records are additionally sorted according to the index's record's value (meaning the key of the record in the referenced object store).
Every index has a name. The name is unique within index's referenced object store.
Each index also has a unique flag. When this flag is set to true, the index enforces that no two records in the index has the same key. If a record in the index's referenced object store is attempted to be inserted or modified such that evaluating the index's key path on the records new value yields a result which already exists in the index, then the attempted modification to the object store fails.
Each index also has a multiEntry flag. This flag affects how the index behaves when the result of evaluating
the index's key path yields an Array
. If the multiEntry flag is false, then
a single record whose key is an Array
is added to the index. If the multiEntry flag is
true, then the one record is added to the index for each item in the Array
. The key for each
record is the value of respective item in the Array
.
The IDBIndex interface provides access to the metadata of an index. Note however that multiple instances of those interfaces representing the same index can exist.
A transaction is used to interact with the data in a database. Whenever data is read or written to the database it is done by using a transaction.
All transactions are created through a connection, which is the transaction's connection. The transaction has a mode that determines which types of interactions can be performed upon that transaction. The mode is set when the transaction is created and remains fixed for the life of the transaction. The transaction also has a scope that determines the object stores with which the transaction may interact. Transactions have an active flag, which determines if new requests can be made against the transaction. Finally, transactions also contain a request list of requests which have been made against the transaction.
Each transaction has a fixed scope, determined when the transaction is created. A transaction's scope remains fixed for the lifetime of that transaction.
Transactions offer some protection from application and system failures. A transaction may be used to store multiple data records or to conditionally modify certain data records. A transaction represents an atomic and durable set of data access and data mutation operations.
Transactions are expected to be short lived. This is encouraged by the automatic committing functionality described below. Authors can still cause transactions to run for a long time; however, this usage pattern is not generally recommended as it can lead to a bad user experience.
The lifetime of a transaction is as follows:
IDBDatabase.transaction
.
The arguments passed determine the scope of the transaction and whether the transaction is read-only.
When a transaction is created its active flag is initially set to true.
DOMException
of type TransactionInactiveError
.
QuotaExceededError
should
be used as error, and if an IO error happened, UnknownError
should be used as
error.
Transactions are opened in one of three modes. The mode determines how concurrent access to object stores in the transaction are isolated.
"readonly"
transaction is only allowed
to read data. No modifications can be done by this type of transaction. This has the advantage
that several "readonly"
transactions can run at the same time even if their scopes
are overlapping, i.e. if they are using the same object stores. This type of transaction can
be created any time once a database has been opened using the
IDBDatabase.transaction
method.
"readwrite"
transaction is allowed to read, modify and
delete data from existing object stores. However object stores and indexes can't be added or removed.
Multiple "readwrite"
transactions can't run at the same time if their scopes are overlapping
since that would mean that they can modify each other's data in the middle of the transaction.
This type of transaction can be created any time once a database has been opened using the
IDBDatabase.transaction
method.
"versionchange"
transaction is similar to a "readwrite"
transaction,
however it can additionally create and remove object stores and indexes. It is the only type of
transaction that can do so. This type of transaction can't be manually created, but instead is created
automatically when a upgradeneeded
event is fired.
Any number of transactions opened in "readonly"
mode are allowed to r