Using D1 Read Replication for your e-commerce website
D1 Read Replication is a feature that allows you to replicate your D1 database to multiple regions. This is useful for your e-commerce website, as it reduces read latencies and improves read throughput. In this tutorial, you will learn how to use D1 read replication for your e-commerce website.
While this tutorial uses a fictional e-commerce website, the principles can be applied to any use-case that requires low read latencies and scaling reads, such as a news website, a social media platform, or a marketing website.
If you want to skip the steps and get started quickly, click on the below button:
This will create a repository in your GitHub account and deploy the application to Cloudflare Workers. It will also create and bind a D1 database, create the required tables, add some sample data. During deployment, tick the Enable read replication box to activate read replication.
You can then visit the deployed application.
- Sign up for a Cloudflare account ↗.
- Install
Node.js↗.
Node.js version manager
Use a Node version manager like Volta ↗ or nvm ↗ to avoid permission issues and change Node.js versions. Wrangler, discussed later in this guide, requires a Node version of 16.17.0 or later.
Create a new Workers project by running the following command:
npm create cloudflare@latest -- fast-commerce yarn create cloudflare fast-commerce pnpm create cloudflare@latest fast-commerce For setup, select the following options:
- For What would you like to start with?, choose
Hello World example. - For Which template would you like to use?, choose
SSR / full-stack app. - For Which language do you want to use?, choose
TypeScript. - For Do you want to use git for version control?, choose
Yes. - For Do you want to deploy your application?, choose
No(we will be making some changes before deploying).
For creating the API routes, you will use Hono ↗. You need to install Hono by running the following command:
npm i hono yarn add hono pnpm add hono bun add hono The above step creates a new Workers project with a default frontend and installs Hono. You will update the frontend to list the products. You will also add a new page to the frontend to display a single product.
Navigate to the newly created Worker project folder.
cd fast-commerceUpdate the public/index.html file to list the products. Use the below code as a reference.
public/index.html
<!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>E-commerce Store</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: Arial, sans-serif; }
body { background-color: #f9fafb; min-height: 100vh; display: flex; flex-direction: column; }
header { background-color: white; padding: 1rem 2rem; display: flex; justify-content: space-between; align-items: center; border-bottom: 1px solid #e5e7eb; }
.store-title { font-weight: bold; font-size: 1.25rem; }
.cart-button { padding: 0.5rem 1rem; cursor: pointer; background: none; border: none; }
.products-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 1.5rem; padding: 2rem; }
.product-card { background-color: white; border-radius: 0.5rem; overflow: hidden; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); }
.product-info { padding: 1rem; }
.product-title { font-size: 1.125rem; font-weight: 600; margin-bottom: 0.5rem; }
.product-description { color: #4b5563; font-size: 0.875rem; margin-bottom: 1rem; }
.product-price { font-size: 1.25rem; font-weight: bold; margin-bottom: 0.5rem; }
.product-stock { color: #4b5563; font-size: 0.875rem; margin-bottom: 1rem; }
.view-details-btn { display: block; width: 100%; padding: 0.5rem 0; background-color: #2563eb; color: white; border: none; border-radius: 0.375rem; cursor: pointer; text-align: center; text-decoration: none; font-size: 0.875rem; }
.view-details-btn:hover { background-color: #1d4ed8; }
footer { background-color: white; padding: 1rem 2rem; text-align: center; border-top: 1px solid #e5e7eb; color: #4b5563; font-size: 0.875rem; }
/* Basic Responsiveness */ @media (max-width: 768px) { .products-grid { grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); } }
@media (max-width: 480px) { .products-grid { grid-template-columns: 1fr; } } </style> </head> <body> <header> <h1 class="store-title">E-commerce Store</h1> <button class="cart-button">Cart</button> </header>
<main class="products-grid" id="products-container"> <!-- Products will be loaded here by JavaScript --> </main>
<footer> <p>© 2025 E-commerce Store. All rights reserved.</p> </footer>
<script> document.addEventListener('DOMContentLoaded', () => { let products = []; let d1Duration, queryDuration = 0; let dbLocation; let isPrimary = true;
// Function to create product HTML function createProductCard(product) { return ` <div class="product-card" data-category="${product.category}"> <div class="product-info"> <h3 class="product-title">${product.name}</h3> <p class="product-description">${product.description}</p> <p class="product-price">$${product.price.toFixed(2)}</p> <p class="product-stock">${product.inventory} in stock</p> <a href="proxy.php?url=https%3A%2F%2Fdevelopers.cloudflare.com%2Fd1%2Ftutorials%2Fusing-read-replication-for-e-com%2Fproduct-details.html%3Fid%3D%3C%2Fspan%3E%3Cspan+style%3D"--0:#89DDFF;--1:#007474">${product.id}" class="view-details-btn">View Details</a> </div> </div> `; }
// Function to render content function renderContent() { try { const productsContainer = document.getElementById('products-container'); if (!productsContainer) return; productsContainer.innerHTML = '';
products.forEach((product) => { productsContainer.innerHTML += createProductCard(product); }); } catch (error) { console.error('Error rendering content:', error); } }
// Fetch products fetch('/api/products') .then((response) => response.json()) .then((data) => { products = data; renderContent(); }) .catch((error) => console.error('Error fetching products:', error)); }); </script> </body>
</html>