Cloudflare Workers KV Introduction
Tags: serverless, storage, cloudflare
Published: 2020-06-11 21:07:29

---
title: "Cloudflare Workers KV Introduction"
published: true
description: "A serverless distributed eventually consistent key-value storage solution"
series: Cloudflare Workers
tags: serverless, storage, cloudflare 
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/t64pp3mg1njdgels2xmy.jpg
---

In [my previous article](https://dev.to/fllstck/cloudflare-workers-introduction-14mo), I explained Cloudflare Workers (CFW) and showed you a basic example. In this article, I will talk about Cloudflare Workers KV (KV), the serverless key-value store from Cloudflare.

# What is Cloudflare Workers KV?

KV is a serverless distributed eventually consistent key-value storage solution released in May 2019. It's deployed on the edge of the Cloudflare network like CFW, so the data you put into it is close to the CFW that uses it and, in turn, close to the client that sent a request to that CFW. 

The eventual consistency means that it can take up to 60 seconds for a write to be propagated through the whole network. Also, every key inside the KV allows for one write per second. So KV is mainly suited for data that isn't written often. 

KV can be accessed via an API, the Wrangler CLI, and directly from a CFW. This enables external services to update KV data so it can be read by a CFW without a redeploy.

The maximum size of a key is 512 Bytes, and the maximum size of a value is 10 MB. The values can be of type `String`, [ReadableStream](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream), and [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer), so we can also store binary data!

Every account can have a maximum of 100 namespaces, and every namespace can have an unlimited amount of keys.

Important note: **KV isn't free.**

You have to get a subscription to the [Workers Unlimited plan](https://workers.cloudflare.com/#plans), which costs $5 a month. The plan includes 1GB of storage, 10 million reads, and 1 million writes, 1 million updates, and 1 million deletes per month.

If you go over these limits the costs are:

- $0.50 for 1GB
- $0.50 for 10 million reads 
- $5 for 1 million writes
- $5 for 1 million updates
- $5 for 1 million deletes

# What are good Use Cases?

The deployment of a CFW is quite fast, so if you have data that is written much more often than it's read, you can simply put the data into the code and be done with it. But a CFW's maximum script size is 1 MB; for some use cases, this is simply not enough. 

## Authentication

Authentication is one way to use KV because the CFW docs say: *"All values are encrypted at rest with 256-bit AES-GCM, and only decrypted by the process executing your Worker scripts or responding to your API requests."*

If you put your API behind a CFW, you can implement authentication right inside the CFW and keep it out of your API entirely, simplifying its code.

## Configuration

If you build a highly configurable system with CFW, that config data can also live in KV. This enables you to update it externally, without any CFW redeploys.

## Website Files

If you host a website, chances are that you have a large number of small files, HTML, CSS, JavaScript, images, you name it. With 10 MB maximum file size in KV, most website files should neatly fit into that limit. 

With the rise of [the JAMStack](https://jamstack.org/), it's nice to know that with KV, there is a way to deploy the static files right at the edge, so they are close to the user. After all, low-latency is what it's all about!

Cloudflare even has optimized its static website deployment workflow with [Cloudflare Workers Sites](https://workers.cloudflare.com/sites).

# Example: Creating an Authorization Worker

Now that we know what KV is let's build a CFW that uses it!

In this example, we will build a simple authorizer that can be put in front of an API to check if a user is allowed to access that respective API.

## Pre-Requisites

For this tutorial, you need Node.js v12 and a [Cloudflare account](https://dash.cloudflare.com/sign-up) with a "Workers Unlimited" subscription that costs $5 per month.

## Installing the CLI

Developing and deploying CFW is done with the help of a CLI called Wrangler. We will install it via NPM.

    $ npm i @cloudflare/wrangler -g

## Initializing a Project

The CLI can then be used to create a new CFW project.

    $ wrangler generate auth
    $ cd auth
    $ npm i

## Creating a KV Namespace

A KV namespace is used to separate data. We can create one with the following Wrangler CLI command:

    $ wrangler kv:namespace create "ACCOUNTS"

This will output a namespace ID which we have to include the new namespace into our `wrangler.toml` file.

```toml
kv-namespaces = [
    {binding = "ACCOUNTS", id = "<NAMESPACE_ID>"}
]
```

After this, we get access to a global `ACCOUNTS` object inside our CFW script.

## Putting a Password Hash into KV

To get passwords into our freshly created `ACCOUNTS` namespace in KV, we can also use the Wrangler CLI. 

The following command will add a key "kay" with the SHA-256 hash for the password "fllstck" as value. 

    $ wrangler kv:key put --binding=ACCOUNTS \
    "kay" \
    "69953BBB597B77EDB5FA691FD6396D69756EB949A87F250E32F799AB59F796BD"

We will be able to access the value inside of the CFW with this code:

```javascript
const passwordHash = await ACCOUNTS.get("kay");
```

## Implementing the Worker Script

The authorizer is a CFW in front of an API. This requires the API domain to be handled by Cloudflare DNS.

Put the following JavaScript code into your `index.js`:

```javascript
const API_HOST = "https://dog.ceo";

addEventListener("fetch", (event) => {
  event.respondWith(authorize(event.request));
});

async function authorize(request) {
  const [type, token] = request.headers.get("Authorization").split(" ");

  if (type !== "Basic") {
    return new Response("", {
      status: 400,
      statusText: `Unsupported authentication type "${type}"`,
    });
  }

  const [username, password] = atob(token).split(":");

  const accountHash = await ACCOUNTS.get(username);
  const suppliedHash = await hash(password);

  if (suppliedHash !== accountHash) {
    return new Response("", {
      status: 401,
      statusText: "Unauthorized.",
    });
  }

  if (ENVIRONMENT === "staging") {
    const url = new URL(request.url);
    request = new Request(API_HOST + url.pathname, request);
  }

  return fetch(request);
}

async function hash(password) {
  const msgUint8 = new TextEncoder().encode(password);
  const hashBuffer = await crypto.subtle.digest("SHA-256", msgUint8);
  const hashArray = Array.from(new Uint8Array(hashBuffer));
  return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
}

```

Let's go through it!

The example uses [basic authorization](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization), so we have to extract the `Authorization` header as a first step.

The `Authorization` header is a string that includes an authorization `type` separated with a space from a `token`.

In our case, the `type` should be "Basic".

The `token` consists of a `username` and a `password` separated by a colon and encoded to Base64.

In our KV namespace `ACCOUNTS`, we store password hashes keyed by usernames, so we can use the `username` to find a corresponding password hash.

After we searched for a hash, we will hash the password sent by the client with the `hash()` helper function and compare it with the stored password hash in KV.

If no hash was found in KV or the hashes don't match up, we respond with a `401` status.

If everything matches up, we will send the request to the origin server, which in this case would be our actual API, and redirect the APIs response to the client.

> Note: In this example, the host part of the request URL is overwritten on a staging deployment because the worker will be hosted on workers.dev and not your own domain. Also, for this example, we use the public dog.ceo API.

## Deploying the Worker Script

We use the Wrangler CLI again to deploy the script. For this, we have to add our account ID to the `wrangler.toml` file, it can be found on your Cloudflare dashboard under the menu point Workers.

After we added the ID, we can do a non-production deploy with the following command:

    $ wrangler publish

## Using the Worker

If everything went good, we can access our worker at:

    https://auth.<ACCOUNT_NAME>.workers.dev/api/breeds/image/random

Our CFW will reuse the path of that URL, but replace the host part of it. We also have to include the Authorization header with basic auth credentials.

An example cURL request could look like this:

    $ curl -u kay:fllstck https://auth.fllstck.workers.dev/api/breeds/image/random

# Summary

KV is a pretty powerful addition to Cloudflare Workers that makes them useful for even more use cases.

And the best of it: it isn't much harder to use than the [Web Storage API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API) *and* KV can be accessed via the Wrangler CLI and [the Cloudflare API](https://api.cloudflare.com/#workers-kv-namespace-write-key-value-pair). API access makes them very powerful.

But it's still important to keep the limits in mind!

A maximum of 10 MB per value and up to 60 seconds to populate a write can be a dealbreaker for some types of apps.