Repository: cloudflare/cloudflare-docs
Pull request #20655: thomasgauvin: add examples to workers kv
Author: login: thomasgauvin
Labels: name: product:reference-architecture
name: size/xl
name: product:kv
Created: 2025-03-08T23:47:04Z | Merged: 2025-03-27T15:58:15Z



Diff:
diff --git a/src/content/docs/kv/examples/cache-data-with-workers-kv.mdx b/src/content/docs/kv/examples/cache-data-with-workers-kv.mdx
new file mode 100644
index 000000000000000..4334eea7426fbc7
--- /dev/null
+++ b/src/content/docs/kv/examples/cache-data-with-workers-kv.mdx
@@ -0,0 +1,145 @@
+---
+type: example
+summary: Cache data or API responses in Workers KV to improve application performance
+tags:
+  - KV
+pcx_content_type: configuration
+title: Cache data with Workers KV
+sidebar:
+  order: 5
+description: Example of how to use Workers KV to build a distributed application configuration store.
+---
+
+import { Render, PackageManagers, Tabs, TabItem } from "~/components";
+
+Workers KV can be used as a persistent, single, global cache accessible from Cloudflare Workers to speed up your application.
+Data cached in Workers KV is accessible from all other Cloudflare locations as well, and persists until expiry or deletion.
+
+After fetching data from external resources in your Workers application, you can write the data to Workers KV.
+On subsequent Worker requests (in the same region or in other regions), you can read the cached data from Workers KV instead of calling the external API.
+This improves your Worker application's performance and resilience while reducing load on external resources.
+
+This example shows how you can cache data in Workers KV and read cached data from Workers KV in a Worker application.
+
+:::note[Note]
+
+You can also cache data in Workers with the [Cache API](/workers/runtime-apis/cache/). With the Cache API,
+the contents of the cache do not replicate outside of the originating data center and the cache is ephemeral (can be evicted).
+
+With Workers KV, the data is persisted by default to [central stores](/kv/concepts/how-kv-works/) (or can be set to [expire](/kv/api/write-key-value-pairs/#expiring-keys), and can be accessed from other Cloudflare locations.
+:::
+
+## Cache data in Workers KV from your Worker application
+
+In the following `index.ts` file, the Worker fetches data from an external server and caches the response in Workers KV. If the data is already cached in Workers KV, the Worker reads the cached data from Workers KV instead of calling the external API.
+
+<Tabs>
+<TabItem label="index.ts">
+```js title="index.ts" collapse={42-1000}
+interface Env {
+  CACHE_KV: KVNamespace;
+}
+
+export default {
+  async fetch(request, env, ctx): Promise<Response> {
+
+    const EXPIRATION_TTL = 60; // Cache expiration in seconds
+    const url = 'https://example.com';
+    const cacheKey = "cache-json-example";
+
+    // Try to get data from KV cache first
+    let data = await env.CACHE_KV.get(cacheKey, { type: 'json' });
+    let fromCache = true;
+
+    // If data is not in cache, fetch it from example.com
+    if (!data) {
+      console.log('Cache miss. Fetching fresh data from example.com');
+      fromCache = false;
+
+    		// In this example, we are fetching HTML content but it can also be API responses or any other data
+      const response = await fetch(url);
+    		const htmlData = await response.text();
+
+    		// In this example, we are converting HTML to JSON to demonstrate caching JSON data with Workers KV
+    		// You could cache any type of data, or even cache the HTML data directly
+    		data = helperConvertToJSON(htmlData);
+    		// The expirationTtl option is used to set the expiration time for the cache entry (in seconds), otherwise it will be stored indefinitely
+    		await env.CACHE_KV.put(cacheKey, JSON.stringify(data), { expirationTtl: EXPIRATION_TTL });
+    }
+
+    // Return the appropriate response format
+    	return new Response(JSON.stringify({
+    		data,
+    		fromCache
+    	}), {
+    		headers: { 'Content-Type': 'application/json' }
+    	});
+
+}
+} satisfies ExportedHandler<Env>;
+
+// Helper function to convert HTML to JSON
+function helperConvertToJSON(html: string) {
+// Parse HTML and extract relevant data
+const title = helperExtractTitle(html);
+const content = helperExtractContent(html);
+const lastUpdated = new Date().toISOString();
+
+    return { title, content, lastUpdated };
+
+}
+
+// Helper function to extract title from HTML
+function helperExtractTitle(html: string) {
+const titleMatch = html.match(/<title>(.\*?)<\/title>/i);
+return titleMatch ? titleMatch[1] : 'No title found';
+}
+
+// Helper function to extract content from HTML
+function helperExtractContent(html: string) {
+const bodyMatch = html.match(/<body>(.\*?)<\/body>/is);
+if (!bodyMatch) return 'No content found';
+
+    // Strip HTML tags for a simple text representation
+    const textContent = bodyMatch[1].replace(/<[^>]*>/g, ' ')
+    	.replace(/\s+/g, ' ')
+    	.trim();
+
+    return textContent;
+
+}
+
+````
+</TabItem>
+<TabItem label="wrangler.jsonc">
+```json
+{
+	"$schema": "node_modules/wrangler/config-schema.json",
+	"name": "<ENTER_WORKER_NAME>",
+	"main": "src/index.ts",
+	"compatibility_date": "2025-03-03",
+	"observability": {
+		"enabled": true
+	},
+	"kv_namespaces": [
+		{
+			"binding": "CACHE_KV",
+			"id": "<YOUR_BINDING_ID>"
+		}
+	]
+}
+````
+
+</TabItem>
+</Tabs>
+
+This code snippet demonstrates how to read and update cached data in Workers KV from your Worker.
+If the data is not in the Workers KV cache, the Worker fetches the data from an external server and caches it in Workers KV.
+
+In this example, we convert HTML to JSON to demonstrate how to cache JSON data with Workers KV, but any type of data
+can be cached in Workers KV. For instance, you could cache API responses, HTML content, or any other data that you want to persist across requests.
+
+## Related resources
+
+- [Rust support in Workers](/workers/languages/rust/).
+- [Using KV in Workers](/kv/get-started/).
diff --git a/src/content/docs/kv/examples/distributed-configuration-with-workers-kv.mdx b/src/content/docs/kv/examples/distributed-configuration-with-workers-kv.mdx
new file mode 100644
index 000000000000000..27bf6d07291237c
--- /dev/null
+++ b/src/content/docs/kv/examples/distributed-configuration-with-workers-kv.mdx
@@ -0,0 +1,235 @@
+---
+type: example
+summary: Use Workers KV to as a geo-distributed, low-latency configuration store for your Workers application
+tags:
+  - KV
+pcx_content_type: configuration
+title: Build a distributed configuration store
+sidebar:
+  order: 5
+description: Example of how to use Workers KV to build a distributed application configuration store.
+---
+
+import { Render, PackageManagers, Tabs, TabItem } from "~/components";
+
+Storing application configuration data is an ideal use case for Workers KV. Configuration data can include data to personalize an application for each user or tenant, enable features for user groups, restrict access with allow-lists/deny-lists, etc. These use-cases can have high read volumes that are highly cacheable by Workers KV, which can ensure low-latency reads from your Workers application.
+
+In this example, application configuration data is used to personalize the Workers application for each user. The configuration data is stored in an external application and database, and written to Workers KV using the REST API.
+
+## Write your configuration from your external application to Workers KV
+
+In some cases, your source-of-truth for your configuration data may be stored elsewhere than Workers KV.
+If this is the case, use the Workers KV REST API to write the configuration data to your Workers KV namespace. 
+
+The following external Node.js application demonstrates a simple scripts that reads user data from a database and writes it to Workers KV using the REST API library.
+
+<Tabs>
+<TabItem label="index.js">
+```js title="index.js"
+const postgres = require('postgres');
+const { Cloudflare } = require('cloudflare');
+const { backOff } = require('exponential-backoff');
+
+if(!process.env.DATABASE_CONNECTION_STRING || !process.env.CLOUDFLARE_EMAIL || !process.env.CLOUDFLARE_API_KEY || !process.env.CLOUDFLARE_WORKERS_KV_NAMESPACE_ID || !process.env.CLOUDFLARE_ACCOUNT_ID) {
+	console.error('Missing required environment variables.');
+	process.exit(1);
+}
+
+// Setup Postgres connection
+const sql = postgres(process.env.DATABASE_CONNECTION_STRING);
+
+// Setup Cloudflare REST API client
+const client = new Cloudflare({
+	apiEmail: process.env.CLOUDFLARE_EMAIL,
+	apiKey: process.env.CLOUDFLARE_API_KEY,
+});
+
+// Function to sync Postgres data to Workers KV
+async function syncPreviewStatus() {
+	console.log('Starting sync of user preview status...');
+
+	try {
+		// Get all users and their preview status
+		const users = await sql`SELECT id, preview_features_enabled FROM users`;
+
+		console.log(users);
+
+		// Create the bulk update body
+		const bulkUpdateBody = users.map(user => ({
+			key: user.id,
+			value: JSON.stringify({
+				preview_features_enabled: user.preview_features_enabled
+			})
+		}));
+
+		const response = await backOff(async () => {
+			console.log("trying to update")
+			try{
+				const response = await client.kv.namespaces.bulkUpdate(process.env.CLOUDFLARE_WORKERS_KV_NAMESPACE_ID, {
+					account_id: process.env.CLOUDFLARE_ACCOUNT_ID,
+					body: bulkUpdateBody
+				});
+			}
+			catch(e){
+				// Implement your error handling and logging here
+				console.log(e);
+				throw e; // Rethrow the error to retry
+			}
+		});
+
+		console.log(`Sync complete. Updated ${users.length} users.`);
+	} catch (error) {
+		console.error('Error syncing preview status:', error);
+	}
+}
+
+// Run the sync function
+syncPreviewStatus()
+	.catch(console.error)
+	.finally(() => process.exit(0));
+```
+</TabItem>
+<TabItem label=".env">
+```md title=".env"
+DATABASE_CONNECTION_STRING = <DB_CONNECTION_STRING_HERE>
+CLOUDFLARE_EMAIL = <CLOUDFLARE_EMAIL_HERE>
+CLOUDFLARE_API_KEY = <CLOUDFLARE_API_KEY_HERE>
+CLOUDFLARE_ACCOUNT_ID = <CLOUDFLARE_ACCOUNT_ID_HERE>
+CLOUDFLARE_WORKERS_KV_NAMESPACE_ID = <CLOUDFLARE_WORKERS_KV_NAMESPACE_ID_HERE>
+````
+
+</TabItem>
+<TabItem label="db.sql">
+```sql title="db.sql"
+-- Create users table with preview_features_enabled flag
+CREATE TABLE users (
+  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
+  username VARCHAR(100) NOT NULL,
+  email VARCHAR(255) NOT NULL,
+  preview_features_enabled BOOLEAN DEFAULT false
+);
+
+-- Insert sample users
+INSERT INTO users (username, email, preview_features_enabled) VALUES
+('alice', 'alice@example.com', true),
+('bob', 'bob@example.com', false),
+('charlie', 'charlie@example.com', true);
+
+````
+</TabItem>
+</Tabs>
+
+In this code snippet, the Node.js application reads user data from a Postgres database and writes the user data to be used for configuration in our Workers application to Workers KV using the Cloudflare REST API Node.js library.
+The application also uses exponential backoff to handle retries in case of errors.
+
+## Use configuration data from Workers KV in your Worker application
+
+With the configuration data now in the Workers KV namespace, we can use it in our Workers application to personalize the application for each user.
+
+<Tabs>
+<TabItem label="index.ts">
+```js title="index.ts"
+// Example configuration data stored in Workers KV:
+// Key: "user-id-abc" | Value: {"preview_features_enabled": false}
+// Key: "user-id-def" | Value: {"preview_features_enabled": true}
+
+interface Env {
+  USER_CONFIGURATION: KVNamespace;
+}
+
+export default {
+  async fetch(request, env) {
+    // Get user ID from query parameter
+    const url = new URL(request.url);
+    const userId = url.searchParams.get('userId');
+
+    if (!userId) {
+      return new Response('Please provide a userId query parameter', {
+        status: 400,
+        headers: { 'Content-Type': 'text/plain' }
+      });
+    }
+
+
+		const userConfiguration = await env.USER_CONFIGURATION.get<{
+			preview_features_enabled: boolean;
+		}>(userId, {type: "json"});
+
+		console.log(userConfiguration);
+
+    // Build HTML response
+    const html = `
+      <!DOCTYPE html>
+      <html>
+        <head>
+          <title>My App</title>
+          <style>
+            body {
+              font-family: Arial, sans-serif;
+              max-width: 800px;
+              margin: 0 auto;
+              padding: 20px;
+            }
+            .preview-banner {
+              background-color: #ffeb3b;
+              padding: 10px;
+              text-align: center;
+              margin-bottom: 20px;
+              border-radius: 4px;
+            }
+          </style>
+        </head>
+        <body>
+          ${userConfiguration?.preview_features_enabled ? `
+            <div class="preview-banner">
+              🎉 You have early access to preview features! 🎉
+            </div>
+          ` : ''}
+          <h1>Welcome to My App</h1>
+          <p>This is the regular content everyone sees.</p>
+        </body>
+      </html>
+    `;
+
+    return new Response(html, {
+			headers: { "Content-Type": "text/html; charset=utf-8" }
+    });
+  }
+} satisfies ExportedHandler<Env>;
+
+```
+</TabItem>
+<TabItem label="wrangler.jsonc">
+```json
+{
+	"$schema": "node_modules/wrangler/config-schema.json",
+	"name": "<ENTER_WORKER_NAME>",
+	"main": "src/index.ts",
+	"compatibility_date": "2025-03-03",
+	"observability": {
+		"enabled": true
+	},
+	"kv_namespaces": [
+		{
+			"binding": "USER_CONFIGURATION",
+			"id": "<YOUR_BINDING_ID>"
+		}
+	]
+}
+````
+
+</TabItem>
+</Tabs>
+
+This code will use the path within the URL and find the file associated to the path within the KV store. It also sets the proper MIME type in the response to inform the browser how to handle the response. To retrieve the value from the KV store, this code uses `arrayBuffer` to properly handle binary data such as images, documents, and video/audio files.
+
+## Optimize performance for configuration
+
+To optimize performance, you may opt to consolidate values in fewer key-value pairs. By doing so, you may benefit from higher caching efficiency and lower latency. 
+
+For example, instead of storing each user's configuration in a separate key-value pair, you may store all users' configurations in a single key-value pair. This approach may be suitable for use-cases where the configuration data is small and can be easily managed in a single key-value pair (the [size limit for a Workers KV value is 25 MiB](/kv/platform/limits/)).
+
+## Related resources
+
+- [Rust support in Workers](/workers/languages/rust/)
+- [Using KV in Workers](/kv/get-started/)
diff --git a/src/content/docs/kv/examples/implement-ab-testing-with-workers-kv.mdx b/src/content/docs/kv/examples/implement-ab-testing-with-workers-kv.mdx
new file mode 100644
index 000000000000000..29fcaf903f8df8a
--- /dev/null
+++ b/src/content/docs/kv/examples/implement-ab-testing-with-workers-kv.mdx
@@ -0,0 +1,11 @@
+---
+type: example
+summary: Use Workers KV to store A/B testing configuration data and analyze the performance of different versions of your website
+tags:
+  - KV
+pcx_content_type: configuration
+title: A/B testing with Workers KV
+external_link: /reference-architecture/diagrams/serverless/a-b-testing-using-workers/
+sidebar:
+  order: 6
+---
\ No newline at end of file
diff --git a/src/content/docs/kv/examples/routing-with-workers-kv.mdx b/src/content/docs/kv/examples/routing-with-workers-kv.mdx
new file mode 100644
index 000000000000000..ed6a5339d1871ee
--- /dev/null
+++ b/src/content/docs/kv/examples/routing-with-workers-kv.mdx
@@ -0,0 +1,149 @@
+---
+type: example
+summary: Store routing data in Workers KV to route requests across various web servers with Workers
+tags:
+  - KV
+pcx_content_type: configuration
+title: Route requests across various web servers
+sidebar:
+  order: 5
+description: Example of how to use Workers KV to build a distributed application configuration store.
+---
+
+import { Render, PackageManagers, Tabs, TabItem } from "~/components";
+
+Using Workers KV to store routing data to route requests across various web servers with Workers is an ideal use case for Workers KV. Routing workloads can have high read volume, and Workers KV's low-latency reads can help ensure that routing decisions are made quickly and efficiently.
+
+Routing can be helpful to route requests coming into a single Cloudflare Worker application to different web servers based on the request's path, hostname, or other request attributes.
+
+
+In single-tenant applications, this can be used to route requests to various origin servers based on the business domain (for example, requests to `/admin` routed to administration server, `/store` routed to storefront server, `/api` routed to the API server).
+
+In multi-tenant applications, requests can be routed to the tenant's respective origin resources (for example, requests to `tenantA.your-worker-hostname.com` routed to server for Tenant A, `tenantB.your-worker-hostname.com` routed to server for Tenant B).
+
+Routing can also be used to implement [A/B testing](/reference-architecture/diagrams/serverless/a-b-testing-using-workers/), canary deployments, or blue-green deployments for your own external applications.
+If you are looking to implement canary or blue-green deployments of applications built fully on Cloudflare Workers, see [Workers gradual deployments](/workers/configuration/versions-and-deployments/gradual-deployments/).
+
+## Route requests with Workers KV
+
+In this example, a multi-tenant e-Commerce application is built on Cloudflare Workers. Each storefront is a different tenant and has its own external web server.
+Our Cloudflare Worker is responsible for receiving all requests for all storefronts and routing requests to the correct origin web server according to the storefront ID.
+
+For simplicity of demonstration, the storefront will be identified with a path element containing the storefront ID, where
+`https://<WORKER_HOSTNAME>/<STOREFRONT_ID>/...` is the URL pattern for the storefront. You may prefer to use subdomains to identify storefronts in a real-world scenario.
+
+<Tabs>
+<TabItem label="index.ts">
+```js title="index.ts" collapse={17-22, 34-39, 69-73}
+
+// Example routing data stored in Workers KV:
+// Key: "storefrontA" | Value: {"origin": "https://storefrontA-server.example.com"}
+// Key: "storefrontB" | Value: {"origin": "https://storefrontB-server.example.com"}
+
+interface Env {
+ROUTING_CONFIG: KVNamespace;
+}
+
+export default {
+  async fetch(request, env, ctx) {
+
+    // Parse the URL to extract the storefront ID from the path
+    const url = new URL(request.url);
+    const pathParts = url.pathname.split('/').filter(part => part !== '');
+
+    // Check if a storefront ID is provided in the path, otherwise return 400
+    if (pathParts.length === 0) {
+      return new Response('Welcome to our multi-tenant platform. Please specify a storefront ID in the URL path.', {
+        status: 400,
+        headers: { 'Content-Type': 'text/plain' }
+      });
+    }
+
+    // Extract the storefront ID from the first path segment
+    const storefrontId = pathParts[0];
+
+    try {
+      // Look up the storefront configuration in KV using env.ROUTING_CONFIG
+      const storefrontConfig = await env.ROUTING_CONFIG.get<{
+    			origin: string;
+    		}>(storefrontId, {type: "json"});
+
+      // If no configuration is found, return a 404
+      if (!storefrontConfig) {
+        return new Response(`Storefront "${storefrontId}" not found.`, {
+          status: 404,
+          headers: { 'Content-Type': 'text/plain' }
+        });
+      }
+
+      // Construct the new URL for the origin server
+      // Remove the storefront ID from the path when forwarding
+      const newPathname = '/' + pathParts.slice(1).join('/');
+      const originUrl = new URL(newPathname, storefrontConfig.origin);
+      originUrl.search = url.search;
+
+      // Create a new request to the origin server
+      const originRequest = new Request(originUrl, {
+        method: request.method,
+        headers: request.headers,
+        body: request.body,
+        redirect: 'follow'
+      });
+
+      // Send the request to the origin server
+      const response = await fetch(originRequest);
+
+    		console.log(response.status)
+
+      // Clone the response and add a custom header
+      const modifiedResponse = new Response(response.body, response);
+      modifiedResponse.headers.set('X-Served-By', 'Cloudflare Worker');
+      modifiedResponse.headers.set('X-Storefront-ID', storefrontId);
+
+      return modifiedResponse;
+
+    } catch (error) {
+      // Handle any errors
+      console.error(`Error processing request for storefront ${storefrontId}:`, error);
+      return new Response('An error occurred while processing your request.', {
+        status: 500,
+        headers: { 'Content-Type': 'text/plain' }
+      });
+    }
+
+}
+} satisfies ExportedHandler<Env>;
+
+````
+</TabItem>
+<TabItem label="wrangler.jsonc">
+```json
+{
+	"$schema": "node_modules/wrangler/config-schema.json",
+	"name": "<ENTER_WORKER_NAME>",
+	"main": "src/index.ts",
+	"compatibility_date": "2025-03-03",
+	"observability": {
+		"enabled": true
+	},
+	"kv_namespaces": [
+		{
+			"binding": "ROUTING_CONFIG",
+			"id": "<YOUR_BINDING_ID>"
+		}
+	]
+}
+````
+
+</TabItem>
+</Tabs>
+
+In this example, the Cloudflare Worker receives a request and extracts the storefront ID from the URL path.
+The storefront ID is used to look up the origin server URL from Workers KV using the `get()` method.
+The request is then forwarded to the origin server, and the response is modified to include custom headers before being returned to the client.
+
+
+## Related resources
+
+- [Rust support in Workers](/workers/languages/rust/).
+- [Using KV in Workers](/kv/get-started/).
diff --git a/src/content/docs/kv/examples/workers-kv-to-serve-assets.mdx b/src/content/docs/kv/examples/workers-kv-to-serve-assets.mdx
index 4d65807da018faa..293d300879fa596 100644
--- a/src/content/docs/kv/examples/workers-kv-to-serve-assets.mdx
+++ b/src/content/docs/kv/examples/workers-kv-to-serve-assets.mdx
@@ -1,14 +1,16 @@
 ---
 type: example
-summary: Store and retrieve static assets with Workers KV
+summary: Store static assets in Workers KV and serve them from a Worker application with low-latency and high-throughput
+tags:
+  - KV
 pcx_content_type: configuration
-title: Store and retrieve static assets with Workers KV
+title: Store and retrieve static assets
 sidebar:
   order: 4
 description: Example of how to use Workers KV to store static assets
 ---
 
-import { Render, PackageManagers } from "~/components";
+import { Render, PackageManagers, TabItem, Tabs } from "~/components";
 
 By storing static assets in Workers KV, you can retrieve these assets globally with low-latency and high throughput. You can then serve these assets directly, or use them to dynamically generate responses. This can be useful when serving files and images, or when generating dynamic HTML responses from static assets such as translations.
 
@@ -16,117 +18,13 @@ By storing static assets in Workers KV, you can retrieve these assets globally w
 With [Workers KV](/kv), you can access, edit and store assets directly from your [Worker](/workers). If you need to serve assets as part of a front-end or full-stack web application, consider using [Cloudflare Pages](/pages/) or [Workers static assets](/workers/static-assets/), which provide a purpose-built deployment experience for web applications and their assets.
 :::
 
-<Render file="tutorials-before-you-start" product="workers" />
+## Write static assets to Workers KV using Wrangler
 
-## 1. Create a new Worker application
+To store static assets in Workers KV, you can use the [Wrangler CLI](/workers/wrangler/) (commonly used during development), the [Workers KV binding](/kv/concepts/kv-bindings/) from a Workers application, or the [Workers KV REST API](/api/resources/kv/subresources/namespaces/methods/list/) (commonly used to access Workers KV from an external application). We will demonstrate how to use the Wrangler CLI.
 
-To get started, create a Worker application using the [`create-cloudflare` CLI](https://github.com/cloudflare/workers-sdk/tree/main/packages/create-cloudflare). Open a terminal window and run the following command:
+For this scenario, we will store a sample HTML file within our Workers KV store.
 
-<PackageManagers
-	type="create"
-	pkg="cloudflare@latest"
-	args={"example-kv-assets"}
-/>
-
-<Render
-	file="c3-post-run-steps"
-	product="workers"
-	params={{
-		category: "hello-world",
-		type: "Worker only",
-		lang: "TypeScript",
-	}}
-/>
-
-Then, move into your newly created application
-
-```sh
-cd example-kv-assets
-```
-
-We'll also install the dependencies we will need for this project.
-
-```sh
-npm install mime accept-language-parser
-npm install --save-dev @types/accept-language-parser
-```
-
-## 2. Create a new KV namespace
-
-Next, we will create a KV store. This can be done through the Cloudflare dashboard or the Wrangler CLI. For this example, we will use the Wrangler CLI.
-
-To create a KV store via Wrangler:
-
-1. Open your terminal and run the following command:
-
-   ```sh
-   npx wrangler kv namespace create assets
-   ```
-
-   The `wrangler kv namespace create assets` subcommand creates a KV namespace by concatenating your Worker's name and the value provided for `assets`. An `id` will be randomly generated for the KV namespace.
-
-   ```sh
-   npx wrangler kv namespace create assets
-   ```
-
-   ```sh {6} output
-   🌀 Creating namespace with title "example-kv-assets-assets"
-   ✨ Success!
-   Add the following to your configuration file in your kv_namespaces array:
-   [[kv_namespaces]]
-   binding = "assets"
-   id = "<GENERATED_NAMESPACE_ID>"
-   ```
-
-2. In your Wrangler file, add the following with the values generated in the terminal:
-
-   ```bash {3} title="wrangler.toml"
-   [[kv_namespaces]]
-   binding = "assets"
-   id = "<GENERATED_NAMESPACE_ID>"
-   ```
-
-   The [KV binding](/kv/concepts/kv-bindings/) `assets` is how your Worker will interact with the [KV namespace](/kv/concepts/kv-namespaces/). This binding will be provided as a runtime variable within your Workers code by the Workers runtime.
-
-   We'll also create a preview KV namespace. It is recommended to create a separate KV namespace when developing locally to avoid making changes to the production namespace. When developing locally against remote resources, the Wrangler CLI will only use the namespace specified by `preview_id` in the KV namespace configuration of the Wrangler file.
-
-3. In your terminal, run the following command:
-
-   ```sh
-   npx wrangler kv namespace create assets --preview
-   ```
-
-   This command will create a special KV namespace that will be used only when developing with Wrangler against remote resources using `wrangler dev --remote`.
-
-   ```sh
-   npx wrangler kv namespace create assets --preview
-   ```
-
-   ```sh {6} output
-   🌀 Creating namespace with title "example-kv-assets-assets_preview"
-   ✨ Success!
-   Add the following to your configuration file in your kv_namespaces array:
-   [[kv_namespaces]]
-   binding = "assets"
-   preview_id = "<GENERATED_PREVIEW_NAMESPACE_ID>"
-   ```
-
-4. In your Wrangler file, add the additional preview_id below kv_namespaces with the values generated in the terminal:
-
-   ```bash {4} title="wrangler.toml"
-   [[kv_namespaces]]
-   binding = "assets"
-   id = "<GENERATED_NAMESPACE_ID>"
-   preview_id = "<GENERATED_PREVIEW_NAMESPACE_ID>"
-   ```
-
-We now have one KV binding that will use the production KV namespace when deployed and the preview KV namespace when developing locally against remote resources with `wrangler dev --remote`.
-
-## 3. Store static assets in KV using Wrangler
-
-To store static assets in KV, you can use the Wrangler CLI, the KV binding from a Worker application, or the KV REST API. We'll demonstrate how to use the Wrangler CLI.
-
-For this scenario, we'll be storing a sample HTML file within our KV store. Create a new file `index.html` in the root of project with the following content:
+Create a new file `index.html` with the following content:
 
 ```html title="index.html"
 Hello World!
@@ -135,94 +33,106 @@ Hello World!
 We can then use the following Wrangler commands to create a KV pair for this file within our production and preview namespaces:
 
 ```sh
-npx wrangler kv key put index.html --path index.html --binding assets --preview false
-npx wrangler kv key put index.html --path index.html --binding assets --preview
+npx wrangler kv key put index.html --path index.html --namespace-id=<ENTER_NAMESPACE_ID_HERE>
 ```
 
 This will create a KV pair with the filename as key and the file content as value, within the our production and preview namespaces specified by your binding in your Wrangler file.
 
-## 4. Serve static assets from KV from your Worker application
+## Serve static assets from KV from your Worker application
 
-Within the `index.ts` file of our Worker project, replace the contents with the following:
+In this example, our Workers application will accept any key name as the path of the HTTP request and return the value stored in the KV store for that key.
 
-```js title="index.ts"
+<Tabs>
+<TabItem label="index.ts">
+```js
 
-import mime from 'mime';
+import mime from "mime";
 
 interface Env {
-	assets: KVNamespace;
+assets: KVNamespace;
 }
 
 export default {
 	async fetch(request, env, ctx): Promise<Response> {
-		//return error if not a get request
+		// Return error if not a get request
 		if(request.method !== 'GET'){
 			return new Response('Method Not Allowed', {
 				status: 405,
 			})
 		}
 
-		//get the key from the url & return error if key missing
-		const parsedUrl = new URL(request.url)
-		const key = parsedUrl.pathname.replace(/^\/+/, '') // strip any preceding /'s
-		if(!key){
-			return new Response('Missing path in URL', {
-				status: 400
-			})
-		}
-
-		//get the mimetype from the key path
-		const extension = key.split('.').pop();
-		let mimeType = mime.getType(key) || "text/plain";
-		if (mimeType.startsWith("text") || mimeType === "application/javascript") {
-			mimeType += "; charset=utf-8";
-		}
+    	// Get the key from the url & return error if key missing
+    	const parsedUrl = new URL(request.url)
+    	const key = parsedUrl.pathname.replace(/^\/+/, '') // Strip any preceding /'s
+    	if(!key){
+    		return new Response('Missing path in URL', {
+    			status: 400
+    		})
+    	}
+
+    	// Get the mimetype from the key path
+    	const extension = key.split('.').pop();
+    	let mimeType = mime.getType(key) || "text/plain";
+    	if (mimeType.startsWith("text") || mimeType === "application/javascript") {
+    		mimeType += "; charset=utf-8";
+    	}
+
+    	// Get the value from the Workers KV store and return it if found
+    	const value = await env.assets.get(key, 'arrayBuffer')
+    	if(!value){
+    		return new Response("Not found", {
+    			status: 404
+    		})
+    	}
+
+    	// Return the response from the Workers application with the value from the KV store
+    	return new Response(value, {
+    		status: 200,
+    		headers: new Headers({
+    			"Content-Type": mimeType
+    		})
+    	});
+    },
 
-		//get the value from the KV store and return it if found
-		const value = await env.assets.get(key, 'arrayBuffer')
-		if(!value){
-			return new Response("Not found", {
-				status: 404
-			})
-		}
-		return new Response(value, {
-			status: 200,
-			headers: new Headers({
-				"Content-Type": mimeType
-			})
-		});
-	},
 } satisfies ExportedHandler<Env>;
-```
 
-This code will use the path within the URL and find the file associated to the path within the KV store. It also sets the proper MIME type in the response to indicate to the browser how to handle the response. To retrieve the value from the KV store, this code uses `arrayBuffer` to properly handle binary data such as images, documents, and video/audio files.
-
-To start the Worker, run the following within a terminal:
-
-```sh
-npx wrangler dev --remote
-```
+````
+</TabItem>
+<TabItem label="wrangler.jsonc">
+```json
+{
+	"$schema": "node_modules/wrangler/config-schema.json",
+	"name": "<ENTER_WORKER_NAME>",
+	"main": "src/index.ts",
+	"compatibility_date": "2025-03-03",
+	"observability": {
+		"enabled": true
+	},
+	"kv_namespaces": [
+		{
+			"binding": "assets",
+			"id": "<YOUR_BINDING_ID>"
+		}
+	]
+}
+````
 
-This will run you Worker code against your remote resources, specifically using the preview KV namespace as configured.
+</TabItem>
+</Tabs>
 
-```sh
-npx wrangler dev --remote
-```
+This code parses the key name for the key-value pair to fetch from the HTTP request. Then, it determines the proper MIME type for the response to inform the browser how to handle the response.
+To retrieve the value from the KV store, this code uses `arrayBuffer` to properly handle binary data such as images, documents, and video/audio files.
 
-```sh output
-Your worker has access to the following bindings:
-- KV Namespaces:
-  - assets: <GENERATED_PREVIEW_NAMESPACE_ID>
-[wrangler:inf] Ready on http://localhost:<PORT>
-```
+Given a sample key-value pair with key `index.html` with value containing some HTML content in our Workers KV namespace store, we can access our Workers application
+at `https://<YOUR-WORKER-HOSTNAME>/index.html` to see the contents of the `index.html` file.
 
-Access the URL provided by the Wrangler command as such `http://localhost:<PORT>/index.html`. You will be able to see the returned HTML file containing the file contents of our `index.html` file that was added to our KV store. Try it out with an image or a document and you will see that this Worker is also properly serving those assets from KV.
+Try it out with an image or a document and you will see that this Worker is also properly serving those assets from KV.
 
-## 5. Create an endpoint to generate dynamic responses from your key-value pairs
+## Generate dynamic responses from your key-value pairs
 
-We'll add a `hello-world` endpoint to our Workers application, which will return a "Hello World!" message based on the language requested to demonstrate how to generate a dynamic response from our KV-stored assets.
+In addition to serving static assets, we can also generate dynamic HTML or API responses based on the values stored in our KV store.
 
-Start by creating this file in the root of your project:
+1. Start by creating this file in the root of your project:
 
 ```json title="hello-world.json"
 [
@@ -261,123 +171,136 @@ Start by creating this file in the root of your project:
 ]
 ```
 
-Open a terminal and enter the following KV command to create a KV entry for the translations file:
+2. Open a terminal and enter the following KV command to create a KV entry for the translations file:
 
 ```sh
-npx wrangler kv key put hello-world.json --path hello-world.json --binding assets --preview false
-npx wrangler kv key put hello-world.json --path hello-world.json --binding assets --preview
+npx wrangler kv key put hello-world.json --path hello-world.json --namespace-id=<ENTER_NAMESPACE_ID_HERE>
 ```
 
-Update your Workers code to add logic to serve a translated HTML file based on the language of the Accept-Language header of the request:
+3. Update your Workers code to add logic to serve a translated HTML file based on the language of the Accept-Language header of the request:
 
-```js {2, 26-63} title="index.ts"
+<Tabs>
+<TabItem label="index.ts">
+```js {2, 26-63}
 import mime from 'mime';
 import parser from 'accept-language-parser'
 
 interface Env {
-	assets: KVNamespace;
+assets: KVNamespace;
 }
 
 export default {
-	async fetch(request, env, ctx): Promise<Response> {
-		//return error if not a get request
-		if(request.method !== 'GET'){
-			return new Response('Method Not Allowed', {
-				status: 405,
-			})
-		}
-
-		//get the key from the url & return error if key missing
-		const parsedUrl = new URL(request.url)
-		const key = parsedUrl.pathname.replace(/^\/+/, '') // strip any preceding /'s
-		if(!key){
-			return new Response('Missing path in URL', {
-				status: 400
-			})
-		}
-
-		//add handler for translation path
-		if(key === 'hello-world'){
-			//retrieve the language header from the request and the translations from KV
-			const languageHeader = request.headers.get('Accept-Language') || 'en'//default to english
-			const translations : {
-				"language_code": string,
-				"message": string
-			}[] = await env.assets.get('hello-world.json', 'json') || [];
-
-			//extract the requested language
-			const supportedLanguageCodes = translations.map(item => item.language_code)
-			const languageCode = parser.pick(supportedLanguageCodes, languageHeader, {
-				loose: true
-			})
+  async fetch(request, env, ctx): Promise<Response> {
+    // Return error if not a get request
+    if(request.method !== 'GET'){
+      return new Response('Method Not Allowed', {
+        status: 405,
+      })
+    }
+
+    // Get the key from the url & return error if key missing
+    const parsedUrl = new URL(request.url)
+    const key = parsedUrl.pathname.replace(/^\/+/, '') // Strip any preceding /'s
+    if(!key){
+      return new Response('Missing path in URL', {
+        status: 400
+      })
+    }
+
+    	// Add handler for translation path (with early return)
+    	if(key === 'hello-world'){
+    		// Retrieve the language header from the request and the translations from Workers KV
+    		const languageHeader = request.headers.get('Accept-Language') || 'en' // Default to English
+    		const translations : {
+    			"language_code": string,
+    			"message": string
+    		}[] = await env.assets.get('hello-world.json', 'json') || [];
+
+    		// Extract the requested language
+    		const supportedLanguageCodes = translations.map(item => item.language_code)
+    		const languageCode = parser.pick(supportedLanguageCodes, languageHeader, {
+    			loose: true
+    		})
+
+    		// Get the message for the selected language
+    		let selectedTranslation = translations.find(item => item.language_code === languageCode)
+    		if(!selectedTranslation) selectedTranslation = translations.find(item => item.language_code === "en")
+    		const helloWorldTranslated = selectedTranslation!['message'];
+
+    		// Generate and return the translated html
+    		const html = `<!DOCTYPE html>
+    		<html>
+    			<head>
+    				<title>Hello World translation</title>
+    			</head>
+    			<body>
+    				<h1>${helloWorldTranslated}</h1>
+    			</body>
+    		</html>
+    		`
+    		return new Response(html, {
+    			status: 200,
+    			headers: {
+    				'Content-Type': 'text/html; charset=utf-8'
+    			}
+    		})
+    	}
+
+    // Get the mimetype from the key path
+    const extension = key.split('.').pop();
+    let mimeType = mime.getType(key) || "text/plain";
+    if (mimeType.startsWith("text") || mimeType === "application/javascript") {
+      mimeType += "; charset=utf-8";
+    }
+
+    // Get the value from the Workers KV store and return it if found
+    const value = await env.assets.get(key, 'arrayBuffer')
+    if(!value){
+      return new Response("Not found", {
+        status: 404
+      })
+    }
+
+    // Return the response from the Workers application with the value from the KV store
+    return new Response(value, {
+      status: 200,
+      headers: new Headers({
+        "Content-Type": mimeType
+      })
+    });
+
+},
+} satisfies ExportedHandler<Env>;
 
-			//get the message for the selected language
-			let selectedTranslation = translations.find(item => item.language_code === languageCode)
-			if(!selectedTranslation) selectedTranslation = translations.find(item => item.language_code === "en")
-			const helloWorldTranslated = selectedTranslation!['message'];
-
-			//generate and return the translated html
-			const html = `<!DOCTYPE html>
-			<html>
-				<head>
-					<title>Hello World translation</title>
-				</head>
-				<body>
-					<h1>${helloWorldTranslated}</h1>
-				</body>
-			</html>
-			`
-			return new Response(html, {
-				status: 200,
-				headers: {
-					'Content-Type': 'text/html; charset=utf-8'
-				}
-			})
+````
+</TabItem>
+<TabItem label="wrangler.jsonc">
+```json
+{
+	"$schema": "node_modules/wrangler/config-schema.json",
+	"name": "<ENTER_WORKER_NAME>",
+	"main": "src/index.ts",
+	"compatibility_date": "2025-03-03",
+	"observability": {
+		"enabled": true
+	},
+	"kv_namespaces": [
+		{
+			"binding": "assets",
+			"id": "<YOUR_BINDING_ID>"
 		}
+	]
+}
+````
 
-		//get the mimetype from the key path
-		const extension = key.split('.').pop();
-		let mimeType = mime.getType(key) || "text/plain";
-		if (mimeType.startsWith("text") || mimeType === "application/javascript") {
-			mimeType += "; charset=utf-8";
-		}
-
-		//get the value from the KV store and return it if found
-		const value = await env.assets.get(key, 'arrayBuffer')
-		if(!value){
-			return new Response("Not found", {
-				status: 404
-			})
-		}
-		return new Response(value, {
-			status: 200,
-			headers: new Headers({
-				"Content-Type": mimeType
-			})
-		});
-	},
-} satisfies ExportedHandler<Env>;
-```
+</TabItem>
+</Tabs>
 
 This new code provides a specific endpoint, `/hello-world`, which will provide translated responses. When this URL is accessed, our Worker code will first retrieve the language that is requested by the client in the `Accept-Language` request header and the translations from our KV store for the `hello-world.json` key. It then gets the translated message and returns the generated HTML.
 
-```sh
-npx wrangler dev --remote
-```
-
-With the Worker code running, we can notice that our application is now returning the properly translated "Hello World" message. From your browser's developer console, change the locale language (on Chromium browsers, Run `Show Sensors` to get a dropdown selection for locales).
-
-## 6. Deploy your project
-
-Run `wrangler deploy` to deploy your Workers project to Cloudflare with the binding to the KV namespace.
-
-```sh
-npx wrangler deploy
-```
-
-Wrangler will automatically set your KV binding to use the production KV namespace set in our Wrangler file with the KV namespace id. Throughout this example, we uploaded our assets to both the preview and the production KV namespaces.
+When accessing the Worker application at `https://<YOUR-WORKER-HOSTNAME>/hello-world`, we can notice that our application is now returning the properly translated "Hello World" message.
 
-We can now verify that our project is properly working by accessing our Workers default hostname and accessing `<WORKER-SUBDOMAIN>.<DEFAULT-ACCOUNT-HOSTNAME>.dev/index.html` or `<WORKER-SUBDOMAIN>.<DEFAULT-ACCOUNT-HOSTNAME>.dev/hello-world` to see our deployed Worker in action, generating responses from the values in our KV store.
+From your browser's developer console, change the locale language (on Chromium browsers, Run `Show Sensors` to get a dropdown selection for locales). You will see that the Worker is now returning the translated message based on the locale language.
 
 ## Related resources
 
diff --git a/src/content/docs/kv/index.mdx b/src/content/docs/kv/index.mdx
index 6ee4bfae4187a53..f9a01220d632180 100644
--- a/src/content/docs/kv/index.mdx
+++ b/src/content/docs/kv/index.mdx
@@ -72,7 +72,7 @@ export default {
 ```json
 {
 	"$schema": "node_modules/wrangler/config-schema.json",
-	"name": "WORKER-NAME",
+	"name": "<ENTER_WORKER_NAME>",
 	"main": "src/index.ts",
 	"compatibility_date": "2025-02-04",
 	"observability": {
diff --git a/src/content/docs/reference-architecture/diagrams/serverless/a-b-testing-using-workers.mdx b/src/content/docs/reference-architecture/diagrams/serverless/a-b-testing-using-workers.mdx
index 503fb21b445cca0..baaa2d8ea26b696 100644
--- a/src/content/docs/reference-architecture/diagrams/serverless/a-b-testing-using-workers.mdx
+++ b/src/content/docs/reference-architecture/diagrams/serverless/a-b-testing-using-workers.mdx
@@ -35,8 +35,11 @@ This architecture shows a same-URL A/B testing endpoint. The A/B testing logic a
 3. **Origin requests**: Check for already existing cookies in the request headers. If no cookie for group assignment is set, randomly assign a group. If a cookie is set, extract assigned group from the cookie header. Send request to either the control endpoint (A) or variant endpoints (B) depending on the configuration and the assigned group.
 4. **Response**: Return the response from the origin. Additionally, if no cookie was previously set, set a cookie with the respective assigned group for session affinity.
 
+For an example with code snippets on how to use Workers and Workers KV to route requests to different origin web servers, refer to Workers KV's example on [routing across web servers](/kv/examples/routing-with-workers-kv/).
+
 ## Related resources
 
 - [Workers: Get started](/workers/get-started/guide/)
-- [KV: Get started](/kv/get-started/)
+- [Workers KV: Get started](/kv/get-started/)
+- [Workers KV: Route requests to web servers with Workers and Workers KV](/kv/examples/routing-with-workers-kv/)
 - [Code Example: A/B testing with same-URL direct access](/workers/examples/ab-testing/)


Reviews:
user: login: Oxyjun
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T13:50:26Z
user: login: Oxyjun
body: PCX review
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T13:53:39Z
user: login: Oxyjun
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T14:02:22Z
user: login: thomasgauvin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T14:30:52Z
user: login: hyperlint-ai-deprecated[bot]
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-13T20:57:15Z
user: login: thomasgauvin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-14T14:41:14Z
user: login: thomasgauvin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-14T17:11:55Z
user: login: thomasgauvin
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-14T17:12:22Z

Review comments:
diff_hunk: @@ -0,0 +1,134 @@
+---
+type: example
+summary: Cache data or API responses in Workers KV to improve application performance
+tags:
+  - KV
+pcx_content_type: configuration
+title: Cache data with Workers KV
+sidebar:
+  order: 5
+description: Example of how to use Workers KV to build a distributed application configuration store.
+---
+
+import { Render, PackageManagers, Tabs, TabItem } from "~/components";
+
+Workers KV can be used as a persistent, single, global cache accessible from Cloudflare Workers to speed up your application.
+Data cached in Workers KV will be accessible from all other Cloudflare locations as well and will be persisted until expiry or deletion.
path: src/content/docs/kv/examples/cache-data-with-workers-kv.mdx
user: login: Oxyjun
body: ```suggestion
Data cached in Workers KV is accessible from all other Cloudflare locations as well, and persists until expiry or deletion.
```
created_at: 2025-03-10T10:43:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,134 @@
+---
+type: example
+summary: Cache data or API responses in Workers KV to improve application performance
+tags:
+  - KV
+pcx_content_type: configuration
+title: Cache data with Workers KV
+sidebar:
+  order: 5
+description: Example of how to use Workers KV to build a distributed application configuration store.
+---
+
+import { Render, PackageManagers, Tabs, TabItem } from "~/components";
+
+Workers KV can be used as a persistent, single, global cache accessible from Cloudflare Workers to speed up your application.
+Data cached in Workers KV will be accessible from all other Cloudflare locations as well and will be persisted until expiry or deletion.
+
+After fetching data from external resources in your Workers application, you can write the data to Workers KV.
+On subsequent Worker requests (in the same region or in other regions), you can read the cached data from Workers KV instead of calling the external API.
+This improves your Worker application's performance and resilience while reducing load on the external resource.
path: src/content/docs/kv/examples/cache-data-with-workers-kv.mdx
user: login: Oxyjun
body: ```suggestion
This improves your Worker application's performance and resilience while reducing load on external resources.
```
created_at: 2025-03-10T10:45:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,239 @@
+---
+type: example
+summary: Use Workers KV to as a geo-distributed, low-latency configuration store for your Workers application
+tags:
+  - KV
+pcx_content_type: configuration
+title: Build a distributed configuration store
+sidebar:
+  order: 5
+description: Example of how to use Workers KV to build a distributed application configuration store.
+---
+
+import { Render, PackageManagers, Tabs, TabItem } from "~/components";
+
+Storing application configuration data is an ideal use case for Workers KV. Configuration data can include data to personalize an application for each user or tenant, enable features for user groups, restrict access with allow-lists/deny-lists, etc. These use-cases can have high read volumes that are highly cacheable by Workers KV, which can ensure low-latency reads from your Workers application.
+
+In this example, application configuration data is used to personalize the Workers application for each user. The configuration data is stored in an external application and database and written to Workers KV using the REST API.
path: src/content/docs/kv/examples/distributed-configuration-with-workers-kv.mdx
user: login: Oxyjun
body: ```suggestion
In this example, application configuration data is used to personalize the Workers application for each user. The configuration data is stored in an external application and database, and written to Workers KV using the REST API.
```
created_at: 2025-03-10T11:34:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,239 @@
+---
+type: example
+summary: Use Workers KV to as a geo-distributed, low-latency configuration store for your Workers application
+tags:
+  - KV
+pcx_content_type: configuration
+title: Build a distributed configuration store
+sidebar:
+  order: 5
+description: Example of how to use Workers KV to build a distributed application configuration store.
+---
+
+import { Render, PackageManagers, Tabs, TabItem } from "~/components";
+
+Storing application configuration data is an ideal use case for Workers KV. Configuration data can include data to personalize an application for each user or tenant, enable features for user groups, restrict access with allow-lists/deny-lists, etc. These use-cases can have high read volumes that are highly cacheable by Workers KV, which can ensure low-latency reads from your Workers application.
+
+In this example, application configuration data is used to personalize the Workers application for each user. The configuration data is stored in an external application and database and written to Workers KV using the REST API.
+
+## Write your configuration from your external application to Workers KV
+
+In some cases, your source-of-truth for your configuration data may be stored elsewhere than Workers KV.
+If this is the case, use the Workers KV REST API to write the configuration data to your Workers KV namespace. You may also
path: src/content/docs/kv/examples/distributed-configuration-with-workers-kv.mdx
user: login: Oxyjun
body: Incomplete sentence
created_at: 2025-03-10T11:39:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,239 @@
+---
+type: example
+summary: Use Workers KV to as a geo-distributed, low-latency configuration store for your Workers application
+tags:
+  - KV
+pcx_content_type: configuration
+title: Build a distributed configuration store
+sidebar:
+  order: 5
+description: Example of how to use Workers KV to build a distributed application configuration store.
+---
+
+import { Render, PackageManagers, Tabs, TabItem } from "~/components";
+
+Storing application configuration data is an ideal use case for Workers KV. Configuration data can include data to personalize an application for each user or tenant, enable features for user groups, restrict access with allow-lists/deny-lists, etc. These use-cases can have high read volumes that are highly cacheable by Workers KV, which can ensure low-latency reads from your Workers application.
+
+In this example, application configuration data is used to personalize the Workers application for each user. The configuration data is stored in an external application and database and written to Workers KV using the REST API.
+
+## Write your configuration from your external application to Workers KV
+
+In some cases, your source-of-truth for your configuration data may be stored elsewhere than Workers KV.
+If this is the case, use the Workers KV REST API to write the configuration data to your Workers KV namespace. You may also
+
+The following external Node.js application demonstrates a simple scripts that reads user data from a database and writes it to Workers KV using the REST API library.
+
+<Tabs>
+<TabItem label="index.js">
+```js title="index.js"
+const postgres = require('postgres');
+const { Cloudflare } = require('cloudflare');
+const { backOff } = require('exponential-backoff');
+
+if(!process.env.DATABASE_CONNECTION_STRING || !process.env.CLOUDFLARE_EMAIL || !process.env.CLOUDFLARE_API_KEY || !process.env.CLOUDFLARE_WORKERS_KV_NAMESPACE_ID || !process.env.CLOUDFLARE_ACCOUNT_ID) {
+	console.error('Missing required environment variables.');
+	process.exit(1);
+}
+
+// Setup Postgres connection
+const sql = postgres(process.env.DATABASE_CONNECTION_STRING);
+
+// Setup Cloudflare REST API client
+const client = new Cloudflare({
+	apiEmail: process.env.CLOUDFLARE_EMAIL,
+	apiKey: process.env.CLOUDFLARE_API_KEY,
+});
+
+// Function to sync Postgres data to Workers KV
+async function syncPreviewStatus() {
+	console.log('Starting sync of user preview status...');
+
+	try {
+		// Get all users and their preview status
+		const users = await sql`SELECT id, preview_features_enabled FROM users`;
+
+		console.log(users);
+
+		// Create the bulk update body
+		const bulkUpdateBody = users.map(user => ({
+			key: user.id,
+			value: JSON.stringify({
+				preview_features_enabled: user.preview_features_enabled
+			})
+		}));
+
+		const response = await backOff(async () => {
+			console.log("trying to update")
+			try{
+				const response = await client.kv.namespaces.bulkUpdate(process.env.CLOUDFLARE_WORKERS_KV_NAMESPACE_ID, {
+					account_id: process.env.CLOUDFLARE_ACCOUNT_ID,
+					body: bulkUpdateBody
+				});
+			}
+			catch(e){
+				// Implement your error handling and logging here
+				console.log(e);
+				throw e; // Rethrow the error to retry
+			}
+		});
+
+		console.log(`Sync complete. Updated ${users.length} users.`);
+	} catch (error) {
+		console.error('Error syncing preview status:', error);
+	}
+}
+
+// Run the sync function
+syncPreviewStatus()
+	.catch(console.error)
+	.finally(() => process.exit(0));
+```
+</TabItem>
+<TabItem label=".env">
+```md title=".env"
+DATABASE_CONNECTION_STRING = <DB_CONNECTION_STRING_HERE>
+CLOUDFLARE_EMAIL = <CLOUDFLARE_EMAIL_HERE>
+CLOUDFLARE_API_KEY = <CLOUDFLARE_API_KEY_HERE>
+CLOUDFLARE_ACCOUNT_ID = <CLOUDFLARE_ACCOUNT_ID_HERE>
+CLOUDFLARE_WORKERS_KV_NAMESPACE_ID = <CLOUDFLARE_WORKERS_KV_NAMESPACE_ID_HERE>
+````
+
+</TabItem>
+<TabItem label="db.sql">
+```sql title="db.sql"
+-- Create users table with preview_features_enabled flag
+CREATE TABLE users (
+  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
+  username VARCHAR(100) NOT NULL,
+  email VARCHAR(255) NOT NULL,
+  preview_features_enabled BOOLEAN DEFAULT false
+);
+
+-- Insert sample users
+INSERT INTO users (username, email, preview_features_enabled) VALUES
+('alice', 'alice@example.com', true),
+('bob', 'bob@example.com', false),
+('charlie', 'charlie@example.com', true);
+
+````
+</TabItem>
+</Tabs>
+
+In this code snippet, the Node.js application reads user data from a Postgres database and writes the user data to be used for configuration in our Workers application to Workers KV using the Cloudflare REST API Node.js library.
+The application also uses exponential backoff to handle retries in case of errors.
+
+## Use configuration data from Workers KV in your Worker application
+
+With the configuration data now in the Workers KV namespace, we can use it in our Workers application to personalize the application for each user.
+
+<Tabs>
+<TabItem label="index.ts">
+```js title="index.ts"
+// Example configuration data stored in Workers KV:
+// Key: "user-id-abc" | Value: {"preview_features_enabled": false}
+// Key: "user-id-def" | Value: {"preview_features_enabled": true}
+
+interface Env {
+  USER_CONFIGURATION: KVNamespace;
+}
+
+export default {
+  async fetch(request, env) {
+    // Get user ID from query parameter
+    const url = new URL(request.url);
+    const userId = url.searchParams.get('userId');
+
+    if (!userId) {
+      return new Response('Please provide a userId query parameter', {
+        status: 400,
+        headers: { 'Content-Type': 'text/plain' }
+      });
+    }
+
+
+		const userConfiguration = await env.USER_CONFIGURATION.get<{
+			preview_features_enabled: boolean;
+		}>(userId, {type: "json"});
+
+		console.log(userConfiguration);
+
+    // Build HTML response
+    const html = `
+      <!DOCTYPE html>
+      <html>
+        <head>
+          <title>My App</title>
+          <style>
+            body {
+              font-family: Arial, sans-serif;
+              max-width: 800px;
+              margin: 0 auto;
+              padding: 20px;
+            }
+            .preview-banner {
+              background-color: #ffeb3b;
+              padding: 10px;
+              text-align: center;
+              margin-bottom: 20px;
+              border-radius: 4px;
+            }
+          </style>
+        </head>
+        <body>
+          ${userConfiguration?.preview_features_enabled ? `
+            <div class="preview-banner">
+              🎉 You have early access to preview features! 🎉
+            </div>
+          ` : ''}
+          <h1>Welcome to My App</h1>
+          <p>This is the regular content everyone sees.</p>
+        </body>
+      </html>
+    `;
+
+    return new Response(html, {
+			headers: { "Content-Type": "text/html; charset=utf-8" }
+    });
+  }
+} satisfies ExportedHandler<Env>;
+
+```
+</TabItem>
+<TabItem label="wrangler.jsonc">
+```json
+{
+	"$schema": "node_modules/wrangler/config-schema.json",
+	"name": "<ENTER_WORKER_NAME>",
+	"main": "src/index.ts",
+	"compatibility_date": "2025-03-03",
+	"observability": {
+		"enabled": true
+	},
+	"kv_namespaces": [
+		{
+			"binding": "USER_CONFIGURATION",
+			"id": "<YOUR_BINDING_ID>"
+		}
+	]
+}
+````
+
+</TabItem>
+</Tabs>
+
+This code will use the path within the URL and find the file associated to the path within the KV store. It also sets the proper MIME type in the response to indicate to the browser how to handle the response. To retrieve the value from the KV store, this code uses `arrayBuffer` to properly handle binary data such as images, documents, and video/audio files.
path: src/content/docs/kv/examples/distributed-configuration-with-workers-kv.mdx
user: login: Oxyjun
body: ```suggestion
This code will use the path within the URL and find the file associated to the path within the KV store. It also sets the proper MIME type in the response to inform the browser how to handle the response. To retrieve the value from the KV store, this code uses `arrayBuffer` to properly handle binary data such as images, documents, and video/audio files.
```
created_at: 2025-03-10T13:05:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,239 @@
+---
+type: example
+summary: Use Workers KV to as a geo-distributed, low-latency configuration store for your Workers application
+tags:
+  - KV
+pcx_content_type: configuration
+title: Build a distributed configuration store
+sidebar:
+  order: 5
+description: Example of how to use Workers KV to build a distributed application configuration store.
+---
+
+import { Render, PackageManagers, Tabs, TabItem } from "~/components";
+
+Storing application configuration data is an ideal use case for Workers KV. Configuration data can include data to personalize an application for each user or tenant, enable features for user groups, restrict access with allow-lists/deny-lists, etc. These use-cases can have high read volumes that are highly cacheable by Workers KV, which can ensure low-latency reads from your Workers application.
+
+In this example, application configuration data is used to personalize the Workers application for each user. The configuration data is stored in an external application and database and written to Workers KV using the REST API.
+
+## Write your configuration from your external application to Workers KV
+
+In some cases, your source-of-truth for your configuration data may be stored elsewhere than Workers KV.
+If this is the case, use the Workers KV REST API to write the configuration data to your Workers KV namespace. You may also
+
+The following external Node.js application demonstrates a simple scripts that reads user data from a database and writes it to Workers KV using the REST API library.
+
+<Tabs>
+<TabItem label="index.js">
+```js title="index.js"
+const postgres = require('postgres');
+const { Cloudflare } = require('cloudflare');
+const { backOff } = require('exponential-backoff');
+
+if(!process.env.DATABASE_CONNECTION_STRING || !process.env.CLOUDFLARE_EMAIL || !process.env.CLOUDFLARE_API_KEY || !process.env.CLOUDFLARE_WORKERS_KV_NAMESPACE_ID || !process.env.CLOUDFLARE_ACCOUNT_ID) {
+	console.error('Missing required environment variables.');
+	process.exit(1);
+}
+
+// Setup Postgres connection
+const sql = postgres(process.env.DATABASE_CONNECTION_STRING);
+
+// Setup Cloudflare REST API client
+const client = new Cloudflare({
+	apiEmail: process.env.CLOUDFLARE_EMAIL,
+	apiKey: process.env.CLOUDFLARE_API_KEY,
+});
+
+// Function to sync Postgres data to Workers KV
+async function syncPreviewStatus() {
+	console.log('Starting sync of user preview status...');
+
+	try {
+		// Get all users and their preview status
+		const users = await sql`SELECT id, preview_features_enabled FROM users`;
+
+		console.log(users);
+
+		// Create the bulk update body
+		const bulkUpdateBody = users.map(user => ({
+			key: user.id,
+			value: JSON.stringify({
+				preview_features_enabled: user.preview_features_enabled
+			})
+		}));
+
+		const response = await backOff(async () => {
+			console.log("trying to update")
+			try{
+				const response = await client.kv.namespaces.bulkUpdate(process.env.CLOUDFLARE_WORKERS_KV_NAMESPACE_ID, {
+					account_id: process.env.CLOUDFLARE_ACCOUNT_ID,
+					body: bulkUpdateBody
+				});
+			}
+			catch(e){
+				// Implement your error handling and logging here
+				console.log(e);
+				throw e; // Rethrow the error to retry
+			}
+		});
+
+		console.log(`Sync complete. Updated ${users.length} users.`);
+	} catch (error) {
+		console.error('Error syncing preview status:', error);
+	}
+}
+
+// Run the sync function
+syncPreviewStatus()
+	.catch(console.error)
+	.finally(() => process.exit(0));
+```
+</TabItem>
+<TabItem label=".env">
+```md title=".env"
+DATABASE_CONNECTION_STRING = <DB_CONNECTION_STRING_HERE>
+CLOUDFLARE_EMAIL = <CLOUDFLARE_EMAIL_HERE>
+CLOUDFLARE_API_KEY = <CLOUDFLARE_API_KEY_HERE>
+CLOUDFLARE_ACCOUNT_ID = <CLOUDFLARE_ACCOUNT_ID_HERE>
+CLOUDFLARE_WORKERS_KV_NAMESPACE_ID = <CLOUDFLARE_WORKERS_KV_NAMESPACE_ID_HERE>
+````
+
+</TabItem>
+<TabItem label="db.sql">
+```sql title="db.sql"
+-- Create users table with preview_features_enabled flag
+CREATE TABLE users (
+  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
+  username VARCHAR(100) NOT NULL,
+  email VARCHAR(255) NOT NULL,
+  preview_features_enabled BOOLEAN DEFAULT false
+);
+
+-- Insert sample users
+INSERT INTO users (username, email, preview_features_enabled) VALUES
+('alice', 'alice@example.com', true),
+('bob', 'bob@example.com', false),
+('charlie', 'charlie@example.com', true);
+
+````
+</TabItem>
+</Tabs>
+
+In this code snippet, the Node.js application reads user data from a Postgres database and writes the user data to be used for configuration in our Workers application to Workers KV using the Cloudflare REST API Node.js library.
+The application also uses exponential backoff to handle retries in case of errors.
+
+## Use configuration data from Workers KV in your Worker application
+
+With the configuration data now in the Workers KV namespace, we can use it in our Workers application to personalize the application for each user.
+
+<Tabs>
+<TabItem label="index.ts">
+```js title="index.ts"
+// Example configuration data stored in Workers KV:
+// Key: "user-id-abc" | Value: {"preview_features_enabled": false}
+// Key: "user-id-def" | Value: {"preview_features_enabled": true}
+
+interface Env {
+  USER_CONFIGURATION: KVNamespace;
+}
+
+export default {
+  async fetch(request, env) {
+    // Get user ID from query parameter
+    const url = new URL(request.url);
+    const userId = url.searchParams.get('userId');
+
+    if (!userId) {
+      return new Response('Please provide a userId query parameter', {
+        status: 400,
+        headers: { 'Content-Type': 'text/plain' }
+      });
+    }
+
+
+		const userConfiguration = await env.USER_CONFIGURATION.get<{
+			preview_features_enabled: boolean;
+		}>(userId, {type: "json"});
+
+		console.log(userConfiguration);
+
+    // Build HTML response
+    const html = `
+      <!DOCTYPE html>
+      <html>
+        <head>
+          <title>My App</title>
+          <style>
+            body {
+              font-family: Arial, sans-serif;
+              max-width: 800px;
+              margin: 0 auto;
+              padding: 20px;
+            }
+            .preview-banner {
+              background-color: #ffeb3b;
+              padding: 10px;
+              text-align: center;
+              margin-bottom: 20px;
+              border-radius: 4px;
+            }
+          </style>
+        </head>
+        <body>
+          ${userConfiguration?.preview_features_enabled ? `
+            <div class="preview-banner">
+              🎉 You have early access to preview features! 🎉
+            </div>
+          ` : ''}
+          <h1>Welcome to My App</h1>
+          <p>This is the regular content everyone sees.</p>
+        </body>
+      </html>
+    `;
+
+    return new Response(html, {
+			headers: { "Content-Type": "text/html; charset=utf-8" }
+    });
+  }
+} satisfies ExportedHandler<Env>;
+
+```
+</TabItem>
+<TabItem label="wrangler.jsonc">
+```json
+{
+	"$schema": "node_modules/wrangler/config-schema.json",
+	"name": "<ENTER_WORKER_NAME>",
+	"main": "src/index.ts",
+	"compatibility_date": "2025-03-03",
+	"observability": {
+		"enabled": true
+	},
+	"kv_namespaces": [
+		{
+			"binding": "USER_CONFIGURATION",
+			"id": "<YOUR_BINDING_ID>"
+		}
+	]
+}
+````
+
+</TabItem>
+</Tabs>
+
+This code will use the path within the URL and find the file associated to the path within the KV store. It also sets the proper MIME type in the response to indicate to the browser how to handle the response. To retrieve the value from the KV store, this code uses `arrayBuffer` to properly handle binary data such as images, documents, and video/audio files.
+
+## Optimizing performance for configuration
path: src/content/docs/kv/examples/distributed-configuration-with-workers-kv.mdx
user: login: Oxyjun
body: ```suggestion
## Optimize performance for configuration
```
created_at: 2025-03-10T13:09:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,239 @@
+---
+type: example
+summary: Use Workers KV to as a geo-distributed, low-latency configuration store for your Workers application
+tags:
+  - KV
+pcx_content_type: configuration
+title: Build a distributed configuration store
+sidebar:
+  order: 5
+description: Example of how to use Workers KV to build a distributed application configuration store.
+---
+
+import { Render, PackageManagers, Tabs, TabItem } from "~/components";
+
+Storing application configuration data is an ideal use case for Workers KV. Configuration data can include data to personalize an application for each user or tenant, enable features for user groups, restrict access with allow-lists/deny-lists, etc. These use-cases can have high read volumes that are highly cacheable by Workers KV, which can ensure low-latency reads from your Workers application.
+
+In this example, application configuration data is used to personalize the Workers application for each user. The configuration data is stored in an external application and database and written to Workers KV using the REST API.
+
+## Write your configuration from your external application to Workers KV
+
+In some cases, your source-of-truth for your configuration data may be stored elsewhere than Workers KV.
+If this is the case, use the Workers KV REST API to write the configuration data to your Workers KV namespace. You may also
+
+The following external Node.js application demonstrates a simple scripts that reads user data from a database and writes it to Workers KV using the REST API library.
+
+<Tabs>
+<TabItem label="index.js">
+```js title="index.js"
+const postgres = require('postgres');
+const { Cloudflare } = require('cloudflare');
+const { backOff } = require('exponential-backoff');
+
+if(!process.env.DATABASE_CONNECTION_STRING || !process.env.CLOUDFLARE_EMAIL || !process.env.CLOUDFLARE_API_KEY || !process.env.CLOUDFLARE_WORKERS_KV_NAMESPACE_ID || !process.env.CLOUDFLARE_ACCOUNT_ID) {
+	console.error('Missing required environment variables.');
+	process.exit(1);
+}
+
+// Setup Postgres connection
+const sql = postgres(process.env.DATABASE_CONNECTION_STRING);
+
+// Setup Cloudflare REST API client
+const client = new Cloudflare({
+	apiEmail: process.env.CLOUDFLARE_EMAIL,
+	apiKey: process.env.CLOUDFLARE_API_KEY,
+});
+
+// Function to sync Postgres data to Workers KV
+async function syncPreviewStatus() {
+	console.log('Starting sync of user preview status...');
+
+	try {
+		// Get all users and their preview status
+		const users = await sql`SELECT id, preview_features_enabled FROM users`;
+
+		console.log(users);
+
+		// Create the bulk update body
+		const bulkUpdateBody = users.map(user => ({
+			key: user.id,
+			value: JSON.stringify({
+				preview_features_enabled: user.preview_features_enabled
+			})
+		}));
+
+		const response = await backOff(async () => {
+			console.log("trying to update")
+			try{
+				const response = await client.kv.namespaces.bulkUpdate(process.env.CLOUDFLARE_WORKERS_KV_NAMESPACE_ID, {
+					account_id: process.env.CLOUDFLARE_ACCOUNT_ID,
+					body: bulkUpdateBody
+				});
+			}
+			catch(e){
+				// Implement your error handling and logging here
+				console.log(e);
+				throw e; // Rethrow the error to retry
+			}
+		});
+
+		console.log(`Sync complete. Updated ${users.length} users.`);
+	} catch (error) {
+		console.error('Error syncing preview status:', error);
+	}
+}
+
+// Run the sync function
+syncPreviewStatus()
+	.catch(console.error)
+	.finally(() => process.exit(0));
+```
+</TabItem>
+<TabItem label=".env">
+```md title=".env"
+DATABASE_CONNECTION_STRING = <DB_CONNECTION_STRING_HERE>
+CLOUDFLARE_EMAIL = <CLOUDFLARE_EMAIL_HERE>
+CLOUDFLARE_API_KEY = <CLOUDFLARE_API_KEY_HERE>
+CLOUDFLARE_ACCOUNT_ID = <CLOUDFLARE_ACCOUNT_ID_HERE>
+CLOUDFLARE_WORKERS_KV_NAMESPACE_ID = <CLOUDFLARE_WORKERS_KV_NAMESPACE_ID_HERE>
+````
+
+</TabItem>
+<TabItem label="db.sql">
+```sql title="db.sql"
+-- Create users table with preview_features_enabled flag
+CREATE TABLE users (
+  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
+  username VARCHAR(100) NOT NULL,
+  email VARCHAR(255) NOT NULL,
+  preview_features_enabled BOOLEAN DEFAULT false
+);
+
+-- Insert sample users
+INSERT INTO users (username, email, preview_features_enabled) VALUES
+('alice', 'alice@example.com', true),
+('bob', 'bob@example.com', false),
+('charlie', 'charlie@example.com', true);
+
+````
+</TabItem>
+</Tabs>
+
+In this code snippet, the Node.js application reads user data from a Postgres database and writes the user data to be used for configuration in our Workers application to Workers KV using the Cloudflare REST API Node.js library.
+The application also uses exponential backoff to handle retries in case of errors.
+
+## Use configuration data from Workers KV in your Worker application
+
+With the configuration data now in the Workers KV namespace, we can use it in our Workers application to personalize the application for each user.
+
+<Tabs>
+<TabItem label="index.ts">
+```js title="index.ts"
+// Example configuration data stored in Workers KV:
+// Key: "user-id-abc" | Value: {"preview_features_enabled": false}
+// Key: "user-id-def" | Value: {"preview_features_enabled": true}
+
+interface Env {
+  USER_CONFIGURATION: KVNamespace;
+}
+
+export default {
+  async fetch(request, env) {
+    // Get user ID from query parameter
+    const url = new URL(request.url);
+    const userId = url.searchParams.get('userId');
+
+    if (!userId) {
+      return new Response('Please provide a userId query parameter', {
+        status: 400,
+        headers: { 'Content-Type': 'text/plain' }
+      });
+    }
+
+
+		const userConfiguration = await env.USER_CONFIGURATION.get<{
+			preview_features_enabled: boolean;
+		}>(userId, {type: "json"});
+
+		console.log(userConfiguration);
+
+    // Build HTML response
+    const html = `
+      <!DOCTYPE html>
+      <html>
+        <head>
+          <title>My App</title>
+          <style>
+            body {
+              font-family: Arial, sans-serif;
+              max-width: 800px;
+              margin: 0 auto;
+              padding: 20px;
+            }
+            .preview-banner {
+              background-color: #ffeb3b;
+              padding: 10px;
+              text-align: center;
+              margin-bottom: 20px;
+              border-radius: 4px;
+            }
+          </style>
+        </head>
+        <body>
+          ${userConfiguration?.preview_features_enabled ? `
+            <div class="preview-banner">
+              🎉 You have early access to preview features! 🎉
+            </div>
+          ` : ''}
+          <h1>Welcome to My App</h1>
+          <p>This is the regular content everyone sees.</p>
+        </body>
+      </html>
+    `;
+
+    return new Response(html, {
+			headers: { "Content-Type": "text/html; charset=utf-8" }
+    });
+  }
+} satisfies ExportedHandler<Env>;
+
+```
+</TabItem>
+<TabItem label="wrangler.jsonc">
+```json
+{
+	"$schema": "node_modules/wrangler/config-schema.json",
+	"name": "<ENTER_WORKER_NAME>",
+	"main": "src/index.ts",
+	"compatibility_date": "2025-03-03",
+	"observability": {
+		"enabled": true
+	},
+	"kv_namespaces": [
+		{
+			"binding": "USER_CONFIGURATION",
+			"id": "<YOUR_BINDING_ID>"
+		}
+	]
+}
+````
+
+</TabItem>
+</Tabs>
+
+This code will use the path within the URL and find the file associated to the path within the KV store. It also sets the proper MIME type in the response to indicate to the browser how to handle the response. To retrieve the value from the KV store, this code uses `arrayBuffer` to properly handle binary data such as images, documents, and video/audio files.
+
+## Optimizing performance for configuration
+
+To optimize performance, you may opt to consolidate values in fewer key-value pairs. By doing so, you may
+benefit from higher caching efficiency and lower latency. 
path: src/content/docs/kv/examples/distributed-configuration-with-workers-kv.mdx
user: login: Oxyjun
body: ```suggestion
To optimize performance, you may opt to consolidate values in fewer key-value pairs. By doing so, you may benefit from higher caching efficiency and lower latency. 
```
created_at: 2025-03-10T13:09:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,239 @@
+---
+type: example
+summary: Use Workers KV to as a geo-distributed, low-latency configuration store for your Workers application
+tags:
+  - KV
+pcx_content_type: configuration
+title: Build a distributed configuration store
+sidebar:
+  order: 5
+description: Example of how to use Workers KV to build a distributed application configuration store.
+---
+
+import { Render, PackageManagers, Tabs, TabItem } from "~/components";
+
+Storing application configuration data is an ideal use case for Workers KV. Configuration data can include data to personalize an application for each user or tenant, enable features for user groups, restrict access with allow-lists/deny-lists, etc. These use-cases can have high read volumes that are highly cacheable by Workers KV, which can ensure low-latency reads from your Workers application.
+
+In this example, application configuration data is used to personalize the Workers application for each user. The configuration data is stored in an external application and database and written to Workers KV using the REST API.
+
+## Write your configuration from your external application to Workers KV
+
+In some cases, your source-of-truth for your configuration data may be stored elsewhere than Workers KV.
+If this is the case, use the Workers KV REST API to write the configuration data to your Workers KV namespace. You may also
+
+The following external Node.js application demonstrates a simple scripts that reads user data from a database and writes it to Workers KV using the REST API library.
+
+<Tabs>
+<TabItem label="index.js">
+```js title="index.js"
+const postgres = require('postgres');
+const { Cloudflare } = require('cloudflare');
+const { backOff } = require('exponential-backoff');
+
+if(!process.env.DATABASE_CONNECTION_STRING || !process.env.CLOUDFLARE_EMAIL || !process.env.CLOUDFLARE_API_KEY || !process.env.CLOUDFLARE_WORKERS_KV_NAMESPACE_ID || !process.env.CLOUDFLARE_ACCOUNT_ID) {
+	console.error('Missing required environment variables.');
+	process.exit(1);
+}
+
+// Setup Postgres connection
+const sql = postgres(process.env.DATABASE_CONNECTION_STRING);
+
+// Setup Cloudflare REST API client
+const client = new Cloudflare({
+	apiEmail: process.env.CLOUDFLARE_EMAIL,
+	apiKey: process.env.CLOUDFLARE_API_KEY,
+});
+
+// Function to sync Postgres data to Workers KV
+async function syncPreviewStatus() {
+	console.log('Starting sync of user preview status...');
+
+	try {
+		// Get all users and their preview status
+		const users = await sql`SELECT id, preview_features_enabled FROM users`;
+
+		console.log(users);
+
+		// Create the bulk update body
+		const bulkUpdateBody = users.map(user => ({
+			key: user.id,
+			value: JSON.stringify({
+				preview_features_enabled: user.preview_features_enabled
+			})
+		}));
+
+		const response = await backOff(async () => {
+			console.log("trying to update")
+			try{
+				const response = await client.kv.namespaces.bulkUpdate(process.env.CLOUDFLARE_WORKERS_KV_NAMESPACE_ID, {
+					account_id: process.env.CLOUDFLARE_ACCOUNT_ID,
+					body: bulkUpdateBody
+				});
+			}
+			catch(e){
+				// Implement your error handling and logging here
+				console.log(e);
+				throw e; // Rethrow the error to retry
+			}
+		});
+
+		console.log(`Sync complete. Updated ${users.length} users.`);
+	} catch (error) {
+		console.error('Error syncing preview status:', error);
+	}
+}
+
+// Run the sync function
+syncPreviewStatus()
+	.catch(console.error)
+	.finally(() => process.exit(0));
+```
+</TabItem>
+<TabItem label=".env">
+```md title=".env"
+DATABASE_CONNECTION_STRING = <DB_CONNECTION_STRING_HERE>
+CLOUDFLARE_EMAIL = <CLOUDFLARE_EMAIL_HERE>
+CLOUDFLARE_API_KEY = <CLOUDFLARE_API_KEY_HERE>
+CLOUDFLARE_ACCOUNT_ID = <CLOUDFLARE_ACCOUNT_ID_HERE>
+CLOUDFLARE_WORKERS_KV_NAMESPACE_ID = <CLOUDFLARE_WORKERS_KV_NAMESPACE_ID_HERE>
+````
+
+</TabItem>
+<TabItem label="db.sql">
+```sql title="db.sql"
+-- Create users table with preview_features_enabled flag
+CREATE TABLE users (
+  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
+  username VARCHAR(100) NOT NULL,
+  email VARCHAR(255) NOT NULL,
+  preview_features_enabled BOOLEAN DEFAULT false
+);
+
+-- Insert sample users
+INSERT INTO users (username, email, preview_features_enabled) VALUES
+('alice', 'alice@example.com', true),
+('bob', 'bob@example.com', false),
+('charlie', 'charlie@example.com', true);
+
+````
+</TabItem>
+</Tabs>
+
+In this code snippet, the Node.js application reads user data from a Postgres database and writes the user data to be used for configuration in our Workers application to Workers KV using the Cloudflare REST API Node.js library.
+The application also uses exponential backoff to handle retries in case of errors.
+
+## Use configuration data from Workers KV in your Worker application
+
+With the configuration data now in the Workers KV namespace, we can use it in our Workers application to personalize the application for each user.
+
+<Tabs>
+<TabItem label="index.ts">
+```js title="index.ts"
+// Example configuration data stored in Workers KV:
+// Key: "user-id-abc" | Value: {"preview_features_enabled": false}
+// Key: "user-id-def" | Value: {"preview_features_enabled": true}
+
+interface Env {
+  USER_CONFIGURATION: KVNamespace;
+}
+
+export default {
+  async fetch(request, env) {
+    // Get user ID from query parameter
+    const url = new URL(request.url);
+    const userId = url.searchParams.get('userId');
+
+    if (!userId) {
+      return new Response('Please provide a userId query parameter', {
+        status: 400,
+        headers: { 'Content-Type': 'text/plain' }
+      });
+    }
+
+
+		const userConfiguration = await env.USER_CONFIGURATION.get<{
+			preview_features_enabled: boolean;
+		}>(userId, {type: "json"});
+
+		console.log(userConfiguration);
+
+    // Build HTML response
+    const html = `
+      <!DOCTYPE html>
+      <html>
+        <head>
+          <title>My App</title>
+          <style>
+            body {
+              font-family: Arial, sans-serif;
+              max-width: 800px;
+              margin: 0 auto;
+              padding: 20px;
+            }
+            .preview-banner {
+              background-color: #ffeb3b;
+              padding: 10px;
+              text-align: center;
+              margin-bottom: 20px;
+              border-radius: 4px;
+            }
+          </style>
+        </head>
+        <body>
+          ${userConfiguration?.preview_features_enabled ? `
+            <div class="preview-banner">
+              🎉 You have early access to preview features! 🎉
+            </div>
+          ` : ''}
+          <h1>Welcome to My App</h1>
+          <p>This is the regular content everyone sees.</p>
+        </body>
+      </html>
+    `;
+
+    return new Response(html, {
+			headers: { "Content-Type": "text/html; charset=utf-8" }
+    });
+  }
+} satisfies ExportedHandler<Env>;
+
+```
+</TabItem>
+<TabItem label="wrangler.jsonc">
+```json
+{
+	"$schema": "node_modules/wrangler/config-schema.json",
+	"name": "<ENTER_WORKER_NAME>",
+	"main": "src/index.ts",
+	"compatibility_date": "2025-03-03",
+	"observability": {
+		"enabled": true
+	},
+	"kv_namespaces": [
+		{
+			"binding": "USER_CONFIGURATION",
+			"id": "<YOUR_BINDING_ID>"
+		}
+	]
+}
+````
+
+</TabItem>
+</Tabs>
+
+This code will use the path within the URL and find the file associated to the path within the KV store. It also sets the proper MIME type in the response to indicate to the browser how to handle the response. To retrieve the value from the KV store, this code uses `arrayBuffer` to properly handle binary data such as images, documents, and video/audio files.
+
+## Optimizing performance for configuration
+
+To optimize performance, you may opt to consolidate values in fewer key-value pairs. By doing so, you may
+benefit from higher caching efficiency and lower latency. 
+
+For example, instead of storing each user's configuration
+in a separate key-value pair, you may store all users' configurations in a single key-value pair. This approach
+may be suitable for use-cases where the configuration data is small and can be easily managed in a single key-value pair
+(the [size limit for a Workers KV value is 25 MiB](/kv/platform/limits/)).
path: src/content/docs/kv/examples/distributed-configuration-with-workers-kv.mdx
user: login: Oxyjun
body: ```suggestion
For example, instead of storing each user's configuration in a separate key-value pair, you may store all users' configurations in a single key-value pair. This approach may be suitable for use-cases where the configuration data is small and can be easily managed in a single key-value pair (the [size limit for a Workers KV value is 25 MiB](/kv/platform/limits/)).
```
created_at: 2025-03-10T13:13:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,239 @@
+---
+type: example
+summary: Use Workers KV to as a geo-distributed, low-latency configuration store for your Workers application
+tags:
+  - KV
+pcx_content_type: configuration
+title: Build a distributed configuration store
+sidebar:
+  order: 5
+description: Example of how to use Workers KV to build a distributed application configuration store.
+---
+
+import { Render, PackageManagers, Tabs, TabItem } from "~/components";
+
+Storing application configuration data is an ideal use case for Workers KV. Configuration data can include data to personalize an application for each user or tenant, enable features for user groups, restrict access with allow-lists/deny-lists, etc. These use-cases can have high read volumes that are highly cacheable by Workers KV, which can ensure low-latency reads from your Workers application.
+
+In this example, application configuration data is used to personalize the Workers application for each user. The configuration data is stored in an external application and database and written to Workers KV using the REST API.
+
+## Write your configuration from your external application to Workers KV
+
+In some cases, your source-of-truth for your configuration data may be stored elsewhere than Workers KV.
+If this is the case, use the Workers KV REST API to write the configuration data to your Workers KV namespace. You may also
+
+The following external Node.js application demonstrates a simple scripts that reads user data from a database and writes it to Workers KV using the REST API library.
+
+<Tabs>
+<TabItem label="index.js">
+```js title="index.js"
+const postgres = require('postgres');
+const { Cloudflare } = require('cloudflare');
+const { backOff } = require('exponential-backoff');
+
+if(!process.env.DATABASE_CONNECTION_STRING || !process.env.CLOUDFLARE_EMAIL || !process.env.CLOUDFLARE_API_KEY || !process.env.CLOUDFLARE_WORKERS_KV_NAMESPACE_ID || !process.env.CLOUDFLARE_ACCOUNT_ID) {
+	console.error('Missing required environment variables.');
+	process.exit(1);
+}
+
+// Setup Postgres connection
+const sql = postgres(process.env.DATABASE_CONNECTION_STRING);
+
+// Setup Cloudflare REST API client
+const client = new Cloudflare({
+	apiEmail: process.env.CLOUDFLARE_EMAIL,
+	apiKey: process.env.CLOUDFLARE_API_KEY,
+});
+
+// Function to sync Postgres data to Workers KV
+async function syncPreviewStatus() {
+	console.log('Starting sync of user preview status...');
+
+	try {
+		// Get all users and their preview status
+		const users = await sql`SELECT id, preview_features_enabled FROM users`;
+
+		console.log(users);
+
+		// Create the bulk update body
+		const bulkUpdateBody = users.map(user => ({
+			key: user.id,
+			value: JSON.stringify({
+				preview_features_enabled: user.preview_features_enabled
+			})
+		}));
+
+		const response = await backOff(async () => {
+			console.log("trying to update")
+			try{
+				const response = await client.kv.namespaces.bulkUpdate(process.env.CLOUDFLARE_WORKERS_KV_NAMESPACE_ID, {
+					account_id: process.env.CLOUDFLARE_ACCOUNT_ID,
+					body: bulkUpdateBody
+				});
+			}
+			catch(e){
+				// Implement your error handling and logging here
+				console.log(e);
+				throw e; // Rethrow the error to retry
+			}
+		});
+
+		console.log(`Sync complete. Updated ${users.length} users.`);
+	} catch (error) {
+		console.error('Error syncing preview status:', error);
+	}
+}
+
+// Run the sync function
+syncPreviewStatus()
+	.catch(console.error)
+	.finally(() => process.exit(0));
+```
+</TabItem>
+<TabItem label=".env">
+```md title=".env"
+DATABASE_CONNECTION_STRING = <DB_CONNECTION_STRING_HERE>
+CLOUDFLARE_EMAIL = <CLOUDFLARE_EMAIL_HERE>
+CLOUDFLARE_API_KEY = <CLOUDFLARE_API_KEY_HERE>
+CLOUDFLARE_ACCOUNT_ID = <CLOUDFLARE_ACCOUNT_ID_HERE>
+CLOUDFLARE_WORKERS_KV_NAMESPACE_ID = <CLOUDFLARE_WORKERS_KV_NAMESPACE_ID_HERE>
+````
+
+</TabItem>
+<TabItem label="db.sql">
+```sql title="db.sql"
+-- Create users table with preview_features_enabled flag
+CREATE TABLE users (
+  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
+  username VARCHAR(100) NOT NULL,
+  email VARCHAR(255) NOT NULL,
+  preview_features_enabled BOOLEAN DEFAULT false
+);
+
+-- Insert sample users
+INSERT INTO users (username, email, preview_features_enabled) VALUES
+('alice', 'alice@example.com', true),
+('bob', 'bob@example.com', false),
+('charlie', 'charlie@example.com', true);
+
+````
+</TabItem>
+</Tabs>
+
+In this code snippet, the Node.js application reads user data from a Postgres database and writes the user data to be used for configuration in our Workers application to Workers KV using the Cloudflare REST API Node.js library.
+The application also uses exponential backoff to handle retries in case of errors.
+
+## Use configuration data from Workers KV in your Worker application
+
+With the configuration data now in the Workers KV namespace, we can use it in our Workers application to personalize the application for each user.
+
+<Tabs>
+<TabItem label="index.ts">
+```js title="index.ts"
+// Example configuration data stored in Workers KV:
+// Key: "user-id-abc" | Value: {"preview_features_enabled": false}
+// Key: "user-id-def" | Value: {"preview_features_enabled": true}
+
+interface Env {
+  USER_CONFIGURATION: KVNamespace;
+}
+
+export default {
+  async fetch(request, env) {
+    // Get user ID from query parameter
+    const url = new URL(request.url);
+    const userId = url.searchParams.get('userId');
+
+    if (!userId) {
+      return new Response('Please provide a userId query parameter', {
+        status: 400,
+        headers: { 'Content-Type': 'text/plain' }
+      });
+    }
+
+
+		const userConfiguration = await env.USER_CONFIGURATION.get<{
+			preview_features_enabled: boolean;
+		}>(userId, {type: "json"});
+
+		console.log(userConfiguration);
+
+    // Build HTML response
+    const html = `
+      <!DOCTYPE html>
+      <html>
+        <head>
+          <title>My App</title>
+          <style>
+            body {
+              font-family: Arial, sans-serif;
+              max-width: 800px;
+              margin: 0 auto;
+              padding: 20px;
+            }
+            .preview-banner {
+              background-color: #ffeb3b;
+              padding: 10px;
+              text-align: center;
+              margin-bottom: 20px;
+              border-radius: 4px;
+            }
+          </style>
+        </head>
+        <body>
+          ${userConfiguration?.preview_features_enabled ? `
+            <div class="preview-banner">
+              🎉 You have early access to preview features! 🎉
+            </div>
+          ` : ''}
+          <h1>Welcome to My App</h1>
+          <p>This is the regular content everyone sees.</p>
+        </body>
+      </html>
+    `;
+
+    return new Response(html, {
+			headers: { "Content-Type": "text/html; charset=utf-8" }
+    });
+  }
+} satisfies ExportedHandler<Env>;
+
+```
+</TabItem>
+<TabItem label="wrangler.jsonc">
+```json
+{
+	"$schema": "node_modules/wrangler/config-schema.json",
+	"name": "<ENTER_WORKER_NAME>",
+	"main": "src/index.ts",
+	"compatibility_date": "2025-03-03",
+	"observability": {
+		"enabled": true
+	},
+	"kv_namespaces": [
+		{
+			"binding": "USER_CONFIGURATION",
+			"id": "<YOUR_BINDING_ID>"
+		}
+	]
+}
+````
+
+</TabItem>
+</Tabs>
+
+This code will use the path within the URL and find the file associated to the path within the KV store. It also sets the proper MIME type in the response to indicate to the browser how to handle the response. To retrieve the value from the KV store, this code uses `arrayBuffer` to properly handle binary data such as images, documents, and video/audio files.
+
+## Optimizing performance for configuration
+
+To optimize performance, you may opt to consolidate values in fewer key-value pairs. By doing so, you may
+benefit from higher caching efficiency and lower latency. 
+
+For example, instead of storing each user's configuration
+in a separate key-value pair, you may store all users' configurations in a single key-value pair. This approach
+may be suitable for use-cases where the configuration data is small and can be easily managed in a single key-value pair
+(the [size limit for a Workers KV value is 25 MiB](/kv/platform/limits/)).
+
+## Related resources
+
+- [Rust support in Workers](/workers/languages/rust/).
+- [Using KV in Workers](/kv/get-started/).
path: src/content/docs/kv/examples/distributed-configuration-with-workers-kv.mdx
user: login: Oxyjun
body: ```suggestion
- [Rust support in Workers](/workers/languages/rust/)
- [Using KV in Workers](/kv/get-started/)
```
created_at: 2025-03-10T13:14:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,147 @@
+---
+type: example
+summary: Store routing data in Workers KV to route requests across various web servers with Workers
+tags:
+  - KV
+pcx_content_type: configuration
+title: Route requests across various web servers
+sidebar:
+  order: 5
+description: Example of how to use Workers KV to build a distributed application configuration store.
+---
+
+import { Render, PackageManagers, Tabs, TabItem } from "~/components";
+
+Using Workers KV to store routing data to route requests across various web servers with Workers is an ideal use case for Workers KV.
+Routing workloads can have high read volume and Workers KV's low-latency reads can help ensure that routing decisions are made quickly and efficiently.
path: src/content/docs/kv/examples/routing-with-workers-kv.mdx
user: login: Oxyjun
body: ```suggestion
Using Workers KV to store routing data to route requests across various web servers with Workers is an ideal use case for Workers KV. Routing workloads can have high read volume, and Workers KV's low-latency reads can help ensure that routing decisions are made quickly and efficiently.
```
created_at: 2025-03-10T13:16:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,147 @@
+---
+type: example
+summary: Store routing data in Workers KV to route requests across various web servers with Workers
+tags:
+  - KV
+pcx_content_type: configuration
+title: Route requests across various web servers
+sidebar:
+  order: 5
+description: Example of how to use Workers KV to build a distributed application configuration store.
+---
+
+import { Render, PackageManagers, Tabs, TabItem } from "~/components";
+
+Using Workers KV to store routing data to route requests across various web servers with Workers is an ideal use case for Workers KV.
+Routing workloads can have high read volume and Workers KV's low-latency reads can help ensure that routing decisions are made quickly and efficiently.
+
+Routing can be helpful to route requests coming into a single Cloudflare Worker application to different web servers based on the request's path, hostname, or other request attributes.
+In single-tenant applications, this can be used to route requests to various origin servers based on the business domain (ex: requests to `/admin` routed to administration server, `/store` routed to storefront server, `/api` routed to the API server).
+In multi-tenant applications, requests can be routed to the tenant's respective origin resources (ex: requests to `tenantA.your-worker-hostname.com` routed to server for Tenant A, `tenantB.your-worker-hostname.com` routed to server for Tenant B).
path: src/content/docs/kv/examples/routing-with-workers-kv.mdx
user: login: Oxyjun
body: ```suggestion

In multi-tenant applications, requests can be routed to the tenant's respective origin resources (for example, requests to `tenantA.your-worker-hostname.com` routed to server for Tenant A, `tenantB.your-worker-hostname.com` routed to server for Tenant B).
```
created_at: 2025-03-10T13:17:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,147 @@
+---
+type: example
+summary: Store routing data in Workers KV to route requests across various web servers with Workers
+tags:
+  - KV
+pcx_content_type: configuration
+title: Route requests across various web servers
+sidebar:
+  order: 5
+description: Example of how to use Workers KV to build a distributed application configuration store.
+---
+
+import { Render, PackageManagers, Tabs, TabItem } from "~/components";
+
+Using Workers KV to store routing data to route requests across various web servers with Workers is an ideal use case for Workers KV.
+Routing workloads can have high read volume and Workers KV's low-latency reads can help ensure that routing decisions are made quickly and efficiently.
+
+Routing can be helpful to route requests coming into a single Cloudflare Worker application to different web servers based on the request's path, hostname, or other request attributes.
path: src/content/docs/kv/examples/routing-with-workers-kv.mdx
user: login: Oxyjun
body: ```suggestion
Routing can be helpful to route requests coming into a single Cloudflare Worker application to different web servers based on the request's path, hostname, or other request attributes.

```
created_at: 2025-03-10T13:18:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,147 @@
+---
+type: example
+summary: Store routing data in Workers KV to route requests across various web servers with Workers
+tags:
+  - KV
+pcx_content_type: configuration
+title: Route requests across various web servers
+sidebar:
+  order: 5
+description: Example of how to use Workers KV to build a distributed application configuration store.
+---
+
+import { Render, PackageManagers, Tabs, TabItem } from "~/components";
+
+Using Workers KV to store routing data to route requests across various web servers with Workers is an ideal use case for Workers KV.
+Routing workloads can have high read volume and Workers KV's low-latency reads can help ensure that routing decisions are made quickly and efficiently.
+
+Routing can be helpful to route requests coming into a single Cloudflare Worker application to different web servers based on the request's path, hostname, or other request attributes.
+In single-tenant applications, this can be used to route requests to various origin servers based on the business domain (ex: requests to `/admin` routed to administration server, `/store` routed to storefront server, `/api` routed to the API server).
path: src/content/docs/kv/examples/routing-with-workers-kv.mdx
user: login: Oxyjun
body: ```suggestion
In single-tenant applications, this can be used to route requests to various origin servers based on the business domain (for example, requests to `/admin` routed to administration server, `/store` routed to storefront server, `/api` routed to the API server).
```
created_at: 2025-03-10T13:18:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,147 @@
+---
+type: example
+summary: Store routing data in Workers KV to route requests across various web servers with Workers
+tags:
+  - KV
+pcx_content_type: configuration
+title: Route requests across various web servers
+sidebar:
+  order: 5
+description: Example of how to use Workers KV to build a distributed application configuration store.
+---
+
+import { Render, PackageManagers, Tabs, TabItem } from "~/components";
+
+Using Workers KV to store routing data to route requests across various web servers with Workers is an ideal use case for Workers KV.
+Routing workloads can have high read volume and Workers KV's low-latency reads can help ensure that routing decisions are made quickly and efficiently.
+
+Routing can be helpful to route requests coming into a single Cloudflare Worker application to different web servers based on the request's path, hostname, or other request attributes.
+In single-tenant applications, this can be used to route requests to various origin servers based on the business domain (ex: requests to `/admin` routed to administration server, `/store` routed to storefront server, `/api` routed to the API server).
+In multi-tenant applications, requests can be routed to the tenant's respective origin resources (ex: requests to `tenantA.your-worker-hostname.com` routed to server for Tenant A, `tenantB.your-worker-hostname.com` routed to server for Tenant B).
+
+Routing can also be used to implement [A/B testing](/reference-architecture/diagrams/serverless/a-b-testing-using-workers/), canary deployments, or blue-green deployments for your own external applications.
+If you are looking to implement canary or blue-green deployments of applications built fully on Cloudflare Workers, see [Workers gradual deployments](/workers/configuration/versions-and-deployments/gradual-deployments/).
+
+## Routing requests with Workers KV
path: src/content/docs/kv/examples/routing-with-workers-kv.mdx
user: login: Oxyjun
body: ```suggestion
## Route requests with Workers KV
```
created_at: 2025-03-10T13:35:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,134 +1,28 @@
 ---
 type: example
-summary: Store and retrieve static assets with Workers KV
+summary: Store static assets in Workers KV and serve them from a Worker application with low-latency and high-throughput
 tags:
   - KV
 pcx_content_type: configuration
-title: Store and retrieve static assets with Workers KV
+title: Store and retrieve static assets
 sidebar:
   order: 4
 description: Example of how to use Workers KV to store static assets
 ---
 
-import { Render, PackageManagers } from "~/components";
+import { Render, PackageManagers, TabItem, Tabs } from "~/components";
 
 By storing static assets in Workers KV, you can retrieve these assets globally with low-latency and high throughput. You can then serve these assets directly, or use them to dynamically generate responses. This can be useful when serving files and images, or when generating dynamic HTML responses from static assets such as translations.
 
 :::note[Note]
 With [Workers KV](/kv), you can access, edit and store assets directly from your [Worker](/workers). If you need to serve assets as part of a front-end or full-stack web application, consider using [Cloudflare Pages](/pages/) or [Workers static assets](/workers/static-assets/), which provide a purpose-built deployment experience for web applications and their assets.
 :::
 
-<Render file="tutorials-before-you-start" product="workers" />
+## Write static assets to Workers KV using Wrangler
 
-## 1. Create a new Worker application
+To store static assets in Workers KV, you can use the [Wrangler CLI](/workers/wrangler/) (commonly used during development), the [Workers KV binding](/kv/concepts/kv-bindings/) from a Workers application, or the [Workers KV REST API](/api/resources/kv/subresources/namespaces/methods/list/) (commonly used to access Workers KV from an external application). We'll demonstrate how to use the Wrangler CLI.
path: src/content/docs/kv/examples/workers-kv-to-serve-assets.mdx
user: login: Oxyjun
body: ```suggestion
To store static assets in Workers KV, you can use the [Wrangler CLI](/workers/wrangler/) (commonly used during development), the [Workers KV binding](/kv/concepts/kv-bindings/) from a Workers application, or the [Workers KV REST API](/api/resources/kv/subresources/namespaces/methods/list/) (commonly used to access Workers KV from an external application). We will demonstrate how to use the Wrangler CLI.
```
created_at: 2025-03-10T13:41:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,134 +1,28 @@
 ---
 type: example
-summary: Store and retrieve static assets with Workers KV
+summary: Store static assets in Workers KV and serve them from a Worker application with low-latency and high-throughput
 tags:
   - KV
 pcx_content_type: configuration
-title: Store and retrieve static assets with Workers KV
+title: Store and retrieve static assets
 sidebar:
   order: 4
 description: Example of how to use Workers KV to store static assets
 ---
 
-import { Render, PackageManagers } from "~/components";
+import { Render, PackageManagers, TabItem, Tabs } from "~/components";
 
 By storing static assets in Workers KV, you can retrieve these assets globally with low-latency and high throughput. You can then serve these assets directly, or use them to dynamically generate responses. This can be useful when serving files and images, or when generating dynamic HTML responses from static assets such as translations.
 
 :::note[Note]
 With [Workers KV](/kv), you can access, edit and store assets directly from your [Worker](/workers). If you need to serve assets as part of a front-end or full-stack web application, consider using [Cloudflare Pages](/pages/) or [Workers static assets](/workers/static-assets/), which provide a purpose-built deployment experience for web applications and their assets.
 :::
 
-<Render file="tutorials-before-you-start" product="workers" />
+## Write static assets to Workers KV using Wrangler
 
-## 1. Create a new Worker application
+To store static assets in Workers KV, you can use the [Wrangler CLI](/workers/wrangler/) (commonly used during development), the [Workers KV binding](/kv/concepts/kv-bindings/) from a Workers application, or the [Workers KV REST API](/api/resources/kv/subresources/namespaces/methods/list/) (commonly used to access Workers KV from an external application). We'll demonstrate how to use the Wrangler CLI.
 
-To get started, create a Worker application using the [`create-cloudflare` CLI](https://github.com/cloudflare/workers-sdk/tree/main/packages/create-cloudflare). Open a terminal window and run the following command:
-
-<PackageManagers
-	type="create"
-	pkg="cloudflare@latest"
-	args={"example-kv-assets"}
-/>
-
-<Render
-	file="c3-post-run-steps"
-	product="workers"
-	params={{
-		category: "hello-world",
-		type: "Hello World Worker",
-		lang: "TypeScript",
-	}}
-/>
-
-Then, move into your newly created application
-
-```sh
-cd example-kv-assets
-```
-
-We'll also install the dependencies we will need for this project.
-
-```sh
-npm install mime accept-language-parser
-npm install --save-dev @types/accept-language-parser
-```
-
-## 2. Create a new KV namespace
-
-Next, we will create a KV store. This can be done through the Cloudflare dashboard or the Wrangler CLI. For this example, we will use the Wrangler CLI.
-
-To create a KV store via Wrangler:
-
-1. Open your terminal and run the following command:
-
-   ```sh
-   npx wrangler kv namespace create assets
-   ```
-
-   The `wrangler kv namespace create assets` subcommand creates a KV namespace by concatenating your Worker's name and the value provided for `assets`. An `id` will be randomly generated for the KV namespace.
-
-   ```sh
-   npx wrangler kv namespace create assets
-   ```
-
-   ```sh {6} output
-   🌀 Creating namespace with title "example-kv-assets-assets"
-   ✨ Success!
-   Add the following to your configuration file in your kv_namespaces array:
-   [[kv_namespaces]]
-   binding = "assets"
-   id = "<GENERATED_NAMESPACE_ID>"
-   ```
-
-2. In your Wrangler file, add the following with the values generated in the terminal:
-
-   ```bash {3} title="wrangler.toml"
-   [[kv_namespaces]]
-   binding = "assets"
-   id = "<GENERATED_NAMESPACE_ID>"
-   ```
-
-   The [KV binding](/kv/concepts/kv-bindings/) `assets` is how your Worker will interact with the [KV namespace](/kv/concepts/kv-namespaces/). This binding will be provided as a runtime variable within your Workers code by the Workers runtime.
-
-   We'll also create a preview KV namespace. It is recommended to create a separate KV namespace when developing locally to avoid making changes to the production namespace. When developing locally against remote resources, the Wrangler CLI will only use the namespace specified by `preview_id` in the KV namespace configuration of the Wrangler file.
-
-3. In your terminal, run the following command:
-
-   ```sh
-   npx wrangler kv namespace create assets --preview
-   ```
-
-   This command will create a special KV namespace that will be used only when developing with Wrangler against remote resources using `wrangler dev --remote`.
-
-   ```sh
-   npx wrangler kv namespace create assets --preview
-   ```
-
-   ```sh {6} output
-   🌀 Creating namespace with title "example-kv-assets-assets_preview"
-   ✨ Success!
-   Add the following to your configuration file in your kv_namespaces array:
-   [[kv_namespaces]]
-   binding = "assets"
-   preview_id = "<GENERATED_PREVIEW_NAMESPACE_ID>"
-   ```
-
-4. In your Wrangler file, add the additional preview_id below kv_namespaces with the values generated in the terminal:
-
-   ```bash {4} title="wrangler.toml"
-   [[kv_namespaces]]
-   binding = "assets"
-   id = "<GENERATED_NAMESPACE_ID>"
-   preview_id = "<GENERATED_PREVIEW_NAMESPACE_ID>"
-   ```
-
-We now have one KV binding that will use the production KV namespace when deployed and the preview KV namespace when developing locally against remote resources with `wrangler dev --remote`.
-
-## 3. Store static assets in KV using Wrangler
-
-To store static assets in KV, you can use the Wrangler CLI, the KV binding from a Worker application, or the KV REST API. We'll demonstrate how to use the Wrangler CLI.
-
-For this scenario, we'll be storing a sample HTML file within our KV store. Create a new file `index.html` in the root of project with the following content:
+For this scenario, we'll be storing a sample HTML file within our Workers KV store. Create a new file `index.html` with the following content:
path: src/content/docs/kv/examples/workers-kv-to-serve-assets.mdx
user: login: Oxyjun
body: ```suggestion
For this scenario, we will store a sample HTML file within our Workers KV store.

Create a new file `index.html` with the following content:
```
created_at: 2025-03-10T13:42:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -137,92 +31,104 @@ Hello World!
 We can then use the following Wrangler commands to create a KV pair for this file within our production and preview namespaces:
 
 ```sh
-npx wrangler kv key put index.html --path index.html --binding assets --preview false
-npx wrangler kv key put index.html --path index.html --binding assets --preview
+npx wrangler kv key put index.html --path index.html --namespace-id=<ENTER_NAMESPACE_ID_HERE>
 ```
 
 This will create a KV pair with the filename as key and the file content as value, within the our production and preview namespaces specified by your binding in your Wrangler file.
 
-## 4. Serve static assets from KV from your Worker application
+## Serve static assets from KV from your Worker application
 
-Within the `index.ts` file of our Worker project, replace the contents with the following:
+In this example, our Workers application will accept any key name as the path of the HTTP request and return the value stored in the KV store for that key.
 
-```js title="index.ts"
+<Tabs>
+<TabItem label="index.ts">
+```js
 
-import mime from 'mime';
+import mime from "mime";
 
 interface Env {
-	assets: KVNamespace;
+assets: KVNamespace;
 }
 
 export default {
 	async fetch(request, env, ctx): Promise<Response> {
-		//return error if not a get request
+		// Return error if not a get request
 		if(request.method !== 'GET'){
 			return new Response('Method Not Allowed', {
 				status: 405,
 			})
 		}
 
-		//get the key from the url & return error if key missing
-		const parsedUrl = new URL(request.url)
-		const key = parsedUrl.pathname.replace(/^\/+/, '') // strip any preceding /'s
-		if(!key){
-			return new Response('Missing path in URL', {
-				status: 400
-			})
-		}
-
-		//get the mimetype from the key path
-		const extension = key.split('.').pop();
-		let mimeType = mime.getType(key) || "text/plain";
-		if (mimeType.startsWith("text") || mimeType === "application/javascript") {
-			mimeType += "; charset=utf-8";
-		}
+    	// Get the key from the url & return error if key missing
+    	const parsedUrl = new URL(request.url)
+    	const key = parsedUrl.pathname.replace(/^\/+/, '') // Strip any preceding /'s
+    	if(!key){
+    		return new Response('Missing path in URL', {
+    			status: 400
+    		})
+    	}
+
+    	// Get the mimetype from the key path
+    	const extension = key.split('.').pop();
+    	let mimeType = mime.getType(key) || "text/plain";
+    	if (mimeType.startsWith("text") || mimeType === "application/javascript") {
+    		mimeType += "; charset=utf-8";
+    	}
+
+    	// Get the value from the Workers KV store and return it if found
+    	const value = await env.assets.get(key, 'arrayBuffer')
+    	if(!value){
+    		return new Response("Not found", {
+    			status: 404
+    		})
+    	}
+
+    	// Return the response from the Workers application with the value from the KV store
+    	return new Response(value, {
+    		status: 200,
+    		headers: new Headers({
+    			"Content-Type": mimeType
+    		})
+    	});
+    },
 
-		//get the value from the KV store and return it if found
-		const value = await env.assets.get(key, 'arrayBuffer')
-		if(!value){
-			return new Response("Not found", {
-				status: 404
-			})
-		}
-		return new Response(value, {
-			status: 200,
-			headers: new Headers({
-				"Content-Type": mimeType
-			})
-		});
-	},
 } satisfies ExportedHandler<Env>;
-```
 
-This code will use the path within the URL and find the file associated to the path within the KV store. It also sets the proper MIME type in the response to indicate to the browser how to handle the response. To retrieve the value from the KV store, this code uses `arrayBuffer` to properly handle binary data such as images, documents, and video/audio files.
-
-To start the Worker, run the following within a terminal:
-
-```sh
-npx wrangler dev --remote
-```
+````
+</TabItem>
+<TabItem label="wrangler.jsonc">
+```json
+{
+	"$schema": "node_modules/wrangler/config-schema.json",
+	"name": "<ENTER_WORKER_NAME>",
+	"main": "src/index.ts",
+	"compatibility_date": "2025-03-03",
+	"observability": {
+		"enabled": true
+	},
+	"kv_namespaces": [
+		{
+			"binding": "assets",
+			"id": "<YOUR_BINDING_ID>"
+		}
+	]
+}
+````
 
-This will run you Worker code against your remote resources, specifically using the preview KV namespace as configured.
+</TabItem>
+</Tabs>
 
-```sh
-npx wrangler dev --remote
-```
+This code parses the key name for the key-value pair to fetch from the HTTP request. Then, it determines the proper MIME type for the response to indicate to the browser how to handle the response.
path: src/content/docs/kv/examples/workers-kv-to-serve-assets.mdx
user: login: Oxyjun
body: ```suggestion
This code parses the key name for the key-value pair to fetch from the HTTP request. Then, it determines the proper MIME type for the response to inform the browser how to handle the response.
```
created_at: 2025-03-10T13:43:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -137,92 +31,104 @@ Hello World!
 We can then use the following Wrangler commands to create a KV pair for this file within our production and preview namespaces:
 
 ```sh
-npx wrangler kv key put index.html --path index.html --binding assets --preview false
-npx wrangler kv key put index.html --path index.html --binding assets --preview
+npx wrangler kv key put index.html --path index.html --namespace-id=<ENTER_NAMESPACE_ID_HERE>
 ```
 
 This will create a KV pair with the filename as key and the file content as value, within the our production and preview namespaces specified by your binding in your Wrangler file.
 
-## 4. Serve static assets from KV from your Worker application
+## Serve static assets from KV from your Worker application
 
-Within the `index.ts` file of our Worker project, replace the contents with the following:
+In this example, our Workers application will accept any key name as the path of the HTTP request and return the value stored in the KV store for that key.
 
-```js title="index.ts"
+<Tabs>
+<TabItem label="index.ts">
+```js
 
-import mime from 'mime';
+import mime from "mime";
 
 interface Env {
-	assets: KVNamespace;
+assets: KVNamespace;
 }
 
 export default {
 	async fetch(request, env, ctx): Promise<Response> {
-		//return error if not a get request
+		// Return error if not a get request
 		if(request.method !== 'GET'){
 			return new Response('Method Not Allowed', {
 				status: 405,
 			})
 		}
 
-		//get the key from the url & return error if key missing
-		const parsedUrl = new URL(request.url)
-		const key = parsedUrl.pathname.replace(/^\/+/, '') // strip any preceding /'s
-		if(!key){
-			return new Response('Missing path in URL', {
-				status: 400
-			})
-		}
-
-		//get the mimetype from the key path
-		const extension = key.split('.').pop();
-		let mimeType = mime.getType(key) || "text/plain";
-		if (mimeType.startsWith("text") || mimeType === "application/javascript") {
-			mimeType += "; charset=utf-8";
-		}
+    	// Get the key from the url & return error if key missing
+    	const parsedUrl = new URL(request.url)
+    	const key = parsedUrl.pathname.replace(/^\/+/, '') // Strip any preceding /'s
+    	if(!key){
+    		return new Response('Missing path in URL', {
+    			status: 400
+    		})
+    	}
+
+    	// Get the mimetype from the key path
+    	const extension = key.split('.').pop();
+    	let mimeType = mime.getType(key) || "text/plain";
+    	if (mimeType.startsWith("text") || mimeType === "application/javascript") {
+    		mimeType += "; charset=utf-8";
+    	}
+
+    	// Get the value from the Workers KV store and return it if found
+    	const value = await env.assets.get(key, 'arrayBuffer')
+    	if(!value){
+    		return new Response("Not found", {
+    			status: 404
+    		})
+    	}
+
+    	// Return the response from the Workers application with the value from the KV store
+    	return new Response(value, {
+    		status: 200,
+    		headers: new Headers({
+    			"Content-Type": mimeType
+    		})
+    	});
+    },
 
-		//get the value from the KV store and return it if found
-		const value = await env.assets.get(key, 'arrayBuffer')
-		if(!value){
-			return new Response("Not found", {
-				status: 404
-			})
-		}
-		return new Response(value, {
-			status: 200,
-			headers: new Headers({
-				"Content-Type": mimeType
-			})
-		});
-	},
 } satisfies ExportedHandler<Env>;
-```
 
-This code will use the path within the URL and find the file associated to the path within the KV store. It also sets the proper MIME type in the response to indicate to the browser how to handle the response. To retrieve the value from the KV store, this code uses `arrayBuffer` to properly handle binary data such as images, documents, and video/audio files.
-
-To start the Worker, run the following within a terminal:
-
-```sh
-npx wrangler dev --remote
-```
+````
+</TabItem>
+<TabItem label="wrangler.jsonc">
+```json
+{
+	"$schema": "node_modules/wrangler/config-schema.json",
+	"name": "<ENTER_WORKER_NAME>",
+	"main": "src/index.ts",
+	"compatibility_date": "2025-03-03",
+	"observability": {
+		"enabled": true
+	},
+	"kv_namespaces": [
+		{
+			"binding": "assets",
+			"id": "<YOUR_BINDING_ID>"
+		}
+	]
+}
+````
 
-This will run you Worker code against your remote resources, specifically using the preview KV namespace as configured.
+</TabItem>
+</Tabs>
 
-```sh
-npx wrangler dev --remote
-```
+This code parses the key name for the key-value pair to fetch from the HTTP request. Then, it determines the proper MIME type for the response to indicate to the browser how to handle the response.
+To retrieve the value from the KV store, this code uses `arrayBuffer` to properly handle binary data such as images, documents, and video/audio files.
 
-```sh output
-Your worker has access to the following bindings:
-- KV Namespaces:
-  - assets: <GENERATED_PREVIEW_NAMESPACE_ID>
-[wrangler:inf] Ready on http://localhost:<PORT>
-```
+Given a sample key-value pair with key `index.html` with value containing some HTML content in our Workers KV namespace store, we can access our Workers application
+at `https://<YOUR-WORKER-HOSTNAME>/index.html` to see the contents of the `index.html` file.
 
-Access the URL provided by the Wrangler command as such `http://localhost:<PORT>/index.html`. You will be able to see the returned HTML file containing the file contents of our `index.html` file that was added to our KV store. Try it out with an image or a document and you will see that this Worker is also properly serving those assets from KV.
+Try it out with an image or a document and you will see that this Worker is also properly serving those assets from KV.
 
-## 5. Create an endpoint to generate dynamic responses from your key-value pairs
+## Generate dynamic responses from your key-value pairs
 
-We'll add a `hello-world` endpoint to our Workers application, which will return a "Hello World!" message based on the language requested to demonstrate how to generate a dynamic response from our KV-stored assets.
+In addition to serving static assets, we can also generate dynamic HTML or API responses based on the values stored in our KV store.
 
 Start by creating this file in the root of your project:
path: src/content/docs/kv/examples/workers-kv-to-serve-assets.mdx
user: login: Oxyjun
body: ```suggestion
1. Start by creating this file in the root of your project:
```
created_at: 2025-03-10T13:49:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -266,120 +172,133 @@ Start by creating this file in the root of your project:
 Open a terminal and enter the following KV command to create a KV entry for the translations file:
path: src/content/docs/kv/examples/workers-kv-to-serve-assets.mdx
user: login: Oxyjun
body: ```suggestion
2. Open a terminal and enter the following KV command to create a KV entry for the translations file:
```
created_at: 2025-03-10T13:49:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -266,120 +172,133 @@ Start by creating this file in the root of your project:
 Open a terminal and enter the following KV command to create a KV entry for the translations file:
 
 ```sh
-npx wrangler kv key put hello-world.json --path hello-world.json --binding assets --preview false
-npx wrangler kv key put hello-world.json --path hello-world.json --binding assets --preview
+npx wrangler kv key put hello-world.json --path hello-world.json --namespace-id=<ENTER_NAMESPACE_ID_HERE>
 ```
 
 Update your Workers code to add logic to serve a translated HTML file based on the language of the Accept-Language header of the request:
path: src/content/docs/kv/examples/workers-kv-to-serve-assets.mdx
user: login: Oxyjun
body: ```suggestion
3. Update your Workers code to add logic to serve a translated HTML file based on the language of the Accept-Language header of the request:
```
created_at: 2025-03-10T13:49:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,239 @@
+---
+type: example
+summary: Use Workers KV to as a geo-distributed, low-latency configuration store for your Workers application
+tags:
+  - KV
+pcx_content_type: configuration
+title: Build a distributed configuration store
+sidebar:
+  order: 5
+description: Example of how to use Workers KV to build a distributed application configuration store.
+---
+
+import { Render, PackageManagers, Tabs, TabItem } from "~/components";
+
+Storing application configuration data is an ideal use case for Workers KV. Configuration data can include data to personalize an application for each user or tenant, enable features for user groups, restrict access with allow-lists/deny-lists, etc. These use-cases can have high read volumes that are highly cacheable by Workers KV, which can ensure low-latency reads from your Workers application.
+
+In this example, application configuration data is used to personalize the Workers application for each user. The configuration data is stored in an external application and database and written to Workers KV using the REST API.
+
+## Write your configuration from your external application to Workers KV
+
+In some cases, your source-of-truth for your configuration data may be stored elsewhere than Workers KV.
+If this is the case, use the Workers KV REST API to write the configuration data to your Workers KV namespace. You may also
path: src/content/docs/kv/examples/distributed-configuration-with-workers-kv.mdx
user: login: thomasgauvin
body: ```suggestion
If this is the case, use the Workers KV REST API to write the configuration data to your Workers KV namespace. 
```
created_at: 2025-03-10T14:30:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,145 @@
+---
+type: example
+summary: Cache data or API responses in Workers KV to improve application performance
+tags:
+  - KV
+pcx_content_type: configuration
+title: Cache data with Workers KV
+sidebar:
+  order: 5
+description: Example of how to use Workers KV to build a distributed application configuration store.
+---
+
+import { Render, PackageManagers, Tabs, TabItem } from "~/components";
+
+Workers KV can be used as a persistent, single, global cache accessible from Cloudflare Workers to speed up your application.
+Data cached in Workers KV is accessible from all other Cloudflare locations as well, and persists until expiry or deletion.
+
+After fetching data from external resources in your Workers application, you can write the data to Workers KV.
+On subsequent Worker requests (in the same region or in other regions), you can read the cached data from Workers KV instead of calling the external API.
+This improves your Worker application's performance and resilience while reducing load on external resources.
+
+This example shows how you can cache data in Workers KV and read cached data from Workers KV in a Worker application.
+
+:::note[Note]
+
+You can also cache data in Workers with the [Cache API](https://developers.cloudflare.com/workers/runtime-apis/cache/). With the Cache API,
path: src/content/docs/kv/examples/cache-data-with-workers-kv.mdx
user: login: hyperlint-ai-deprecated[bot]
body: ### Identified issues

- Vale Style Guide - (cloudflare.LinkChecks-warning) **Warning**: When referring to another page in our docs, use the full relative link (`/1.1.1.1/check/`) instead of the full URL (`https://developers.cloudflare.com/1.1.1.1/check/`) or a local development link (`http://localhost:1111/1.1.1.1/check/`).

### Proposed fix

````suggestion
You can also cache data in Workers with the [Cache API](/workers/runtime-apis/cache/). With the Cache API,
````

The link should use a full relative path instead of a full URL to comply with the style guide. I've updated the link to use the relative path.
created_at: 2025-03-13T20:57:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,145 @@
+---
+type: example
+summary: Cache data or API responses in Workers KV to improve application performance
+tags:
+  - KV
+pcx_content_type: configuration
+title: Cache data with Workers KV
+sidebar:
+  order: 5
+description: Example of how to use Workers KV to build a distributed application configuration store.
+---
+
+import { Render, PackageManagers, Tabs, TabItem } from "~/components";
+
+Workers KV can be used as a persistent, single, global cache accessible from Cloudflare Workers to speed up your application.
+Data cached in Workers KV is accessible from all other Cloudflare locations as well, and persists until expiry or deletion.
+
+After fetching data from external resources in your Workers application, you can write the data to Workers KV.
+On subsequent Worker requests (in the same region or in other regions), you can read the cached data from Workers KV instead of calling the external API.
+This improves your Worker application's performance and resilience while reducing load on external resources.
+
+This example shows how you can cache data in Workers KV and read cached data from Workers KV in a Worker application.
+
+:::note[Note]
+
+You can also cache data in Workers with the [Cache API](/workers/runtime-apis/cache/). With the Cache API,
+the contents of the cache do not replicate outside of the originating data center and the cache is ephemeral (can be evicted).
+
+With Workers KV, the data is persisted by default to [central stores](/kv/concepts/how-kv-works/) and can be accessed from other Cloudflare locations.
path: src/content/docs/kv/examples/cache-data-with-workers-kv.mdx
user: login: thomasgauvin
body: ```suggestion
With Workers KV, the data is persisted by default to [central stores](/kv/concepts/how-kv-works/) (or can be set to [expire](kv/api/write-key-value-pairs/#expiring-keys), and can be accessed from other Cloudflare locations.
```
created_at: 2025-03-14T14:41:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,145 @@
+---
+type: example
+summary: Cache data or API responses in Workers KV to improve application performance
+tags:
+  - KV
+pcx_content_type: configuration
+title: Cache data with Workers KV
+sidebar:
+  order: 5
+description: Example of how to use Workers KV to build a distributed application configuration store.
+---
+
+import { Render, PackageManagers, Tabs, TabItem } from "~/components";
+
+Workers KV can be used as a persistent, single, global cache accessible from Cloudflare Workers to speed up your application.
+Data cached in Workers KV is accessible from all other Cloudflare locations as well, and persists until expiry or deletion.
+
+After fetching data from external resources in your Workers application, you can write the data to Workers KV.
+On subsequent Worker requests (in the same region or in other regions), you can read the cached data from Workers KV instead of calling the external API.
+This improves your Worker application's performance and resilience while reducing load on external resources.
+
+This example shows how you can cache data in Workers KV and read cached data from Workers KV in a Worker application.
+
+:::note[Note]
+
+You can also cache data in Workers with the [Cache API](https://developers.cloudflare.com/workers/runtime-apis/cache/). With the Cache API,
path: src/content/docs/kv/examples/cache-data-with-workers-kv.mdx
user: login: thomasgauvin
body: ```suggestion
You can also cache data in Workers with the [Cache API](/workers/runtime-apis/cache/). With the Cache API,
```
created_at: 2025-03-14T17:11:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,145 @@
+---
+type: example
+summary: Cache data or API responses in Workers KV to improve application performance
+tags:
+  - KV
+pcx_content_type: configuration
+title: Cache data with Workers KV
+sidebar:
+  order: 5
+description: Example of how to use Workers KV to build a distributed application configuration store.
+---
+
+import { Render, PackageManagers, Tabs, TabItem } from "~/components";
+
+Workers KV can be used as a persistent, single, global cache accessible from Cloudflare Workers to speed up your application.
+Data cached in Workers KV is accessible from all other Cloudflare locations as well, and persists until expiry or deletion.
+
+After fetching data from external resources in your Workers application, you can write the data to Workers KV.
+On subsequent Worker requests (in the same region or in other regions), you can read the cached data from Workers KV instead of calling the external API.
+This improves your Worker application's performance and resilience while reducing load on external resources.
+
+This example shows how you can cache data in Workers KV and read cached data from Workers KV in a Worker application.
+
+:::note[Note]
+
+You can also cache data in Workers with the [Cache API](/workers/runtime-apis/cache/). With the Cache API,
+the contents of the cache do not replicate outside of the originating data center and the cache is ephemeral (can be evicted).
+
+With Workers KV, the data is persisted by default to [central stores](/kv/concepts/how-kv-works/) (or can be set to [expire](kv/api/write-key-value-pairs/#expiring-keys), and can be accessed from other Cloudflare locations.
path: src/content/docs/kv/examples/cache-data-with-workers-kv.mdx
user: login: thomasgauvin
body: ### 
```suggestion
With Workers KV, the data is persisted by default to [central stores](/kv/concepts/how-kv-works/) (or can be set to [expire](/kv/api/write-key-value-pairs/#expiring-keys), and can be accessed from other Cloudflare locations.
```
created_at: 2025-03-14T17:12:22Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-03-08T23:47:14Z
body: Howdy and thanks for contributing to our repo. We review internal PRs within **1 week**. If it's something urgent or has been sitting without a comment, start a thread in the *Developer Docs* space internally.
author_association: CONTRIBUTOR
user: login: hyperlint-ai-deprecated[bot]
created_at: 2025-03-08T23:48:02Z
body: Howdy and thanks for contributing to our repo. The Cloudflare team reviews new, external PRs within **two (2) weeks**. If it's been two weeks or longer without any movement, please tag the PR **Assignees** in a comment.

We review internal PRs within **1 week**. If it's something urgent or has been sitting without a comment, start a thread in the *Developer Docs* space internally.

---

## PR Change Summary

Enhanced Workers KV documentation with new examples and improved clarity on usage.
- Added examples for caching data, distributed configuration, A/B testing, and routing with Workers KV.
- Updated existing example for serving static assets with improved explanations.
- Modified related resources to include links to new examples.


**Modified Files**

- `src/content/docs/kv/examples/workers-kv-to-serve-assets.mdx`
- `src/content/docs/kv/index.mdx`
- `src/content/docs/reference-architecture/diagrams/serverless/a-b-testing-using-workers.mdx`



**Added Files**

- `src/content/docs/kv/examples/cache-data-with-workers-kv.mdx`
- `src/content/docs/kv/examples/distributed-configuration-with-workers-kv.mdx`
- `src/content/docs/kv/examples/implement-ab-testing-with-workers-kv.mdx`
- `src/content/docs/kv/examples/routing-with-workers-kv.mdx`
 







---

<details>

<summary>How can I customize these reviews?</summary>

Check out the [Hyperlint AI Reviewer docs](https://docs.hyperlint.com/guides/ai-reviewer/) for more information on how to customize the review.

If you just want to ignore it on this PR, you can add the `hyperlint-ignore` label to the PR. Future changes won't trigger a Hyperlint review.

Note specifically for link checks, we only check the first 30 links in a file and we cache the results for several hours (for instance, if you just added a page, you might experience this). Our recommendation is to add `hyperlint-ignore` to the PR to ignore the link check for this PR.
</details>
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-03-08T23:54:29Z
body: **Preview URL:** https://c222fffb.preview.developers.cloudflare.com
**Preview Branch URL:** https://thomasgauvin-add-workers-kv-examples.preview.developers.cloudflare.com

**Files with changes (up to 15)**

| Original Link | Updated Link |
| --- | --- |
| [https://developers.cloudflare.com/kv/examples/workers-kv-to-serve-assets/](https://developers.cloudflare.com/kv/examples/workers-kv-to-serve-assets/) | [https://thomasgauvin-add-workers-kv-examples.preview.developers.cloudflare.com/kv/examples/workers-kv-to-serve-assets/](https://thomasgauvin-add-workers-kv-examples.preview.developers.cloudflare.com/kv/examples/workers-kv-to-serve-assets/) |
| [https://developers.cloudflare.com/kv/examples/distributed-configuration-with-workers-kv/](https://developers.cloudflare.com/kv/examples/distributed-configuration-with-workers-kv/) | [https://thomasgauvin-add-workers-kv-examples.preview.developers.cloudflare.com/kv/examples/distributed-configuration-with-workers-kv/](https://thomasgauvin-add-workers-kv-examples.preview.developers.cloudflare.com/kv/examples/distributed-configuration-with-workers-kv/) |
| [https://developers.cloudflare.com/kv/examples/routing-with-workers-kv/](https://developers.cloudflare.com/kv/examples/routing-with-workers-kv/) | [https://thomasgauvin-add-workers-kv-examples.preview.developers.cloudflare.com/kv/examples/routing-with-workers-kv/](https://thomasgauvin-add-workers-kv-examples.preview.developers.cloudflare.com/kv/examples/routing-with-workers-kv/) |
| [https://developers.cloudflare.com/kv/examples/cache-data-with-workers-kv/](https://developers.cloudflare.com/kv/examples/cache-data-with-workers-kv/) | [https://thomasgauvin-add-workers-kv-examples.preview.developers.cloudflare.com/kv/examples/cache-data-with-workers-kv/](https://thomasgauvin-add-workers-kv-examples.preview.developers.cloudflare.com/kv/examples/cache-data-with-workers-kv/) |
| [https://developers.cloudflare.com/kv/examples/implement-ab-testing-with-workers-kv/](https://developers.cloudflare.com/kv/examples/implement-ab-testing-with-workers-kv/) | [https://thomasgauvin-add-workers-kv-examples.preview.developers.cloudflare.com/kv/examples/implement-ab-testing-with-workers-kv/](https://thomasgauvin-add-workers-kv-examples.preview.developers.cloudflare.com/kv/examples/implement-ab-testing-with-workers-kv/) |
| [https://developers.cloudflare.com/reference-architecture/diagrams/serverless/a-b-testing-using-workers/](https://developers.cloudflare.com/reference-architecture/diagrams/serverless/a-b-testing-using-workers/) | [https://thomasgauvin-add-workers-kv-examples.preview.developers.cloudflare.com/reference-architecture/diagrams/serverless/a-b-testing-using-workers/](https://thomasgauvin-add-workers-kv-examples.preview.developers.cloudflare.com/reference-architecture/diagrams/serverless/a-b-testing-using-workers/) |
| [https://developers.cloudflare.com/kv/](https://developers.cloudflare.com/kv/) | [https://thomasgauvin-add-workers-kv-examples.preview.developers.cloudflare.com/kv/](https://thomasgauvin-add-workers-kv-examples.preview.developers.cloudflare.com/kv/) |
author_association: CONTRIBUTOR