Storage: D1, R2, KV & Hyperdrive
Cloudflare offers a complete storage stack for Python developers — from edge SQL databases to globally distributed key-value stores. Replace your entire data layer with zero egress fees.
D1: SQLite at the Edge
D1 is Cloudflare's serverless SQL database built on SQLite. It's globally distributed with automatic backups and 30-day point-in-time recovery (Time Travel).
from js import Response, env
async def on_fetch(request):
db = env.DB # It's just SQLite, but globally distributed
results = await db.prepare("""
SELECT user_id, COUNT(*) as request_count
FROM api_logs
WHERE timestamp > datetime('now', '-1 hour')
GROUP BY user_id
""").all()
return Response.json(results) Schema & Queries
# Create tables
await env.DB.prepare("""
CREATE TABLE IF NOT EXISTS events (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id TEXT NOT NULL,
event_type TEXT NOT NULL,
properties TEXT,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
)
""").run()
# Create indexes
await env.DB.prepare("""
CREATE INDEX IF NOT EXISTS idx_user_events
ON events(user_id, timestamp)
""").run()
# Insert with prepared statements
await env.DB.prepare(
"INSERT INTO events (user_id, event_type, properties) VALUES (?, ?, ?)"
).bind(user_id, event_type, json.dumps(properties)).run()
# Query with parameters
result = await env.DB.prepare("""
SELECT * FROM events
WHERE user_id = ?
ORDER BY timestamp DESC
LIMIT ?
""").bind(user_id, 100).all() D1 via the Python SDK
from cloudflare import Cloudflare
import pandas as pd
from typing import List, Dict, Any
client = Cloudflare()
# Create a D1 database
database = client.d1.database.create(
account_id="your-account-id",
name="analytics",
)
# Execute queries via the SDK
client.d1.database.query(
account_id="your-account-id",
database_id="your-database-id",
sql="INSERT INTO events (user_id, event_type) VALUES (?, ?)",
params=["user123", "page_view"],
) R2: S3-Compatible Object Storage
R2 provides S3-compatible object storage with zero egress fees. Use your existing boto3 code — just change the endpoint.
R2 in Python Workers
from js import Response, env
async def on_fetch(request):
# Store a file
await env.BUCKET.put("uploads/file.txt", request.body)
# Retrieve a file
object = await env.BUCKET.get("uploads/file.txt")
data = await object.text()
# Serve with proper content type
return Response.new(object.body, headers={
"Content-Type": object.httpMetadata.contentType
}) R2 via the Python SDK (boto3 Compatible)
from cloudflare import Cloudflare
import boto3
from datetime import timedelta
client = Cloudflare()
# Create an R2 bucket
bucket = client.r2.buckets.create(
account_id="your-account-id",
name="ml-models",
storage_class="Standard",
)
# Get temporary S3-compatible credentials
creds = client.r2.temporary_credentials.create(
account_id="your-account-id",
bucket=bucket.name,
permission="read_write",
ttl=timedelta(hours=1),
)
# Use with boto3 — zero code changes!
s3 = boto3.client(
"s3",
endpoint_url=f"https://{creds.account_id}.r2.cloudflarestorage.com",
aws_access_key_id=creds.access_key_id,
aws_secret_access_key=creds.secret_access_key,
aws_session_token=creds.session_token,
)
# Upload your ML model
s3.upload_file("model.pkl", bucket.name, "models/latest.pkl")
# List objects — no egress fees!
for obj in s3.list_objects_v2(Bucket=bucket.name)["Contents"]:
print(f"{obj['Key']}: {obj['Size']} bytes") Workers KV: Global Key-Value Store
Workers KV is a globally distributed key-value store — think Redis, but with no server management and global replication built in.
KV in Python Workers
from js import Response, env
async def on_fetch(request):
# Set a value
await env.KV.put("session:user123", json.dumps({"role": "admin"}))
# Get a value
value = await env.KV.get("session:user123")
# Set with expiration (TTL in seconds)
await env.KV.put("cache:results", data, expirationTtl=3600)
return Response.json({"session": value}) KV via the Python SDK
from cloudflare import Cloudflare
import json
import time
client = Cloudflare()
# Create a KV namespace
namespace = client.kv.namespaces.create(
account_id="your-account-id",
title="user-sessions",
)
# Set a value with optional TTL
client.kv.namespaces.values.update(
account_id="your-account-id",
namespace_id=namespace.id,
key_name="user:123",
value=json.dumps({"role": "admin"}),
metadata=json.dumps({"timestamp": time.time()}),
expiration_ttl=3600,
)
# Get a value
result = client.kv.namespaces.values.get(
account_id="your-account-id",
namespace_id=namespace.id,
key_name="user:123",
) Hyperdrive: Accelerate Existing Databases
Already have a PostgreSQL or MySQL database? Hyperdrive accelerates connections to your existing database by up to 10x — keep your ORM, get edge performance.
# Keep your SQLAlchemy code — Hyperdrive accelerates the connection
# wrangler.toml
# [[hyperdrive]]
# binding = "HYPERDRIVE"
# id = "your-hyperdrive-id"
from js import env
async def on_fetch(request):
# Hyperdrive provides an accelerated connection string
connection_string = env.HYPERDRIVE.connectionString
# Use with SQLAlchemy, psycopg2, or any DB driver
# Connection pooling and caching handled automatically Migration Reference
Map your existing storage stack to Cloudflare equivalents:
| You're Using | Replace With | Why Switch |
|---|---|---|
| Redis / Memcached | Workers KV | Globally distributed, no server management |
| PostgreSQL / MySQL | D1 (for new apps) | Serverless, automatic backups, Time Travel |
| SQLAlchemy + Postgres | Hyperdrive + SQLAlchemy | Keep your ORM, get 10x performance |
| boto3 + S3 | boto3 + R2 | Same API, zero egress fees |
| Pinecone / Weaviate | Vectorize | Integrated with Workers, no separate billing |