Announcing Deno KV
We’re thrilled to introduce Deno KV, a strongly consistent key-value database, globally replicated for low-latency reads across 35 worldwide regions.
Deno Deploy aims to provide the simplest and fastest way to deploy and run JavaScript, TypeScript, and Wasm at the edge. However, creating stateful apps on Deno Deploy previously required connecting to external cloud databases, which involved additional configuration steps, local testing challenges, and potentially undermined the benefits of using the edge if the datastore wasn’t geographically replicated.
With today’s announcement, we’re bringing a globally integrated database to Deno that allows you to effortlessly develop full-featured apps while overcoming these obstacles.
In this post, we’ll discuss key aspects of Deno KV:
- Run locally or managed
- Simple but powerful
- Atomic transactions
- Consistency and performance
- Use cases and examples
- What’s next
If you’re interested in using Deno KV, please join the waitlist.
Note: Deno KV is currently in beta, and long-term data durability is not
guaranteed. Please keep this in mind when using Deno KV for production
applications.
Note: Deno KV is currently in open beta.
Run locally or managed
Deno KV is seamlessly integrated into the open-source Deno runtime, allowing you to run it locally or deploy it as a managed service with zero configuration.
When running locally, Deno KV is backed by SQLite, providing a lightweight and easy-to-use solution for local development, testing, or for single region production systems.
When you deploy your application to Deno Deploy, the Deno KV database is automatically backed by FoundationDB. This managed solution is operated by the Deno company, ensuring high performance and reliability without the need for manual configuration or maintenance on your part.
Simple but powerful
Deno KV is a first-class primitive and exposes only a handful of methods that you can use to store, retrieve, delete, and enumerate data. Designed for JavaScript, Deno KV can store any JavaScript structured serializable value, such as Objects, Arrays, BigInts, Dates, and more.
const kv = await Deno.openKv();
const key = ["users", crypto.randomUUID()];
const value = { name: "Alice", created: new Date() };
await kv.set(key, value);
const result = await kv.get(key);
console.log(result.value);
// { name: "Alice", created: 2023-05-01T09:24:07.620Z }
Use the kv.list()
operation to list all keys matching a specific selector. In
the example below, all keys starting with a particular prefix are selected.
await kv.set(["users", "alice"], { birthday: "January 1, 1990" });
await kv.set(["users", "sam"], { birthday: "February 14, 1985" });
await kv.set(["users", "taylor"], { birthday: "December 25, 1970" });
// List out all entries with keys starting with `["users"]`
const iter = kv.list({ prefix: ["users"] });
for await (const entry of iter) {
console.log(entry.key);
console.log(entry.value);
}
The list operation retrieves data from the store in batches, defaulting to 500
keys. To implement pagination, pass the iter.cursor
property back into
subsequent calls of kv.list()
.
Learn more about the available methods in the documentation.
Atomic transactions
For many applications, reliable database transactions are necessary. This is
possible in Deno KV using kv.atomic()
to create transactions with strong
consistency across multiple keys that are immediately durable by default:
const kv = await Deno.openKv();
const change = 10;
const bob = await kv.get(["balance", "bob"]);
const liz = await kv.get(["balance", "liz"]);
if (bob.value < change) {
throw "not enough balance";
}
const success = await kv.atomic()
.check(bob, liz) // balances did not change
.set(["balance", "bob"], bob.value - change)
.set(["balance", "liz"], liz.value + change)
.commit();
Learn more about how we handle transactions.
Consistency and performance
Deno KV is a strongly-consistent database, providing external consistency, which includes:
- Serializability: The highest level of isolation for transactions, ensuring that concurrent transaction execution results in a system state equivalent to a sequential order of these transactions.
- Linearizability: Guarantees that operations, such as read and write, appear instantaneous and occur in real-time. Once a write operation completes, all subsequent read operations return the updated value, ensuring a strong real-time ordering.
You can relax consistency constraints with the consistency: "eventual"
option
for individual read operations:
// Read with eventual consistency from the nearest region
await db.get(["my-key"], { consistency: "eventual" });
// Read with strong consistency from the primary region
await db.get(["my-key"], { consistency: "strong" });
This option allows the system to serve the read from global replicas and caches for minimal latency.
Here are average latency figures for the beta in our most popular regions. Improvements are expected for the public beta and GA release.
Region | Latency (Eventual Consistency) | Latency (Strong Consistency) |
---|---|---|
North Virginia (us-east4) | 7ms | 7ms |
Frankfurt (europe-west3) | 7ms | 94ms |
Netherlands (europe-west4) | 13ms | 95ms |
California (us-west2) | 72ms | 72ms |
Hong Kong (asia-east2) | 42ms | 194ms |
Use cases and examples
Deno KV is a versatile solution for managing application state, making it ideal for various use cases. Here are some examples of applications showcasing the potential of Deno KV:
- Real-time collaboration: Deno KV can store and synchronize data across
multiple clients, enabling seamless collaboration on tasks such as document
editing or multiplayer gaming. Often with real-time applications, Deno’s
BroadcastChannel
is used to help synchronize state. - User data management: Store and manage user-generated content, such as blog posts and comments, with Deno KV. By using a globally replicated database, you can ensure quick accessibility, regardless of the user’s location.
- Authentication: Deno KV can store user credentials, roles, and permissions, enabling secure and efficient authentication for your applications.
As a basic example, explore this playground to see how simple it is to create a globally consistent, persistent counter using Deno KV:
import { serve } from "/std@0.155.0/http/server.ts";
const db = await Deno.openKv();
serve(async (req: Request) => {
await db.atomic().sum(["views"], 1n).commit();
const res = await db.get(["views"]);
const views = res.value.value;
return new Response(`Views: ${views}`);
});
Here are some more advanced demo apps we have built to illustrate Deno KV’s capabilities:
- Multiplayer Tic-Tac-Toe (source, demo): A simple online multiplayer game.
- Pixel-page (source, demo): A collaborative drawing app that demonstrates real-time synchronization and user data management.
- Shared Todo list (source, demo): A task management application illustrating Deno KV’s ability to store and manage user-generated data.
- KV sketchbook (source, demo): A web-based sketchbook that highlights Deno KV’s ability to store and retrieve user-created sketches, showcasing user data management.
These examples provide a glimpse of what you can achieve with Deno KV. With its simplicity, scalability, and global replication, Deno KV is a powerful tool for developers looking to build stateful applications with ease.
What’s next
Our mission is to make Deno Deploy the go-to platform for deploying and running API servers, web apps, and edge functions. Providing globally replicated, persistent data storage is a major step towards that goal. In the coming months, we’ll be introducing features to further simplify the process of building and deploying applications with just a few lines of code.
During the beta period, users can enjoy up to one gigabyte of storage for free. We will announce pricing details soon.
Other resources:
If you’re interested in using Deno KV, please join waitlist.
Don’t miss any updates — follow us on Twitter.