7.2 Local storage

By default, Deno provides access to local storage for persistently storing data that survives Deno runtime restarts. The data is stored in a file on the disk. The local storage implementation doesn't support saving data remotely. This problem has been solved by Deno KV, which will be topic of the next book revision.

The local storage (and session storage too) is internally supported by SQLite. The users would never know or see SQLite. For them, it is a simple & local KV storage. The local storage mechanism is a simple KV store that reside on the disk.

An overview of the local storage architecture is as follows:

The user applications call the local storage APIs provided by Deno. The local storage APIs in JS space are supported by the OPs in rust space. The local storage APIs in rust, in turn, calls the SQLite APIs, which works with the database file on the disk.

In this section, we'll learn:

  • The location of the database

  • The queries used to work with the database

For all the interactions with the SQLite database, Deno uses rusqlite crate.

Location of the database

The default location of the SQLite database that would hold the data for local storage is:

  • On linux, the location of database is $HOME/.cache/deno

  • On Windows, the location of database is %LOCALAPPDATA%/deno

  • On Mac, the location of database is $HOME/Library/Caches/deno

In short, the location of the database is inside the cache folder that is used by Deno for other purposes.

Unless used at least once, Deno doesn't create any database file. There is no point in creating database files on the disk if the applications on that server have never or are never going to use it.

As soon as any of the storage API is called, Deno ensures that a database exists. This is achieved through the following function (get_webstorage):

This function takes the following actions:

  • Creates a database file

  • Establish a connection to the database

  • Apply some default settings

  • Create a table in the database

The default name for the table is 'data'. This table contains exactly two columns:

  • key

  • value

Both key and values are strings, as suggested by the web storage standards. The table is created only if it doesn't exist. If it exists, the table is left untouched. This ensures that the data present in the table remains intact.

As soon as any of the local storage APIs are used, we'll see database files in the storage directories. If we use repl, there will be a storage directory for repl that gets used for all repl sessions.

Now, there is a directory that holds the database files (there are more than one).

We can set some item in the local storage for repl, and try to get it in another repl session.

Custom databases

The local storage in the browser is defined as:

The localStorage read-only property of the window interface allows you to access a Storage object for the Document's origin; the stored data is saved across browser sessions.

This means that the local storage is tied to the origin of the URL in the browser's address bar. This also means that there is separate storage available for each origin.

Deno takes the same concept forward and makes a different database available to different origins. However, there is no concept of address bar here. Therefore, Deno takes origin from two sources:

  • The main program name

  • The --location argument if specified

This ensures that each application has their own database.

As we can see, in addition to repl database, there is a new one specifically created for this application. A new database gets created for each application that attempts to use local storage.

Within an application, there is a way to segregate data further by specifying the --location argument. This creates a separate database for each location, which is separate from the database that gets created if location is not specified. Each application can open and use a different database by utilizing the --location argument.

That's all about the database files. We'll now turn our attention to the internals of a couple of heavily used local storage APIs:

  • getItem

  • setItem

Get item from local storage

Getting an item from local storage is one of the two most used local storage APIs. The other one is setItem, which we'll see in the next section. This is a simple API with only one input: Key.

We'll trace the journey starting from the user space.

JS space

The getItem API code is as follows:

This is a very simple function that

  • Validates the presence of input key

  • Defers the work to a rust OP called op_webstorage_get

Rust space

The OP function called op_webstorage_get is a synchronous function, that runs a query in the SQLite database and sends the result back. Note that the getItem and setItem are synchronous functions.

The code of op_webstorage_get is much simpler than our expectations. This function:

  • Opens a connection to database (if not already open)

  • Prepares a query

  • Executes the query

  • Return the results back

The important part here is the query, which is:

As simple as it looks, that's all about getting an item from local storage. Simply run a query in the SQLite data and return the result. This is no different from running a query directly (which we'll do shortly).

Set item in the local storage

Setting an item into local storage is the other of the two most used local storage APIs.This is a simple API with two inputs: Key & Value.

Again, we'll trace the journey starting from the user space.

JS space

The setItem API code is as follows:

This is a very simple function that

  • Validates the presence of input key & value

  • Defers the work to a rust OP called op_webstorage_set

Rust space

The OP function called op_webstorage_set is a synchronous function, that runs a DML operation in the SQLite database. Note that the getItem and setItem are synchronous functions.

The code of op_webstorage_set is also much simpler than our expectations, but slightly longer than the get function. There are multiple size related checks.

Mirroring browser implementations, Deno enforces a 10MB size limit on local storage per origin. This constraint ensures database integrity and prevents excessive storage consumption. The op_webstorage_set function diligently safeguards database sanity by preventing size thresholds from being exceeded.

This op_webstorage_set function:

  • Opens a connection to database (if not already open)

  • Checks if the length of key & value is not more than 10MB

  • Checks if current database size is less than 10MB

  • Executes the DML operation to insert or update record in the database

The important part here is the DML statement, which is:

As simple as it looks, that's all about setting an item into local storage. This API returns nothing back.

Other APIs

Before closing this section, we'll take a quick at a couple of other interesting APIs:

  • removeItem

  • clear

The removeItem API removes the record from the database. It issues a DELETE command to make this happen.

Lastly, the clear API removes all records from the table. This API also issues the DELETE command without any inputs.

Database file

Fulfilling our earlier promise and satisfying our curiosity, we'll briefly examine the database file within the SQLite shell. The local_storage file, residing within any database folder in the root database directory, can be directly opened using the SQLite shell.

First, we'll set a couple of keys into the local storage using deno repl:

The file named local_storage can be opened directly inside the SQLite shell:

As you can see, this is the same type of SQLite database file that you may have used in the past. We've verified that a table named "data" exists with two keys that we set earlier. We've also verified that the table contains two rows matching the data we set through the Deno REPL.


This concludes our exploration of local storage internals in Deno. The next section is about session storage, building upon the detailed background we've established. The focus on session storage will be concise, leveraging your newly acquired understanding of local storage mechanisms.

Last updated