Hyperdrive
Demos and architectures
import { GlossaryTooltip, ResourcesBySelector } from "~/components";
Learn how you can use Hyperdrive within your existing application and architecture.
Reference architectures
Explore the following reference architectures that use Hyperdrive:
Getting started
import { Render, PackageManagers, Tabs, TabItem } from "~/components";
Hyperdrive accelerates access to your existing databases from Cloudflare Workers, making even single-region databases feel globally distributed.
By maintaining a connection pool to your database within Cloudflare's network, Hyperdrive reduces seven round-trips to your database before you can even send a query: the TCP handshake (1x), TLS negotiation (3x), and database authentication (3x).
Hyperdrive understands the difference between read and write queries to your database, and caches the most common read queries, improving performance and reducing load on your origin database.
This guide will instruct you through:
Creating your first Hyperdrive configuration.
Creating a Cloudflare Worker and binding it to your Hyperdrive configuration.
Establishing a database connection from your Worker to a public database.
:::note
Hyperdrive currently works with PostgreSQL, MySQL and many compatible databases. This includes CockroachDB and Materialize (which are PostgreSQL-compatible), Supabase, and PlanetScale.
Learn more about the databases that Hyperdrive supports.
:::
Prerequisites
Before you begin, ensure you have completed the following:
Sign up for a Cloudflare account if you have not already.
Install
Node.js.
For supported Node.js versions, refer to the Wrangler system requirements.
Have a publicly accessible PostgreSQL or MySQL (or compatible) database. If your database is in a private network, refer to Connect to a private database using Workers VPC.
1. Log in
Before creating your Hyperdrive binding, log in with your Cloudflare account by running:
npx wrangler login
You will be directed to a web page asking you to log in to the Cloudflare dashboard. After you have logged in, you will be asked if Wrangler can make changes to your Cloudflare account. Scroll down and select Allow to continue.
2. Create a Worker
:::note[New to Workers?]
Refer to How Workers works to learn about the Workers serverless execution model works. Go to the Workers Get started guide to set up your first Worker.
:::
Create a new project named
hyperdrive-tutorial by running:
This will create a new
hyperdrive-tutorial directory. Your new
hyperdrive-tutorial directory will include:
A
"Hello World" Worker at
src/index.ts.
A
wrangler.jsonc configuration file.
wrangler.jsonc is how your
hyperdrive-tutorial Worker will connect to Hyperdrive.
Enable Node.js compatibility
Node.js compatibility is required for database drivers, and needs to be configured for your Workers project.
3. Connect Hyperdrive to a database
Hyperdrive works by connecting to your database, pooling database connections globally, and speeding up your database access through Cloudflare's network.
It will provide a secure connection string that is only accessible from your Worker which you can use to connect to your database through Hyperdrive.
This means that you can use the Hyperdrive connection string with your existing drivers or ORM libraries without needing significant changes to your code.
To create your first Hyperdrive database configuration, change into the directory you just created for your Workers project:
cd hyperdrive-tutorial
To create your first Hyperdrive, you will need:
The IP address (or hostname) and port of your database.
The database username (for example,
hyperdrive-demo).
The password associated with that username.
The name of the database you want Hyperdrive to connect to. For example,
postgres or
mysql.
Hyperdrive accepts the combination of these parameters in the common connection string format used by database drivers:
```txt
postgres://USERNAME:PASSWORD@HOSTNAME_OR_IP_ADDRESS:PORT/database_name
```
Most database providers will provide a connection string you can copy-and-paste directly into Hyperdrive.
To create a Hyperdrive connection, run the
wrangler command, replacing the placeholder values passed to the
--connection-string flag with the values of your existing database:
npx wrangler hyperdrive create --connection-string="postgres://user:password@HOSTNAME_OR_IP_ADDRESS:PORT/database_name"
```txt
mysql://USERNAME:PASSWORD@HOSTNAME_OR_IP_ADDRESS:PORT/database_name
```
Most database providers will provide a connection string you can copy-and-paste directly into Hyperdrive.
To create a Hyperdrive connection, run the `wrangler` command, replacing the placeholder values passed to the `--connection-string` flag with the values of your existing database:
npx wrangler hyperdrive create --connection-string="mysql://user:password@HOSTNAME_OR_IP_ADDRESS:PORT/database_name"
:::note[Manage caching]
By default, Hyperdrive caches eligible read query results. If you wish to disable caching, pass the flag
--caching-disabled.
Alternatively, you can use the
--max-age flag to specify the maximum duration (in seconds) for which items should persist in the cache, before they are evicted. Default value is 60 seconds.
Hyperdrive does not invalidate cached read results when your application writes to your database. If your application needs read-after-write consistency, use a separate cache-disabled Hyperdrive configuration for the reads that must return fresh data. Refer to Query caching for guidance and Hyperdrive Wrangler commands for command options.
:::
If successful, the command will output your new Hyperdrive configuration:
{
"hyperdrive": [
{
"binding": "HYPERDRIVE",
"id": ""
}
]
}
Copy the
id field: you will use this in the next step to make Hyperdrive accessible from your Worker script.
:::note
Hyperdrive will attempt to connect to your database with the provided credentials to verify they are correct before creating a configuration. If you encounter an error when attempting to connect, refer to Hyperdrive's troubleshooting documentation to debug possible causes.
:::
4. Bind your Worker to Hyperdrive
5. Run a query against your database
Once you have created a Hyperdrive configuration and bound it to your Worker, you can run a query against your database.
Install a database driver
To connect to your database, you will need a database driver which allows you to authenticate and query your database. For this tutorial, you will use node-postgres (pg), one of the most widely used PostgreSQL drivers.
To install
pg, ensure you are in the
hyperdrive-tutorial directory. Open your terminal and run the following command:
If you are using TypeScript, you should also install the type definitions for
pg:
With the driver installed, you can now create a Worker script that queries your database.
To connect to your database, you will need a database driver which allows you to authenticate and query your database. For this tutorial, you will use mysql2, one of the most widely used MySQL drivers.
To install
mysql2, ensure you are in the
hyperdrive-tutorial directory. Open your terminal and run the following command:
With the driver installed, you can now create a Worker script that queries your database.
Write a Worker
After you have set up your database, you will run a SQL query from within your Worker.
Go to your
hyperdrive-tutorial Worker and open the
index.ts file.
The
index.ts file is where you configure your Worker's interactions with Hyperdrive.
Populate your
index.ts file with the following code:
// pg 8.16.3 or later is recommended
import { Client } from "pg";
export interface Env {
// If you set another name in the Wrangler config file as the value for 'binding',
// replace "HYPERDRIVE" with the variable name you defined.
HYPERDRIVE: Hyperdrive;
}
export default {
async fetch(request, env, ctx): Promise {
// Create a new client on each request. Hyperdrive maintains the underlying
// database connection pool, so creating a new client is fast.
const sql = new Client({
connectionString: env.HYPERDRIVE.connectionString,
});
try {
// Connect to the database
await sql.connect();
// Sample query
const results = await sql.query(`SELECT * FROM pg_tables`);
// Return result rows as JSON
return Response.json(results.rows);
} catch (e) {
console.error(e);
return Response.json(
{ error: e instanceof Error ? e.message : e },
{ status: 500 },
);
}
},
} satisfies ExportedHandler;
Upon receiving a request, the code above does the following:
Creates a new database client configured to connect to your database via Hyperdrive, using the Hyperdrive connection string.
Initiates a query via
await sql.query() that outputs all tables (user and system created) in the database (as an example query).
Returns the response as JSON to the client. Hyperdrive automatically cleans up the client connection when the request ends, and keeps the underlying database connection open in its pool for reuse.
After you have set up your database, you will run a SQL query from within your Worker.
Go to your
hyperdrive-tutorial Worker and open the
index.ts file.
The
index.ts file is where you configure your Worker's interactions with Hyperdrive.
Populate your
index.ts file with the following code:
// mysql2 v3.13.0 or later is required
import { createConnection } from "mysql2/promise";
export interface Env {
// If you set another name in the Wrangler config file as the value for 'binding',
// replace "HYPERDRIVE" with the variable name you defined.
HYPERDRIVE: Hyperdrive;
}
export default {
async fetch(request, env, ctx): Promise {
// Create a new connection on each request. Hyperdrive maintains the underlying
// database connection pool, so creating a new connection is fast.
const connection = await createConnection({
host: env.HYPERDRIVE.host,
user: env.HYPERDRIVE.user,
password: env.HYPERDRIVE.password,
database: env.HYPERDRIVE.database,
port: env.HYPERDRIVE.port,
// The following line is needed for mysql2 compatibility with Workers
// mysql2 uses eval() to optimize result parsing for rows with > 100 columns
// Configure mysql2 to use static parsing instead of eval() parsing with disableEval
disableEval: true,
});
try {
// Sample query
const [results, fields] = await connection.query("SHOW tables;");
// Return result rows as JSON
return new Response(JSON.stringify({ results, fields }), {
headers: {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
},
});
} catch (e) {
console.error(e);
return Response.json(
{ error: e instanceof Error ? e.message : e },
{ status: 500 },
);
}
},
} satisfies ExportedHandler;
Upon receiving a request, the code above does the following:
Creates a new database client configured to connect to your database via Hyperdrive, using the Hyperdrive connection string.
Initiates a query via
await connection.query that outputs all tables (user and system created) in the database (as an example query).
Returns the response as JSON to the client. Hyperdrive automatically cleans up the client connection when the request ends, and keeps the underlying database connection open in its pool for reuse.
Run in development mode (optional)
You can test your Worker locally before deploying by running
wrangler dev. This runs your Worker code on your machine while connecting to your database.
The
localConnectionString field works with both local and remote databases and allows you to connect directly to your database from your Worker project running locally. You must specify the SSL/TLS mode if required (
sslmode=require for Postgres,
sslMode=REQUIRED for MySQL).
To connect to a database during local development, configure
localConnectionString in your
wrangler.jsonc:
{
"hyperdrive": [
{
"binding": "HYPERDRIVE",
"id": "your-hyperdrive-id",
"localConnectionString": "postgres://user:password@your-database-host:5432/database",
},
],
}
Or set an environment variable:
export CLOUDFLARE_HYPERDRIVE_LOCAL_CONNECTION_STRING_HYPERDRIVE="postgres://user:password@your-database-host:5432/database"
Then start local development:
npx wrangler dev
:::note
When using
wrangler dev with
localConnectionString or
CLOUDFLARE_HYPERDRIVE_LOCAL_CONNECTION_STRING_HYPERDRIVE, Hyperdrive caching does not take effect locally.
Alternatively, you can run
wrangler dev --remote to test against your deployed Hyperdrive configuration with caching enabled, but this runs your entire Worker in Cloudflare's network instead of locally.
Learn more about local development with Hyperdrive.
:::
6. Deploy your Worker
You can now deploy your Worker to make your project accessible on the Internet. To deploy your Worker, run:
npx wrangler deploy
# Outputs: https://hyperdrive-tutorial..workers.dev
You can now visit the URL for your newly created project to query your live database.
For example, if the URL of your new Worker is
hyperdrive-tutorial..workers.dev, accessing
https://hyperdrive-tutorial..workers.dev/ will send a request to your Worker that queries your database directly.
By finishing this tutorial, you have created a Hyperdrive configuration, a Worker to access that database and deployed your project globally.
Next steps
Learn more about how Hyperdrive works.
How to configure query caching.
Troubleshooting common issues when connecting a database to Hyperdrive.
If you have any feature requests or notice any bugs, share your feedback directly with the Cloudflare team by joining the Cloudflare Developers community on Discord.
Hyperdrive (Postgres & MySQL)
import {
CardGrid,
Description,
Feature,
LinkTitleCard,
Plan,
RelatedProduct,
Tabs,
TabItem,
LinkButton,
} from "~/components";
Turn your existing regional database into a globally distributed database.
Hyperdrive is a service that accelerates queries you make to existing databases, making it faster to access your data from across the globe from Cloudflare Workers, irrespective of your users' location.
Hyperdrive supports any Postgres or MySQL database, including those hosted on AWS, Google Cloud, Azure, Supabase, Neon, and PlanetScale. Hyperdrive also supports Postgres-compatible databases like CockroachDB and Timescale.
You do not need to write new code or replace your favorite tools: Hyperdrive works with your existing code and tools you use.
Use Hyperdrive's connection details from your Cloudflare Workers application with your existing database drivers and object-relational mapping (ORM) libraries.
Examples
PostgreSQL
```ts
import { Client } from "pg";
export default {
async fetch(request, env, ctx): Promise {
// Create a new client instance for each request. Hyperdrive maintains the
// underlying database connection pool, so creating a new client is fast.
const client = new Client({
connectionString: env.HYPERDRIVE.connectionString,
});
try {
// Connect to the database
await client.connect();
// Sample SQL query
const result = await client.query("SELECT * FROM pg_tables");
return Response.json(result.rows);
} catch (e) {
return Response.json({ error: e instanceof Error ? e.message : e }, { status: 500 });
}
},
} satisfies ExportedHandler<{ HYPERDRIVE: Hyperdrive }>;
```json
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "WORKER-NAME",
"main": "src/index.ts",
"upload_source_maps": true,
"compatibility_date": "2025-02-04",
"compatibility_flags": [
"nodejs_compat"
],
"observability": {
"enabled": true
},
"hyperdrive": [
{
"binding": "HYPERDRIVE",
"id": "",
"localConnectionString": ""
}
]
}
MySQL
```ts
import { createConnection } from 'mysql2/promise';
export default {
async fetch(request, env, ctx): Promise {
// Create a new connection on each request. Hyperdrive maintains the
// underlying database connection pool, so creating a new client is fast.
const connection = await createConnection({
host: env.HYPERDRIVE.host,
user: env.HYPERDRIVE.user,
password: env.HYPERDRIVE.password,
database: env.HYPERDRIVE.database,
port: env.HYPERDRIVE.port,
// This is needed to use mysql2 with Workers
// This configures mysql2 to use static parsing instead of eval() parsing (not available on Workers)
disableEval: true
});
const [results, fields] = await connection.query('SHOW tables;');
return new Response(JSON.stringify({ results, fields }), {
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
});
}} satisfies ExportedHandler<{ HYPERDRIVE: Hyperdrive }>;
```json
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "WORKER-NAME",
"main": "src/index.ts",
"upload_source_maps": true,
"compatibility_date": "2025-02-04",
"compatibility_flags": [
"nodejs_compat"
],
"observability": {
"enabled": true
},
"hyperdrive": [
{
"binding": "HYPERDRIVE",
"id": "",
"localConnectionString": ""
}
]
}
Get started
Features
Connect Hyperdrive to your existing database and deploy a Worker that queries it.
Hyperdrive allows you to connect to any PostgreSQL or PostgreSQL-compatible database.
Hyperdrive allows you to connect to any MySQL database.
Default-on caching for your most popular queries executed against your database.
Related products
Build serverless applications and deploy instantly across the globe for exceptional performance, reliability, and scale.
Deploy dynamic front-end applications in record time.
More resources
",
"timestamp": "",
"signature": ""
}
pscale database create accepts this payload through its
--cloudflare-billing flag. Passing
@- makes the PlanetScale CLI read it from standard input, which we recommend over passing the signature as a command line argument:
npx wrangler hyperdrive planetscale signature | \
pscale database create \
--org \
--engine postgresql \
--cloudflare-billing @- \
--format json
pscale database create defaults to Vitess, so pass
--engine postgresql for a Postgres database, and
--format json is recommended when the output is consumed by an agent.
Your PlanetScale credentials stay between you and
pscale. Wrangler authorizes the Cloudflare billing side only.
The signature is a cryptographically signed token that authorizes creating a database billed to your Cloudflare account. Treat it as a credential and do not share it.
Refer to PlanetScale's documentation for the options
pscale database create supports.
Workers + PlanetScale
With Workers, build your application to deploy anywhere across Cloudflare’s global network spanning 330+ cities. You can deploy with a single step, and users in new locations can reach your application without deploying regional infrastructure.
Workers compute runs close to your users for low latency. PlanetScale Postgres provides regional databases for your application's control plane or any centralized data that doesn't fit Cloudflare's edge distribution model. Use it for records such as customers, billing, account settings, or other relational data.
Hyperdrive provides the connection glue between Workers and PlanetScale. It pools database connections and uses Cloudflare's Cache for eligible read queries to make your application fast even when your database is centralized.
How you benefit?
Run near the user. When a user sends a request, Cloudflare routes it to a nearby location. Your Worker runs in that location, so request handling starts close to the user.
Check for cached reads locally. On the same Cloudflare server handling the Worker request, Hyperdrive sets up your database connection in single digit milliseconds (p90 4ms) so that your database client/driver can send queries immediately. Hyperdrive's connection setup performs TCP connection startup, TLS encryption, and client authentication all on the same local machine, removing any network roundtrips and latency to your database. Once the database connection is ready if the Worker sends a cacheable read query and the result is cached, Hyperdrive returns it without leaving that location.
Forward when needed with caching in-between. If no local cached result exists, or if the query cannot be cached, Hyperdrive sends the query across Cloudflare's network to a location close to your PlanetScale database. Hyperdrive checks another cache in that location before it reaches the database; this cache is populated by multiple requests to your database to improve your cache hit ratios similar to tiered caching .
Query PlanetScale only when necessary. If neither cache has the result, Hyperdrive sends the query to PlanetScale using an already available pool of database connections. Writes and other uncacheable queries go to PlanetScale so the database remains the source of truth. Multiple layers of caching reduce overall load on your database.
Hyperdrive does not invalidate cached read results when your application writes to PlanetScale. If your application needs read-after-write consistency for authentication, sessions, permissions, or another critical path, use a separate cache-disabled Hyperdrive configuration for those reads. Refer to Query caching for guidance.
PlanetScale developer experience
Postgres or MySQL
Choose PlanetScale Postgres or MySQL, and keep using familiar database drivers, object-relational mapping (ORM) libraries, and SQL tooling.
Performance and reliability
Run production databases on PlanetScale infrastructure with commitment to performance and reliability that power trusted customer workloads.
Modern development workflow
Use development branches to test database changes, query insights to understand query performance, and the Model Context Protocol (MCP) server to give agents access to database insights data, all without needing a database administrator (DBA).
Cloudflare billing
When you create a PlanetScale database from the Cloudflare dashboard, you are billed via your Cloudflare account — you will see a line item on your Cloudflare invoice for your PlanetScale usage. The pricing for PlanetScale is the same when you create and use databases via Cloudflare as it is when you buy directly from PlanetScale. For more pricing details, refer to PlanetScale's pricing. You can introspect per-database billing usage via PlanetScale's dashboard.
FAQ
Support for your PlanetScale databases created via Cloudflare is provided by PlanetScale at their Standard level support or your procured PlanetScale support plan. For help with your PlanetScale database, refer to PlanetScale Support for more information or contact the PlanetScale support team directly via the PlanetScale support portal.
For pay-as-you-go Cloudflare accounts, a PlanetScale database is billed daily from when the database is created until the database is deleted. Your database is billed whether or not you execute queries or store data.
{
const client = new Client({
connectionString: env.HYPERDRIVE.connectionString,
});
await client.connect();
const result = await client.query("SELECT * FROM pg_tables");
// No need to call client.end() — Hyperdrive automatically cleans
// up the client connection when the request ends. The underlying
// pooled connection to your origin database remains open for reuse.
return Response.json(result.rows);
},
} satisfies ExportedHandler;
:::note[Create database clients inside your handlers]
You should always create database clients inside your request handlers (
fetch,
queue, and similar), not in the global scope. Workers do not allow I/O across requests, and Hyperdrive's distributed connection pooling already solves for connection startup latency. Using a driver-level pool (such as
new Pool() or
createPool()) in the global script scope will leave you with stale connections that result in failed queries and hard errors.
:::
Do not create database clients or connection pools in the global scope. Instead, create a new client inside each handler invocation — Hyperdrive's connection pool ensures this is fast:
```ts
import { Client } from "pg";
// 🔴 Bad: Client created in the global scope persists across requests.
// Workers do not allow I/O across request contexts, so this client
// becomes stale and subsequent queries will throw hard errors.
const globalClient = new Client({
connectionString: env.HYPERDRIVE.connectionString,
});
await globalClient.connect();
export default {
async fetch(request, env, ctx): Promise {
// ✅ Good: Client created inside the handler, scoped to this request.
// Hyperdrive pools the underlying connection to your origin database,
// so creating a new client per request is fast and reliable.
const client = new Client({
connectionString: env.HYPERDRIVE.connectionString,
});
await client.connect();
const result = await client.query("SELECT * FROM pg_tables");
return Response.json(result.rows);
},
} satisfies ExportedHandler;
## Connection lifecycle considerations
### Durable Objects and persistent connections
Unlike regular Workers, [Durable Objects](/durable-objects/) can maintain state across multiple requests. If you keep a database client open in a Durable Object, the connection will remain allocated from Hyperdrive's connection pool. Long-lived Durable Objects can exhaust available connections if many objects keep connections open simultaneously.
:::caution
Be careful when maintaining persistent database connections in Durable Objects. Each open connection consumes resources from Hyperdrive's connection pool, which could impact other parts of your application. Close connections when not actively in use, use connection timeouts, and limit the number of Durable Objects that maintain database connections.
:::
### Long-running transactions
Hyperdrive operates in [transaction pooling mode](/hyperdrive/concepts/how-hyperdrive-works/#pooling-mode), where a connection is held for the duration of a transaction. Long-running transactions that contain multiple queries can exhaust Hyperdrive's available connections more quickly because each transaction holds a connection from the pool until it completes.
:::tip
Keep transactions as short as possible. Perform only the essential queries within a transaction, and avoid including non-database operations (like external API calls or complex computations) inside transaction blocks.
:::
Refer to [Limits](/hyperdrive/platform/limits/) to understand how many connections are available for your Hyperdrive configuration based on your Workers plan.
## Related resources
- [How Hyperdrive works](/hyperdrive/concepts/how-hyperdrive-works/)
- [Connection pooling](/hyperdrive/concepts/connection-pooling/)
- [Limits](/hyperdrive/platform/limits/)
- [Durable Objects](/durable-objects/)
Connection pooling
import { Render } from "~/components";
Hyperdrive maintains a pool of connections to your database. These are optimally placed to minimize the latency for your applications. You can configure
the amount of connections your Hyperdrive configuration uses to connect to your origin database. This enables you to right-size your connection pool based on your database capacity and application requirements.
For instance, if your Worker makes many queries to your database (which cannot be resolved by Hyperdrive's caching), you may want to allow Hyperdrive to make more connections to your database.
Conversely, if your Worker makes few queries that actually need to reach your database or if your database allows a small number of database connections, you can reduce the amount of connections Hyperdrive will make to your database.
All configurations have a minimum of 5 connections, and with a maximum depending on your Workers plan. Refer to the limits for details.
How Hyperdrive pools database connections
Hyperdrive will automatically scale the amount of database connections held open by Hyperdrive depending on your traffic and the amount of load that is put on your database.
The
max_size parameter acts as a soft limit - Hyperdrive may temporarily create additional connections during network issues or high traffic periods to ensure high availability and resiliency.
Restart the connection pool
Hyperdrive manages the connection pool for you, including automatic detection and recovery from most database failovers. In rare cases, you may need to restart the pool manually as a break-glass action — for example, after a database failover where Hyperdrive has not yet cycled its connections to the new primary.
To restart, select your Hyperdrive configuration in the Cloudflare dashboard, go to the Settings tab, and select Restart under Danger zone. Restarting requires the Hyperdrive Admin role.
Restarting drains the existing connection pool and forces Hyperdrive to establish new connections to your origin database. After a restart, the Settings tab shows when the configuration was last manually restarted.
:::caution
Restarting drops all active connections in the pool and forces them to be re-established. In-flight queries may see brief errors while the pool rebuilds.
:::
Pooling mode
Best practices
You can configure connection counts using the Cloudflare dashboard or the Cloudflare API. Consider the following best practices to determine the right limit for your use-case:
Start conservatively: Begin with a lower connection count and increase as needed based on your application's performance.
Monitor database metrics: Watch your database's connection usage and performance metrics to optimize the connection count.
Consider database limits: Ensure your configured connection count doesn't exceed your database's maximum connection limit.
Account for multiple configurations: If you have multiple Hyperdrive configurations connecting to the same database, consider the total connection count across all configurations.
Next steps
Learn more about How Hyperdrive works.
Review Hyperdrive limits for your Workers plan.
Learn how to Connect to PostgreSQL from Hyperdrive.
How Hyperdrive works
import { Render } from "~/components";
Connecting to traditional centralized databases from Cloudflare's global network which consists of over 300 data center locations presents a few challenges as queries can originate from any of these locations.
If your database is centrally located, queries can take a long time to get to the database and back. Queries can take even longer in situations where you have to establish new connections from stateless environments like Workers, requiring multiple round trips for each Worker invocation.
Traditional databases usually handle a maximum number of connections. With any reasonably large amount of distributed traffic, it becomes easy to exhaust these connections.
Hyperdrive solves these challenges by managing the number of global connections to your origin database, selectively parsing and choosing which query response to cache while reducing loading on your database and accelerating your database queries.
How Hyperdrive makes databases fast globally
Hyperdrive accelerates database queries by:
Performing the connection setup for new database connections near your Workers
Pooling existing connections near your database
Caching query results
This ensures you have optimal performance when connecting to your database from Workers (whether your queries are cached or not).
1. Edge connection setup
When a database driver connects to a database from a Cloudflare Worker directly, it will first go through the connection setup. This may require multiple round trips to the database in order to verify and establish a secure connection. This can incur additional network latency due to the distance between your Cloudflare Worker and your database.
With Hyperdrive, this connection setup occurs between your Cloudflare Worker and Hyperdrive on the edge, as close to your Worker as possible (see diagram, label 1. Connection setup). This incurs significantly less latency, since the connection setup is completed within the same location.
Learn more about how connections work between Workers and Hyperdrive in Connection lifecycle.
2. Connection Pooling
Hyperdrive creates a pool of connections to your database that can be reused as your application executes queries against your database.
The pool of database connections is placed in one or more regions closest to your origin database. This minimizes the latency incurred by roundtrips between your Cloudflare Workers and database to establish new connections. This also ensures that as little network latency is incurred for uncached queries.
If the connection pool has pre-existing connections, the connection pool will try and reuse that connection (see diagram, label 2. Existing warm connection).
If the connection pool does not have pre-existing connections, it will establish a new connection to your database and use that to route your query. This aims at reusing and creating the least number of connections possible as required to operate your application.
:::note
Hyperdrive automatically manages the connection pool properties for you, including limiting the total number of connections to your origin database. Refer to Limits to learn more.
:::
Learn more about connection pooling behavior and configuration in Connection pooling.
3. Query Caching
Hyperdrive supports caching of non-mutating (read) queries to your database.
When queries are sent via Hyperdrive, Hyperdrive parses the query and determines whether the query is a mutating (write) or non-mutating (read) query.
For non-mutating queries, Hyperdrive caches the response for the configured
max_age. When your Worker sends a later query that matches the original, Hyperdrive returns the cached response instead of sending the query back to the origin database.
Caching reduces the burden on your origin database and accelerates the response times for your queries.
Hyperdrive does not invalidate cached read query results when your application writes to your database. If your application needs read-after-write consistency, refer to Query caching for guidance on using a separate cache-disabled Hyperdrive configuration for reads that must return fresh data.
Learn more about query caching behavior and configuration in Query caching.
Pooling mode
Related resources
Connection lifecycle
Query caching
Connection pooling
Concepts
Learn about the core concepts and architecture behind Hyperdrive.
Query caching
import { TabItem, Tabs, WranglerConfig } from "~/components";
Hyperdrive automatically caches cacheable read queries that your Worker sends to your database when query caching is turned on. This reduces database load and avoids a network round trip to your database for popular queries. Query caching is enabled by default.
What does Hyperdrive cache?
Hyperdrive uses database protocols to differentiate between a mutating query (a query that writes to the database) and a non-mutating query (a read-only query). Hyperdrive caches eligible read-only query responses and does not cache writes.
Besides determining the difference between a
SELECT and an
INSERT, Hyperdrive also parses the database wire-protocol and uses it to differentiate between a mutating or non-mutating query.
For example, a read query that populates the front page of a news site would be cached:
-- Cacheable: uses a parameterized date value instead of CURRENT_DATE
SELECT * FROM articles WHERE DATE(published_time) = $1
ORDER BY published_time DESC LIMIT 50
-- Cacheable: uses a parameterized date value instead of CURDATE()
SELECT * FROM articles WHERE DATE(published_time) = ?
ORDER BY published_time DESC LIMIT 50
Mutating queries (including
INSERT,
UPSERT, or
CREATE TABLE) and queries that use functions designated as
volatile or
stable by PostgreSQL are not cached:
```sql
-- Not cached: mutating queries
INSERT INTO users(id, name, email) VALUES(555, 'Matt', 'hello@example.com');
-- Not cached: LASTVAL() is a volatile function
SELECT LASTVAL(), * FROM articles LIMIT 50;
-- Not cached: NOW() is a stable function
SELECT * FROM events WHERE created_at > NOW() - INTERVAL '1 hour';
```
```sql
-- Not cached: mutating queries
INSERT INTO users(id, name, email) VALUES(555, 'Thomas', 'hello@example.com');
-- Not cached: LAST_INSERT_ID() is a volatile function
SELECT LAST_INSERT_ID(), * FROM articles LIMIT 50;
-- Not cached: NOW() returns a non-deterministic value
SELECT * FROM events WHERE created_at > NOW() - INTERVAL 1 HOUR;
```
Common PostgreSQL functions that are not cacheable include:
Function
PostgreSQL volatility category
Cached
NOW()
STABLE
No
CURRENT_TIMESTAMP
STABLE
No
CURRENT_DATE
STABLE
No
CURRENT_TIME
STABLE
No
LOCALTIME
STABLE
No
LOCALTIMESTAMP
STABLE
No
TIMEOFDAY()
VOLATILE
No
RANDOM()
VOLATILE
No
LASTVAL()
VOLATILE
No
TXID_CURRENT()
STABLE
No
Only functions designated as
IMMUTABLE by PostgreSQL (functions whose return value never changes for the same inputs) are compatible with Hyperdrive caching. If your query uses a
STABLE or
VOLATILE function, move the function call to your application code and pass the resulting value as a query parameter instead.
:::caution[Do not use SQL comments as cache controls]
Hyperdrive uses text-based pattern matching to detect some uncacheable functions in your queries. This can include function names inside SQL comments.
Comments that contain volatile or uncacheable function names, such as
-- NOW() or
-- RANDOM(), can cause the query to be treated as uncacheable. However, comment text that does not contain uncacheable function names does not change the cache key.
For example:
A:
/* some text here */ SELECT * FROM some_table;
B:
/* some different text here */ SELECT * FROM some_table;
Both A and B share the same cached value. If A is run before B, B will receive the value cached by A.
Hyperdrive does not document SQL comments as a cache-control API, and parser behavior can differ between database engines. Use a cache-disabled Hyperdrive configuration when you need a guaranteed fresh read.
Avoid referencing uncacheable function names anywhere in query text, including comments.
:::
Default cache settings
The default caching behavior for Hyperdrive is:
max_age = 60 seconds (1 minute)
stale_while_revalidate = 15 seconds
The
max_age setting determines the maximum lifetime a query response will be served from cache. Cached responses may be evicted from the cache prior to this time if they are rarely used.
The
stale_while_revalidate setting allows Hyperdrive to continue serving stale cache results for an additional period of time while it is revalidating the cache. In most cases, revalidation should happen rapidly.
You can set a maximum
max_age of 1 hour.
Read-after-write behavior
Hyperdrive does not purge or invalidate cached read query results when your application writes to your database. A later matching
SELECT can return the cached result until the configured
max_age expires. Hyperdrive can also serve the result during the
stale_while_revalidate window while it refreshes the cache in the background.
Writes still go to your database. Hyperdrive only caches eligible read query responses.
This means you should choose a caching strategy based on how fresh each read must be:
Use query caching for reads that can tolerate brief staleness. Good examples include public content, dashboards, search results, product catalogs, and other high-volume reads where a short delay after writes is acceptable.
Lower
max_age and
stale_while_revalidate when a short stale window works. This keeps query caching enabled while reducing how long Hyperdrive can serve an older result.
Use a cache-disabled Hyperdrive configuration for reads that must be fresh. Create a second Hyperdrive configuration with
--caching-disabled, bind it alongside your cached configuration, and route those reads through the cache-disabled binding. Good examples include authentication, sessions, permissions, billing state, admin settings, and reads immediately after a write. Refer to Disable caching for an example.
Disable query caching everywhere only when most reads must be fresh. You still get Hyperdrive's connection pooling and fast connection setup when caching is disabled.
If an object-relational mapping (ORM) library or authentication library owns the SQL, create separate database clients for the cached and cache-disabled Hyperdrive bindings. Pass the cache-disabled client to the library or module that needs fresh reads, and use the cached client for reads that can tolerate the configured stale window.
Disable caching
Disable caching on a per-Hyperdrive configuration basis by using the Wrangler CLI to set the
--caching-disabled option.
To create a separate cache-disabled Hyperdrive configuration against the same database:
npx wrangler hyperdrive create my-database-fresh --connection-string="" --caching-disabled
To turn off caching on an existing Hyperdrive configuration:
npx wrangler hyperdrive update --caching-disabled
You can configure multiple Hyperdrive connections from a single application: one connection that enables caching for popular queries, and a second connection for fresh reads that should not use query caching.
When you use multiple Hyperdrive configurations for the same database, account for the total origin connections across configurations. Refer to Tune connection pool for guidance.
For example, using database drivers:
```ts title="index.ts"
export default {
async fetch(request, env, ctx): Promise {
// Create clients inside your handler — not in global scope
const client = postgres(env.HYPERDRIVE.connectionString);
// Use the cache-disabled binding for auth, permissions, and reads after writes.
const clientNoCache = postgres(env.HYPERDRIVE_CACHE_DISABLED.connectionString);
// ...
},
} satisfies ExportedHandler;
```
```ts title="index.ts"
export default {
async fetch(request, env, ctx): Promise {
// Create connections inside your handler — not in global scope
const connection = await createConnection({
host: env.HYPERDRIVE.host,
user: env.HYPERDRIVE.user,
password: env.HYPERDRIVE.password,
database: env.HYPERDRIVE.database,
port: env.HYPERDRIVE.port,
});
// Use the cache-disabled binding for auth, permissions, and reads after writes.
const connectionNoCache = await createConnection({
host: env.HYPERDRIVE_CACHE_DISABLED.host,
user: env.HYPERDRIVE_CACHE_DISABLED.user,
password: env.HYPERDRIVE_CACHE_DISABLED.password,
database: env.HYPERDRIVE_CACHE_DISABLED.database,
port: env.HYPERDRIVE_CACHE_DISABLED.port,
});
// ...
},
} satisfies ExportedHandler;
```
The Wrangler configuration remains the same both for PostgreSQL and MySQL.
{
"hyperdrive": [
{
"binding": "HYPERDRIVE",
"id": "",
},
{
"binding": "HYPERDRIVE_CACHE_DISABLED",
"id": "",
},
],
}
Next steps
For more information, refer to How Hyperdrive works.
To connect to PostgreSQL, refer to Connect to PostgreSQL.
For troubleshooting guidance, refer to Troubleshoot and debug.
Connect to a private database using Workers VPC (Recommended)
import { Render, Tabs, TabItem } from "~/components";
Workers VPC provides a way to connect Hyperdrive to a private database without configuring Cloudflare Access applications or service tokens. Instead, you create a TCP VPC Service that points to your database and pass its service ID to Hyperdrive.
For the Tunnel and Access approach, refer to Connect to a private database using Tunnel.
How it works
When your database is isolated within a private network (such as a virtual private cloud or an on-premise network), you must enable a secure connection from your network to Cloudflare.
Cloudflare Tunnel is used to establish a secure outbound connection from your private network to Cloudflare.
A VPC Service is used to route traffic from your Worker through the tunnel to your database, without requiring Cloudflare Access applications or service tokens.
A request from the Cloudflare Worker to the origin database goes through Hyperdrive, the VPC Service, and the Cloudflare Tunnel established by
cloudflared.
cloudflared must be running in the private network in which your database is accessible.
flowchart LR
A[Cloudflare Worker] --> B[Hyperdrive] --> C[VPC Service] --> D[Cloudflare Tunnel] --> E[Private Database]
Prerequisites
A database in your private network, configured to use TLS/SSL.
A Cloudflare Tunnel running in a network that can reach your database.
The Connectivity Directory Admin role on your Cloudflare account to create VPC Services.
1. Set up a Cloudflare Tunnel
If you do not already have a tunnel running in the same network as your database, create one.
The tunnel must be able to reach your database host and port from within the private network.
For full tunnel documentation, refer to Cloudflare Tunnel for Workers VPC.
2. Create a TCP VPC Service
Create a VPC Service of type
tcp that points to your database. Set the
--app-protocol flag to
postgresql or
mysql so that Hyperdrive can optimize connections.
npx wrangler vpc service create my-postgres-db \
--type tcp \
--tcp-port 5432 \
--app-protocol postgresql \
--tunnel-id \
--ipv4
npx wrangler vpc service create my-mysql-db \
--type tcp \
--tcp-port 3306 \
--app-protocol mysql \
--tunnel-id \
--ipv4
Replace:
with the tunnel ID from step 1.
with the private IP address of your database (for example,
10.0.0.5). You can also use
--hostname with a DNS name instead of
--ipv4.
The command will return a service ID. Save this value for the next step.
You can also create a TCP VPC Service from the Workers VPC dashboard. Refer to VPC Services for all configuration options.
TLS certificate verification
Unlike Hyperdrive, which does not verify the origin server certificate by default, Workers VPC defaults to
verify_full — it verifies both the certificate chain and the hostname. If your database uses a self-signed certificate or a certificate from a private certificate authority (CA), the TLS handshake will fail unless you adjust the verification mode.
For databases with self-signed certificates, add
--cert-verification-mode when creating the VPC Service:
verify_ca — Verifies the certificate chain but skips hostname verification. Use this when your database has a certificate signed by a CA you control but the hostname does not match the certificate.
disabled — Skips certificate verification entirely. Use this only for development or testing.
For example, to create a VPC Service for a PostgreSQL database with a self-signed certificate:
npx wrangler vpc service create my-postgres-db \
--type tcp \
--tcp-port 5432 \
--app-protocol postgresql \
--tunnel-id \
--ipv4 \
--cert-verification-mode verify_ca
To update an existing VPC Service, use
wrangler vpc service update with the same flag.
:::note
Workers VPC trusts publicly trusted certificates and Cloudflare Origin CA certificates. Uploading a custom CA certificate to Workers VPC is not supported yet. If your database uses a certificate signed by a private CA, set
--cert-verification-mode to
verify_ca or
disabled until custom CA support is available.
:::
For the full list of verification modes, refer to TLS certificate verification mode.
3. Create a Hyperdrive configuration
Use the
--service-id flag to point Hyperdrive at the VPC Service you created. When you use
--service-id, you do not provide
--origin-host,
--origin-port, or
--connection-string. Hyperdrive routes traffic through the VPC Service instead.
npx wrangler hyperdrive create \
--service-id \
--database \
--user \
--password \
--scheme postgresql
npx wrangler hyperdrive create \
--service-id \
--database \
--user \
--password \
--scheme mysql
Replace:
with the service ID from step 2.
with the name of your database.
and
with your database credentials.
If successful, the command will output a Hyperdrive configuration with an
id field. Copy this ID for the next step.
:::note
The
--service-id flag conflicts with
--origin-host,
--origin-port,
--connection-string,
--access-client-id, and
--access-client-secret. You cannot combine these options. To update an existing Hyperdrive configuration to use a VPC Service, run
wrangler hyperdrive update with the
--service-id flag.
:::
4. Bind Hyperdrive to a Worker
5. Query the database
Use node-postgres (
pg) to send a test query.
Deploy your Worker:
npx wrangler deploy
If you receive a list of
pg_tables from your database when you access your deployed Worker, Hyperdrive is connected to your private database through Workers VPC.
Use mysql2 to send a test query.
Deploy your Worker:
npx wrangler deploy
If you receive a list of tables from your database when you access your deployed Worker, Hyperdrive is connected to your private database through Workers VPC.
Next steps
Learn more about how Hyperdrive works.
Configure query caching for Hyperdrive.
Review VPC Service configuration options including TLS certificate verification.
Set up high availability tunnels for production workloads.
Troubleshoot common issues when connecting a database to Hyperdrive.
Connect to a private database using Tunnel
import { TabItem, Tabs, Render, Steps, Details } from "~/components";
Hyperdrive can securely connect to your private databases using Cloudflare Tunnel and Cloudflare Access.
:::note
You can also connect Hyperdrive to a private database using Workers VPC (Recommended), which does not require configuring Access applications or service tokens.
:::
How it works
When your database is isolated within a private network (such as a virtual private cloud or an on-premise network), you must enable a secure connection from your network to Cloudflare.
Cloudflare Tunnel is used to establish the secure tunnel connection.
Cloudflare Access is used to restrict access to your tunnel such that only specific Hyperdrive configurations can access it.
A request from the Cloudflare Worker to the origin database goes through Hyperdrive, Cloudflare Access, and the Cloudflare Tunnel established by
cloudflared.
cloudflared must be running in the private network in which your database is accessible.
The Cloudflare Tunnel will establish an outbound bidirectional connection from your private network to Cloudflare. Cloudflare Access will secure your Cloudflare Tunnel to be only accessible by your Hyperdrive configuration.
:::caution[Warning]
If your organization also uses Super Bot Fight Mode, keep Definitely Automated set to Allow. Otherwise, tunnels might fail with a
websocket: bad handshake error.
:::
Prerequisites
A database in your private network, configured to use TLS/SSL.
A hostname on your Cloudflare account, which will be used to route requests to your database.
1. Create a tunnel in your private network
1.1. Create a tunnel
First, create a Cloudflare Tunnel in your private network to establish a secure connection between your network and Cloudflare. Your network must be configured such that the tunnel has permissions to egress to the Cloudflare network and access the database within your network.
1.2. Connect your database using a public hostname
Your tunnel must be configured to use a public hostname on Cloudflare so that Hyperdrive can route requests to it. If you don't have a hostname on Cloudflare yet, you will need to register a new hostname or add a zone to Cloudflare to proceed.
In the Published application routes tab, choose a Domain and specify any subdomain or path information. This will be used in your Hyperdrive configuration to route to this tunnel.
In the Service section, specify Type
TCP and the URL and configured port of your database, such as
localhost:5432 or
my-database-host.database-provider.com:5432. This address will be used by the tunnel to route requests to your database.
Select Save tunnel.
:::note
If you are setting up the tunnel through the CLI instead (locally-managed tunnel), you will have to complete these steps manually. Follow the Cloudflare Zero Trust documentation to add a public hostname to your tunnel and configure the public hostname to route to the address of your database.
:::
2. Create and configure Hyperdrive to connect to the Cloudflare Tunnel
To restrict access to the Cloudflare Tunnel to Hyperdrive, a Cloudflare Access application must be configured with a Policy that requires requests to contain a valid Service Auth token.
The Cloudflare dashboard can automatically create and configure the underlying Cloudflare Access application, Service Auth token, and Policy on your behalf. Alternatively, you can manually create the Access application and configure the Policies.
2.1. (Automatic) Create a Hyperdrive configuration in the Cloudflare dashboard
Create a Hyperdrive configuration in the Cloudflare dashboard to automatically configure Hyperdrive to connect to your Cloudflare Tunnel.
1. In the [Cloudflare dashboard](https://dash.cloudflare.com/?to=/:account/workers/hyperdrive), navigate to **Storage & Databases > Hyperdrive** and click **Create configuration**.
2. Select **Private database**.
3. In the **Networking details** section, select the tunnel you are connecting to.
4. In the **Networking details** section, select the hostname associated to the tunnel. If there is no hostname for your database, return to step [1.2. Connect your database using a public hostname](/hyperdrive/configuration/connect-to-private-database/#12-connect-your-database-using-a-public-hostname).
5. In the **Access Service Authentication Token** section, select **Create new (automatic)**.
6. In the **Access Application** section, select **Create new (automatic)**.
7. In the **Database connection details** section, enter the database **name**, **user**, and **password**.
### 2.1. (Manual) Create a service token
The service token will be used to restrict requests to the tunnel, and is needed for the next step.
In the Cloudflare dashboard, go to Zero Trust > Access controls > Service credentials > Service Tokens.
Select Create Service Token.
Name the service token. The name allows you to easily identify events related to the token in the logs and to revoke the token individually.
Set a Service Token Duration of
Non-expiring. This prevents the service token from expiring, ensuring it can be used throughout the life of the Hyperdrive configuration.
Select Generate token. You will see the generated Client ID and Client Secret for the service token, as well as their respective request headers.
Copy the Access Client ID and Access Client Secret. These will be used when creating the Hyperdrive configuration.
:::caution
This is the only time Cloudflare Access will display the Client Secret. If you lose the Client Secret, you must regenerate the service token.
:::
2.2. (Manual) Create an Access application to secure the tunnel
Cloudflare Access will be used to verify that requests to the tunnel originate from Hyperdrive using the service token created above.
1. In the [Cloudflare dashboard](https://dash.cloudflare.com/), go to **Zero Trust** > **Access controls** > **Applications**.
Select Create new application.
Select Self-hosted and private.
Select Add public hostname and enter the subdomain and domain that was previously set for the tunnel application.
Select Create new policy.
Enter a Policy name and set the Action to Service Auth.
Create an Include rule. Specify a Selector of Service Token and the Value of the service token you created in step 2. Create a service token.
Save the policy.
In Identity providers, turn off Accept all available identity providers and clear all identity providers.
In Session Duration, select
No duration, expires immediately.
(Optional) Go to Additional settings. Turn off Show application in App Launcher.
Select Create.
2.3. (Manual) Create a Hyperdrive configuration
To create a Hyperdrive configuration for your private database, you'll need to specify the Access application and Cloudflare Tunnel information upon creation.
# wrangler v3.65 and above required
npx wrangler hyperdrive create --host= --user= --password= --database= --access-client-id= --access-client-secret=
resource "cloudflare_hyperdrive_config" "" {
account_id = ""
name = ""
origin = {
host = ""
database = ""
user = ""
password = ""
scheme = "postgres"
access_client_id = ""
access_client_secret = ""
}
caching = {
disabled = false
}
}
This will create a Hyperdrive configuration using the usual database information (database name, database host, database user, and database password).
In addition, it will also set the Access Client ID and the Access Client Secret of the Service Token. When Hyperdrive makes requests to the tunnel, requests will be intercepted by Access and validated using the credentials of the Service Token.
:::note
When creating the Hyperdrive configuration for the private database, you must enter the
access-client-id and the
access-client-secret, and omit the
port. Hyperdrive will route database messages to the public hostname of the tunnel, and the tunnel will rely on its service configuration (as configured in 1.2. Connect your database using a public hostname) to route requests to the database within your private network.
:::
3. Query your Hyperdrive configuration from a Worker (optional)
To test your Hyperdrive configuration to the database using Cloudflare Tunnel and Access, use the Hyperdrive configuration ID in your Worker and deploy it.
3.1. Create a Hyperdrive binding
3.2. Query your database
Validate that you can connect to your database from Workers and make queries.
Use node-postgres (
pg) to send a test query to validate that the connection has been successful.
Now, deploy your Worker:
npx wrangler deploy
If you successfully receive the list of
pg_tables from your database when you access your deployed Worker, your Hyperdrive has now been configured to securely connect to a private database using Cloudflare Tunnel and Cloudflare Access.
Use mysql2 to send a test query to validate that the connection has been successful.
Now, deploy your Worker:
npx wrangler deploy
If you successfully receive the list of tables from your database when you access your deployed Worker, your Hyperdrive has now been configured to securely connect to a private database using Cloudflare Tunnel and Cloudflare Access.
Troubleshooting
If you encounter issues when setting up your Hyperdrive configuration with tunnels to a private database, consider these common solutions, in addition to general troubleshooting steps for Hyperdrive:
Ensure your database is configured to use TLS (SSL). Hyperdrive requires TLS (SSL) to connect.
Firewall and networking configuration
import { TabItem, Tabs, Render, WranglerConfig } from "~/components";
Hyperdrive uses the Cloudflare IP address ranges to connect to your database. If you decide to restrict the IP addresses that can access your database with firewall rules, the IP address ranges listed in this reference need to be allow-listed in your database's firewall and networking configurations.
You can connect to your database from Hyperdrive using any of the 3 following networking configurations:
Configure your database to allow inbound connectivity from the public Internet (all IP address ranges).
Configure your database to allow inbound connectivity from the public Internet, with only the IP address ranges used by Hyperdrive allow-listed in an IP access control list (ACL).
Configure your database to allow inbound connectivity from a private network, and run a Cloudflare Tunnel instance in your private network to enable Hyperdrive to connect from the Cloudflare network to your private network. Refer to documentation on connecting to a private database using Tunnel.
Configuration
import { DirectoryListing } from "~/components";
Local development
import { WranglerConfig } from "~/components";
Hyperdrive can be used when developing and testing your Workers locally. Wrangler, the command-line interface for Workers, provides two options for local development:
wrangler dev (default): Runs your Worker code locally on your machine. You configure a
localConnectionString to connect directly to a database (either local or remote). Hyperdrive query caching does not take effect in this mode.
wrangler dev --remote: Runs your Worker on Cloudflare's using your deployed Hyperdrive configuration. This is useful for testing with Hyperdrive's connection pooling and query caching enabled.
Use
wrangler dev
By default,
wrangler dev runs your Worker code locally on your machine. To connect to a database during local development, configure a
localConnectionString that points directly to your database.
The
localConnectionString works with both local and remote databases:
Local databases: Connect to a database instance running on your machine (for example,
postgres://user:password@localhost:5432/database)
Remote databases: Connect directly to remote databases over TLS (for example,
postgres://user:password@remote-host.example.com:5432/database?sslmode=require or
mysql://user:password@remote-host.example.com:3306/database?sslMode=required). You must specify the SSL/TLS mode if required.
:::note
When using
localConnectionString, Hyperdrive's connection pooling and query caching do not take effect. Your Worker connects directly to the database without going through Hyperdrive.
:::
Configure with environment variable
The recommended approach is to use an environment variable to avoid committing credentials to source control:
# Your configured Hyperdrive binding is "HYPERDRIVE"
export CLOUDFLARE_HYPERDRIVE_LOCAL_CONNECTION_STRING_HYPERDRIVE="postgres://user:password@your-database-host:5432/database"
npx wrangler dev
The environment variable format is
CLOUDFLARE_HYPERDRIVE_LOCAL_CONNECTION_STRING_, where
is the name of the binding assigned to your Hyperdrive in your Wrangler configuration file.
To unset an environment variable:
unset CLOUDFLARE_HYPERDRIVE_LOCAL_CONNECTION_STRING_
For example, to set the connection string for a local database:
export CLOUDFLARE_HYPERDRIVE_LOCAL_CONNECTION_STRING_HYPERDRIVE="postgres://user:password@localhost:5432/databasename"
npx wrangler dev
Configure in Wrangler configuration file
Alternatively, you can set
localConnectionString in your Wrangler configuration file:
{
"hyperdrive": [
{
"binding": "HYPERDRIVE",
"id": "c020574a-5623-407b-be0c-cd192bab9545",
"localConnectionString": "postgres://user:password@localhost:5432/databasename"
}
]
}
If both an environment variable and
localConnectionString in the Wrangler configuration file are set, the environment variable takes precedence.
Use
wrangler dev --remote
When you run
wrangler dev --remote, your Worker runs in Cloudflare's network and uses your deployed Hyperdrive configuration. This means:
Your Worker code executes in Cloudflare's production environment, not locally
Hyperdrive's connection pooling and query caching are active
You connect to the database configured in your Hyperdrive configuration (created with
wrangler hyperdrive create)
Changes made during the session interact with remote resources
This mode is useful for testing how your Worker behaves with Hyperdrive's features enabled before deploying.
Configure your Hyperdrive binding in
wrangler.jsonc:
{
"hyperdrive": [
{
"binding": "HYPERDRIVE",
"id": "your-hyperdrive-id",
},
],
}
To start a remote development session:
npx wrangler dev --remote
:::note
The
localConnectionString field is not used with
wrangler dev --remote. Instead, your Worker connects to the database configured in your deployed Hyperdrive configuration.
:::
:::caution
Use
wrangler dev --remote with caution. Since your Worker runs in Cloudflare's production environment, any database writes or side effects will affect your production data.
:::
Refer to the
wrangler dev documentation to learn more about how to configure a local development session.
Related resources
Use
wrangler dev to run your Worker and Hyperdrive locally and debug issues before deploying.
Learn how Hyperdrive works.
Understand how to configure query caching in Hyperdrive.
Rotating database credentials
import { TabItem, Tabs, Render, WranglerConfig } from "~/components";
You can change the connection information and credentials of your Hyperdrive configuration in one of two ways:
Create a new Hyperdrive configuration with the new connection information, and update your Worker to use the new Hyperdrive configuration.
Update the existing Hyperdrive configuration with the new connection information and credentials.
Use a new Hyperdrive configuration
Creating a new Hyperdrive configuration to update your database credentials allows you to keep your existing Hyperdrive configuration unchanged, gradually migrate your Worker to the new Hyperdrive configuration, and easily roll back to the previous configuration if needed.
To create a Hyperdrive configuration that connects to an existing PostgreSQL or MySQL database, use the Wrangler CLI or the Cloudflare dashboard.
# wrangler v3.11 and above required
npx wrangler hyperdrive create my-updated-hyperdrive --connection-string=""
The command above will output the ID of your Hyperdrive. Set this ID in the Wrangler configuration file for your Workers project:
{
// required for database drivers to function
"compatibility_flags": [
"nodejs_compat"
],
"compatibility_date": "$today",
"hyperdrive": [
{
"binding": "HYPERDRIVE",
"id": ""
}
]
}
To update your Worker to use the new Hyperdrive configuration, redeploy your Worker or use gradual deployments.
Update the existing Hyperdrive configuration
You can update the configuration of an existing Hyperdrive configuration using the wrangler CLI.
# wrangler v3.11 and above required
npx wrangler hyperdrive update --origin-host --origin-password --origin-user --database --origin-port
:::note
Updating the settings of an existing Hyperdrive configuration does not purge Hyperdrive's cache and does not tear down the existing database connection pool. New connections will be established using the new connection information. To drain the existing pool and force new connections immediately, restart the connection pool.
:::
SSL/TLS certificates
import {
TabItem,
Tabs,
Render,
WranglerConfig,
DashButton,
} from "~/components";
Hyperdrive provides additional ways to secure connectivity to your database. Hyperdrive supports:
Server certificates for TLS (SSL) modes such as
verify-ca/
VERIFY_CA and
verify-full/
VERIFY_IDENTITY for increased security. When configured, Hyperdrive will verify that the certificates have been signed by the expected certificate authority (CA) to avoid man-in-the-middle attacks.
Client certificates for Hyperdrive to authenticate itself to your database with credentials beyond username/password. To properly use client certificates, your database must be configured to verify the client certificates provided by a client, such as Hyperdrive, to allow access to the database.
Hyperdrive can be configured to use only server certificates, only client certificates, or both depending on your security requirements and database configurations.
Server certificates (TLS/SSL modes)
Hyperdrive supports common encryption TLS/SSL modes to connect to your database. The mode names differ between PostgreSQL and MySQL:
PostgreSQL
MySQL
Description
require (default)
REQUIRED (default)
TLS is required for encrypted connectivity and server certificates are validated (based on WebPKI).
verify-ca
VERIFY_CA
Hyperdrive will verify that the database server is trustworthy by verifying that the certificates of the server have been signed by the expected root certificate authority or intermediate certificate authority.
verify-full
VERIFY_IDENTITY
In addition to
verify-ca/
VERIFY_CA checks, Hyperdrive requires the database hostname to match a Subject Alternative Name (SAN) or Common Name (CN) on the certificate.
By default, all Hyperdrive configurations are encrypted with SSL/TLS (
require/
REQUIRED). This requires your database to be configured to accept encrypted connections (with SSL/TLS).
You can configure Hyperdrive to use
verify-ca/
VERIFY_CA and
verify-full/
VERIFY_IDENTITY for a more stringent security configuration, which provide additional verification checks of the server's certificates. This helps guard against man-in-the-middle attacks.
To configure Hyperdrive to verify the certificates of the server, you must provide Hyperdrive with the certificate of the root certificate authority (CA) or an intermediate certificate which has been used to sign the certificate of your database.
Step 1: Upload the root certificate authority (CA) certificate
Using Wrangler, you can upload your root certificate authority (CA) certificate:
# requires Wrangler 4.9.0 or greater
npx wrangler cert upload certificate-authority --ca-cert \.pem --name \
---
Uploading CA Certificate tmp-cert...
Success! Uploaded CA Certificate
ID:
...
:::note
You must use the CA certificate bundle that is for your specific region. You cannot use a CA certificate bundle that contains more than one CA certificate, such as a global bundle of CA certificates containing each region's certificate.
:::
Step 2: Create your Hyperdrive configuration using the CA certificate and the SSL mode
Once your CA certificate has been created, you can create a Hyperdrive configuration with the newly created certificates using either the dashboard or Wrangler. You must also specify the SSL mode to use (
verify-ca/
verify-full for PostgreSQL or
VERIFY_CA/
VERIFY_IDENTITY for MySQL).
Using Wrangler, enter the following command in your terminal to create a Hyperdrive configuration with the CA certificate and SSL mode:
# PostgreSQL with verify-full
npx wrangler hyperdrive create --connection-string="postgres://user:password@HOSTNAME_OR_IP_ADDRESS:PORT/database_name" --ca-certificate-id --sslmode verify-full
# MySQL with VERIFY_IDENTITY
npx wrangler hyperdrive create --connection-string="mysql://user:password@HOSTNAME_OR_IP_ADDRESS:PORT/database_name" --ca-certificate-id --sslmode VERIFY_IDENTITY
From the dashboard, follow these steps to create a Hyperdrive configuration with server certificates:
In the Cloudflare dashboard, go to the Hyperdrive page.
Select Create configuration.
Select Server certificates.
Specify a SSL mode of Verify CA or Verify full.
Select the SSL certificate of the certificate authority (CA) of your database that you have previously uploaded with Wrangler.
When creating the Hyperdrive configuration, Hyperdrive will attempt to connect to the database with the provided credentials. If the command provides successful results, you have properly configured your Hyperdrive configuration to verify the certificates provided by your database server.
:::note
Hyperdrive will attempt to connect to your database with the provided credentials to verify they are correct before creating a configuration. If you encounter an error when attempting to connect, refer to Hyperdrive's troubleshooting documentation to debug possible causes.
:::
Client certificates
Your database can be configured to verify a certificate provided by the client (in this case, Hyperdrive). This serves as an additional factor to authenticate clients (in addition to the username and password). Refer to the PostgreSQL or MySQL documentation for more details.
For the database server to be able to verify the client certificates, Hyperdrive must be configured to provide a certificate file (
client-cert.pem) and a private key with which the certificate was generated (
private-key.pem).
Step 1: Upload your client certificates (mTLS certificates)
Upload your client certificates to be used by Hyperdrive using Wrangler:
# requires Wrangler 4.9.0 or greater
npx wrangler cert upload mtls-certificate --cert client-cert.pem --key client-key.pem --name
---
Uploading client certificate ...
Success! Uploaded client certificate
ID:
...
Step 2: Create a Hyperdrive configuration
You can now create a Hyperdrive configuration using the newly created client certificate bundle using the dashboard or Wrangler.
Using Wrangler, enter the following command in your terminal to create a Hyperdrive configuration with the client certificate pair:
# PostgreSQL
npx wrangler hyperdrive create --connection-string="postgres://user:password@HOSTNAME_OR_IP_ADDRESS:PORT/database_name" --mtls-certificate-id
# MySQL
npx wrangler hyperdrive create --connection-string="mysql://user:password@HOSTNAME_OR_IP_ADDRESS:PORT/database_name" --mtls-certificate-id
From the dashboard, follow these steps to create a Hyperdrive configuration with server certificates:
In the Cloudflare dashboard, go to the Hyperdrive page.
Select Create configuration.
Select Client certificates.
Select the SSL client certificate and private key pair for Hyperdrive to use during the connection setup with your database server.
When Hyperdrive connects to your database, it will provide a client certificate signed with the private key to the database server. This allows the database server to confirm that the client, in this case Hyperdrive, has both the private key and the client certificate. By using client certificates, you can add an additional authentication layer for your database to ensure that only Hyperdrive can connect to it.
:::note
Hyperdrive will attempt to connect to your database with the provided credentials to verify they are correct before creating a configuration. If you encounter an error when attempting to connect, refer to Hyperdrive's troubleshooting documentation to debug possible causes.
:::
Tune connection pooling
import { TabItem, Tabs, DashButton } from "~/components";
Hyperdrive maintains a pool of connections to your database that are shared across Worker invocations. You can configure the maximum number of these connections based on your database capacity and application requirements.
:::note
Hyperdrive does not have a limit on the number of concurrent client connections made from your Workers to Hyperdrive.
Hyperdrive does have a limit of origin connections that can be made from Hyperdrive to your database. These are shared across Workers, with each Worker using one of these connections over the course of a database transaction. Refer to transaction pooling mode for more information.
:::
Configure connection pool size
You can configure the connection pool size using the Cloudflare dashboard, the Wrangler CLI, or the Cloudflare API.
To configure connection pool size via the dashboard:
Log in to the Cloudflare dashboard and select your account.
Go to Storage & databases > Hyperdrive.
Select your Hyperdrive configuration.
Select Settings.
In the Origin connection limit section, adjust the Maximum connections value.
Select Save.
Use the
wrangler hyperdrive update command with the
--origin-connection-limit flag:
npx wrangler hyperdrive update --origin-connection-limit=
Use the Hyperdrive REST API to update your configuration:
curl --request PATCH \
--url https://api.cloudflare.com/client/v4/accounts//hyperdrive/configs/ \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer ' \
--data '{
"origin_connection_limit":
}'
All Hyperdrive configurations have a minimum of 5 connections. The maximum connection count depends on your Workers plan.
:::note
The Hyperdrive connection pool limit is a "soft limit". This means that it is possible for Hyperdrive to make more connections to your database than this limit in the event of network failure to ensure high availability. We recommend that you set the Hyperdrive connection limit to be lower than the limit of your origin database to account for occasions where Hyperdrive needs to create more connections for resiliency.
:::
:::note
You can request adjustments to Hyperdrive's origin connection limits. To request an increase, submit a Limit Increase Request and Cloudflare will contact you with next steps. Cloudflare also regularly monitors the Hyperdrive channel in Cloudflare's Discord community and can answer questions regarding limits and requests.
:::
Best practices
Start conservatively: Begin with a lower connection count and gradually increase it based on your application's performance.
Monitor database metrics: Watch your database's connection usage and performance metrics to optimize the connection count.
Consider database limits: Ensure your configured connection count does not exceed your database's maximum connection limit.
Account for multiple configurations: If you have multiple Hyperdrive configurations connecting to the same database, consider the total connection count across all configurations.
Related resources
Connection pooling concepts
Connection lifecycle
Metrics and analytics
Hyperdrive limits
Query caching
Examples
import { DirectoryListing } from "~/components";
Python Workers
import { Steps, Tabs, TabItem, WranglerConfig } from "~/components";
You can use Hyperdrive with Python Workers.
To use Hyperdrive with Python Workers, set your compatibility date to
2026-09-08 or later.
Supported drivers
Hyperdrive in Python Workers uses TCP socket support to establish database connections.
While you can use any Python driver that works with TCP connections,
we strongly recommend using the drivers in the tables below, as they have been tested and verified to work with Hyperdrive.
PostgreSQL
Driver
Documentation
asyncpg (recommended)
asyncpg documentation
pg8000
pg8000 documentation
psycopg
psycopg documentation
MySQL
Driver
Documentation
aiomysql (recommended)
aiomysql documentation
pymysql
pymysql documentation
Connect to your database
Before you begin, create a Python Worker and create a Hyperdrive configuration for your database.
Add the Hyperdrive binding to your Wrangler configuration. Replace
with your configuration ID.
name = "python-hyperdrive"
main = "src/main.py"
compatibility_date = "$today"
compatibility_flags = ["python_workers"]
[[hyperdrive]]
binding = "HYPERDRIVE"
id = ""
Install your driver and replace
src/main.py with the corresponding example.
[project]
dependencies = [
"asyncpg",
]
from contextlib import closing
import asyncpg
from workers import Response, WorkerEntrypoint
class Default(WorkerEntrypoint):
async def fetch(self, request):
hd = self.env.HYPERDRIVE
connection = await asyncpg.connect(
host=hd.host,
port=int(hd.port),
user=hd.user,
password=hd.password,
database=hd.database,
ssl=False,
)
await connection.execute("SELECT 1")
await connection.close()
[project]
dependencies = [
"aiomysql",
]
import aiomysql
from workers import Response, WorkerEntrypoint
class Default(WorkerEntrypoint):
async def fetch(self, request):
hd = self.env.HYPERDRIVE
connection = await aiomysql.connect(
host=hd.host,
port=int(hd.port),
user=hd.user,
password=hd.password,
db=hd.database,
ssl=None,
)
try:
cursor = await connection.cursor()
await cursor.execute("SELECT 1")
result = await cursor.fetchone()
return Response.json({"result": result[0]})
finally:
connection.close()
Deploy your Worker:
uv run pywrangler deploy
Limitations and compatibility
Socket support
TCP socket support in Python Workers internally uses the
connect API.
While most standard library socket operations are supported, some low-level operations might not work as expected.
Concurrency and async safety
Socket operations in Python Workers do not block the event loop.
Although Python's native socket operations are synchronous, the underlying TCP socket implementation in Python Workers is asynchronous.
This allows multiple requests to be processed concurrently while one request waits for a socket operation to complete.
To ensure synchronous database operations are serialized, use a lock to prevent concurrent access:
import asyncio
lock = asyncio.Lock()
async with lock:
# Your database operation here
synchronous_db_operation()
SQLAlchemy support
Currently, only synchronous SQLAlchemy ORMs are supported in Python Workers.
Async SQLAlchemy ORMs are not yet supported due to a lack of greenlet support in the Python Workers environment.
Connect to MySQL
import { TabItem, Tabs, Render, WranglerConfig } from "~/components";
Hyperdrive supports MySQL and MySQL-compatible databases, popular drivers, and Object Relational Mapper (ORM) libraries that use those drivers.
Create a Hyperdrive
:::note
New to Hyperdrive? Refer to the Get started guide to learn how to set up your first Hyperdrive.
:::
To create a Hyperdrive that connects to an existing MySQL database, use the Wrangler CLI or the Cloudflare dashboard.
When using Wrangler, replace the placeholder value provided to
--connection-string with the connection string for your database:
# wrangler v3.11 and above required
npx wrangler hyperdrive create my-first-hyperdrive --connection-string="mysql://user:password@database.host.example.com:3306/databasenamehere"
The command above will output the ID of your Hyperdrive, which you will need to set in the Wrangler configuration file for your Workers project:
This will allow Hyperdrive to generate a dynamic connection string within your Worker that you can pass to your existing database driver. Refer to Driver examples to learn how to set up a database driver with Hyperdrive.
Refer to the Examples documentation for step-by-step guides on how to set up Hyperdrive with several popular database providers.
Supported drivers
Hyperdrive uses Workers TCP socket support to support TCP connections to databases. The following table lists the supported database drivers and the minimum version that works with Hyperdrive:
Driver
Documentation
Minimum Version Required
Notes
mysql2 (recommended)
mysql2 documentation
mysql2@3.13.0
Supported in both Workers & Pages. Using the Promise API is recommended.
mysql
mysql documentation
mysql@2.18.0
Requires
compatibility_flags = ["nodejs_compat"] and
compatibility_date = "2024-09-23" - refer to Node.js compatibility. Requires wrangler
3.78.7 or later.
Drizzle
Drizzle documentation
Requires
mysql2@3.13.0
Kysely
Kysely documentation
Requires
mysql2@3.13.0
^ The marked libraries can use either mysql or mysql2 as a dependency.
Other drivers and ORMs not listed may also be supported: this list is not exhaustive.
Database drivers and Node.js compatibility
Node.js compatibility is required for database drivers, including mysql and mysql2, and needs to be configured for your Workers project.
Supported TLS (SSL) modes
Hyperdrive supports the following MySQL TLS/SSL connection modes when connecting to your origin database:
Mode
Supported
Details
DISABLED
No
Hyperdrive does not support insecure plain text connections.
PREFERRED
No (use
REQUIRED)
Hyperdrive will always use TLS.
REQUIRED
Yes (default)
TLS is required, and server certificates are validated (based on WebPKI).
VERIFY_CA
Yes
Verifies the server's TLS certificate is signed by a root CA on the client.
VERIFY_IDENTITY
Yes
In addition to
VERIFY_CA checks, Hyperdrive requires the database hostname to match a Subject Alternative Name (SAN) or Common Name (CN) on the certificate.
Refer to SSL/TLS certificates documentation for details on how to configure
VERIFY_CA or
VERIFY_IDENTITY TLS (SSL) modes for Hyperdrive.
Driver examples
The following examples show you how to:
Create a database client with a database driver.
Pass the Hyperdrive connection string and connect to the database.
Query your database via Hyperdrive.
mysql2
The following Workers code shows you how to use mysql2 with Hyperdrive using the Promise API.
mysql
The following Workers code shows you how to use mysql with Hyperdrive.
Identify connections from Hyperdrive
To identify active connections to your MySQL database server from Hyperdrive:
Hyperdrive's connections to your database will show up with
Cloudflare Hyperdrive in the
PROGRAM_NAME column in the
performance_schema.threads table.
Run
SELECT DISTINCT USER, HOST, PROGRAM_NAME FROM performance_schema.threads WHERE PROGRAM_NAME = 'Cloudflare Hyperdrive' to show whether Hyperdrive is currently holding a connection (or connections) open to your database.
Next steps
Refer to the list of supported database integrations to understand other ways to connect to existing databases.
Learn more about how to use the Socket API in a Worker.
Understand the protocols supported by Workers.
AWS RDS and Aurora
import { Render } from "~/components";
This example shows you how to connect Hyperdrive to an Amazon Relational Database Service (Amazon RDS) or Amazon Aurora MySQL database instance.
1. Allow Hyperdrive access
To allow Hyperdrive to connect to your database, you will need to ensure that Hyperdrive has valid user credentials and network access.
AWS Console
When creating or modifying an instance in the AWS console:
Configure a database cluster and other settings you wish to customize.
Under Settings > Credential settings, note down the Master username and Master password (Aurora only).
Under the Connectivity header, ensure Public access is set to Yes.
Select an Existing VPC security group that allows public Internet access from
0.0.0.0/0 to the port your database instance is configured to listen on (default:
3306 for MySQL instances).
Select Create database.
:::caution
You must ensure that the VPC security group associated with your database allows public IPv4 access to your database port.
Refer to AWS' database server rules for details on how to configure rules specific to your RDS database.
:::
Retrieve the database endpoint (Aurora)
To retrieve the database endpoint (hostname) for Hyperdrive to connect to:
Go to Databases view under RDS in the AWS console.
Select the database you want Hyperdrive to connect to.
Under the Endpoints header, note down the Endpoint name with the type
Writer and the Port.
Retrieve the database endpoint (RDS MySQL)
For regular RDS instances (non-Aurora), you will need to fetch the endpoint and port of the database:
Go to Databases view under RDS in the AWS console.
Select the database you want Hyperdrive to connect to.
Under the Connectivity & security header, note down the Endpoint and the Port.
The endpoint will resemble
YOUR_DATABASE_NAME.cpuo5rlli58m.AWS_REGION.rds.amazonaws.com, and the port will default to
3306.
2. Create your user
Once your database is created, you will need to create a user for Hyperdrive to connect as. Although you can use the Master username configured during initial database creation, best practice is to create a less privileged user.
To create a new user, log in to the database and use the
CREATE USER command:
# Log in to the database
mysql -h ENDPOINT_NAME -P PORT -u MASTER_USERNAME -p database_name
Run the following SQL statements:
-- Create a role for Hyperdrive
CREATE ROLE hyperdrive;
-- Allow Hyperdrive to connect
GRANT USAGE ON mysql_db.* TO hyperdrive;
-- Grant database privileges to the hyperdrive role
GRANT ALL PRIVILEGES ON mysql_db.* to hyperdrive;
-- Create a specific user for Hyperdrive to log in as
CREATE USER 'hyperdrive_user'@'%' IDENTIFIED WITH caching_sha2_password BY 'sufficientlyRandomPassword';
-- Grant this new user the hyperdrive role privileges
GRANT hyperdrive to 'hyperdrive_user'@'%';
Refer to AWS' documentation on user roles in MySQL for more details.
With a database user, password, database endpoint (hostname and port), and database name, you can now set up Hyperdrive.
3. Create a database configuration
Azure Database
import { Render } from "~/components";
This example shows you how to connect Hyperdrive to an Azure Database for MySQL instance.
1. Allow Hyperdrive access
To allow Hyperdrive to connect to your database, you will need to ensure that Hyperdrive has valid credentials and network access.
Azure Portal
Public access networking
To connect to your Azure Database for MySQL instance using public Internet connectivity:
In the Azure Portal, select the instance you want Hyperdrive to connect to.
Expand Settings > Networking > ensure Public access is enabled > in Firewall rules add
0.0.0.0 as Start IP address and
255.255.255.255 as End IP address.
Select Save to persist your changes.
Select Overview from the sidebar and note down the Server name of your instance.
With the username, password, server name, and database name (default:
mysql), you can now create a Hyperdrive database configuration.
Private access networking
To connect to a private Azure Database for MySQL instance, refer to Connect to a private database using Tunnel.
2. Create a database configuration
Google Cloud SQL
import { Render } from "~/components";
This example shows you how to connect Hyperdrive to a Google Cloud SQL MySQL database instance.
1. Allow Hyperdrive access
To allow Hyperdrive to connect to your database, you will need to ensure that Hyperdrive has valid user credentials and network access.
Cloud Console
When creating the instance or when editing an existing instance in the Google Cloud Console:
To allow Hyperdrive to reach your instance:
In the Cloud Console, select the instance you want Hyperdrive to connect to.
Expand Connections > Networking > ensure Public IP is enabled > Add a Network and input
0.0.0.0/0.
Select Done > Save to persist your changes.
Select Overview from the sidebar and note down the Public IP address of your instance.
To create a user for Hyperdrive to connect as:
Select Users in the sidebar.
Select Add User Account > select Built-in authentication.
Provide a name (for example,
hyperdrive-user), then select Generate to generate a password.
Copy this password to your clipboard before selecting Add to create the user.
With the username, password, public IP address and (optional) database name (default:
mysql), you can now create a Hyperdrive database configuration.
2. Create a database configuration
Database Providers
import { DirectoryListing } from "~/components";
PlanetScale
import { Render } from "~/components";
This example shows you how to connect Hyperdrive to a PlanetScale MySQL database.
Drizzle ORM
import { Render, Steps } from "~/components";
Drizzle ORM is a lightweight TypeScript ORM with a focus on type safety. This example demonstrates how to use Drizzle ORM with MySQL via Cloudflare Hyperdrive in a Workers application.
Prerequisites
A Cloudflare account with Workers access
A MySQL database
A Hyperdrive configuration to your MySQL database
1. Install Drizzle
Install the Drizzle ORM and its dependencies such as the mysql2 driver:
# mysql2 v3.13.0 or later is required
npm i drizzle-orm mysql2 dotenv
npm i -D drizzle-kit tsx @types/node
Add the required Node.js compatibility flags and Hyperdrive binding to your
wrangler.jsonc file:
2. Configure Drizzle
2.1. Define a schema
With Drizzle ORM, we define the schema in TypeScript rather than writing raw SQL.
1. Create a folder `/db/` in `/src/`.
2. Create a `schema.ts` file.
3. In `schema.ts`, define a `users` table as shown below.
```ts title="src/db/schema.ts"
// src/schema.ts
import { mysqlTable, int, varchar, timestamp } from "drizzle-orm/mysql-core";
export const users = mysqlTable("users", {
id: int("id").primaryKey().autoincrement(),
name: varchar("name", { length: 255 }).notNull(),
email: varchar("email", { length: 255 }).notNull().unique(),
createdAt: timestamp("created_at").defaultNow(),
});
```
2.2. Connect Drizzle ORM to the database with Hyperdrive
Use your the credentials of your Hyperdrive configuration for your database when using the Drizzle ORM.
Populate your
index.ts file as shown below.
// src/index.ts
import { drizzle } from "drizzle-orm/mysql2";
import { createConnection } from "mysql2/promise";
import { users } from "./db/schema";
export interface Env {
HYPERDRIVE: Hyperdrive;
}
export default {
async fetch(request, env, ctx): Promise {
// Create a connection using the mysql2 driver with the Hyperdrive credentials (only accessible from your Worker).
const connection = await createConnection({
host: env.HYPERDRIVE.host,
user: env.HYPERDRIVE.user,
password: env.HYPERDRIVE.password,
database: env.HYPERDRIVE.database,
port: env.HYPERDRIVE.port,
// Required to enable mysql2 compatibility for Workers
disableEval: true,
});
// Create the Drizzle client with the mysql2 driver connection
const db = drizzle(connection);
// Sample query to get all users
const allUsers = await db.select().from(users);
return Response.json(allUsers);
},
} satisfies ExportedHandler;
2.3. Configure Drizzle-Kit for migrations (optional)
:::note
You need to set up the tables in your database so that Drizzle ORM can make queries that work.
If you have already set it up (for example, if another user has applied the schema to your database), or if you are starting to use Drizzle ORM and the schema matches what already exists in your database, then you do not need to run the migration.
:::
You can generate and run SQL migrations on your database based on your schema using Drizzle Kit CLI. Refer to Drizzle ORM docs for additional guidance.
1. Create a `.env` file in the root folder of your project, and add your database connection string. The Drizzle Kit CLI will use this connection string to create and apply the migrations.
# .env
# Replace with your direct database connection string
DATABASE_URL='mysql://user:password@db-host.cloud/database-name'
Create a
drizzle.config.ts file in the root folder of your project to configure Drizzle Kit and add the following content:
import 'dotenv/config';
import { defineConfig } from 'drizzle-kit';
export default defineConfig({
out: './drizzle',
schema: './src/db/schema.ts',
dialect: 'mysql',
dbCredentials: {
url: process.env.DATABASE_URL!,
},
});
Generate the migration file for your database according to your schema files and apply the migrations to your database.
npx drizzle-kit generate
No config path provided, using default 'drizzle.config.ts'
Reading config file 'drizzle.config.ts'
Reading schema files:
/src/db/schema.ts
1 tables
users 4 columns 0 indexes 0 fks
[✓] Your SQL migration file ➜ drizzle/0000_daffy_rhodey.sql 🚀
npx drizzle-kit migrate
No config path provided, using default 'drizzle.config.ts'
Reading config file 'drizzle.config.ts'
3. Deploy your Worker
Deploy your Worker.
npx wrangler deploy
Libraries and Drivers
import { DirectoryListing } from "~/components";
mysql
import { Render } from "~/components";
The mysql package is a MySQL driver for Node.js.
This example demonstrates how to use it with Cloudflare Workers and Hyperdrive.
mysql2
import { Render } from "~/components";
The mysql2 package is a modern MySQL driver for Node.js with better performance and built-in Promise support.
This example demonstrates how to use it with Cloudflare Workers and Hyperdrive.
Connect to PostgreSQL
import { TabItem, Tabs, Render, WranglerConfig } from "~/components";
Hyperdrive supports PostgreSQL and PostgreSQL-compatible databases, popular drivers and Object Relational Mapper (ORM) libraries that use those drivers.
Create a Hyperdrive
:::note
New to Hyperdrive? Refer to the Get started guide to learn how to set up your first Hyperdrive.
:::
To create a Hyperdrive that connects to an existing PostgreSQL database, use the wrangler CLI or the Cloudflare dashboard.
When using wrangler, replace the placeholder value provided to
--connection-string with the connection string for your database:
# wrangler v3.11 and above required
npx wrangler hyperdrive create my-first-hyperdrive --connection-string="postgres://user:password@database.host.example.com:5432/databasenamehere"
The command above will output the ID of your Hyperdrive, which you will need to set in the Wrangler configuration file for your Workers project:
This will allow Hyperdrive to generate a dynamic connection string within your Worker that you can pass to your existing database driver. Refer to Driver examples to learn how to set up a database driver with Hyperdrive.
Refer to the Examples documentation for step-by-step guides on how to set up Hyperdrive with several popular database providers.
Supported drivers
Hyperdrive uses Workers TCP socket support to support TCP connections to databases. The following table lists the supported database drivers and the minimum version that works with Hyperdrive:
Driver
Documentation
Minimum Version Required
Notes
node-postgres -
pg (recommended)
node-postgres -
pg documentation
pg@8.16.3
8.11.4 introduced a bug with URL parsing and will not work.
8.11.5 fixes this. Requires
compatibility_flags = ["nodejs_compat"] and
compatibility_date = "2024-09-23" - refer to Node.js compatibility. Requires wrangler
3.78.7 or later.
Postgres.js
Postgres.js documentation
postgres@3.4.5
Supported in both Workers & Pages.
Drizzle
Drizzle documentation
0.26.2^
Kysely
Kysely documentation
0.26.3^
rust-postgres
rust-postgres documentation
v0.19.8
Use the
query_typed method for best performance.
^ The marked libraries use
node-postgres as a dependency.
Other drivers and ORMs not listed may also be supported: this list is not exhaustive.
Database drivers and Node.js compatibility
Node.js compatibility is required for database drivers, including Postgres.js, and needs to be configured for your Workers project.
Driver examples
The following examples show you how to:
Create a database client with a database driver.
Pass the Hyperdrive connection string and connect to the database.
Query your database via Hyperdrive.
node-postgres / pg
Postgres.js
Identify connections from Hyperdrive
To identify active connections to your Postgres database server from Hyperdrive:
Hyperdrive's connections to your database will show up with
Cloudflare Hyperdrive as the
application_name in the
pg_stat_activity table.
Run
SELECT DISTINCT usename, application_name FROM pg_stat_activity WHERE application_name = 'Cloudflare Hyperdrive' to show whether Hyperdrive is currently holding a connection (or connections) open to your database.
:::note
Hyperdrive only sets the
application_name to
Cloudflare Hyperdrive when your driver does not send its own. Some drivers set a default
application_name — for example, Postgres.js sends
postgres.js unless you override it. Hyperdrive forwards the driver-provided value to your database, so those connections appear under that name (for example,
postgres.js) instead of
Cloudflare Hyperdrive. This does not mean the connection is bypassing Hyperdrive.
To keep these connections identifiable as Hyperdrive, set the
application_name explicitly in your driver. With Postgres.js:
const sql = postgres(env.HYPERDRIVE.connectionString, {
max: 5,
fetch_types: false,
connection: {
application_name: "Cloudflare Hyperdrive",
},
});
:::
Next steps
Refer to the list of supported database integrations to understand other ways to connect to existing databases.
Learn more about how to use the Socket API in a Worker.
Understand the protocols supported by Workers.
AWS RDS and Aurora
import { Render } from "~/components";
This example shows you how to connect Hyperdrive to an Amazon Relational Database Service (Amazon RDS) Postgres or Amazon Aurora database instance.
1. Allow Hyperdrive access
To allow Hyperdrive to connect to your database, you will need to ensure that Hyperdrive has valid user credentials and network access.
AWS Console
When creating or modifying an instance in the AWS console:
Configure a DB cluster identifier and other settings you wish to customize.
Under Settings > Credential settings, note down the Master username and Master password (Aurora only).
Under the Connectivity header, ensure Public access is set to Yes.
Select an Existing VPC security group that allows public Internet access from
0.0.0.0/0 to the port your database instance is configured to listen on (default:
5432 for PostgreSQL instances).
Select Create database.
:::caution
You must ensure that the VPC security group associated with your database allows public IPv4 access to your database port.
Refer to AWS' database server rules for details on how to configure rules specific to your RDS or Aurora database.
:::
Retrieve the database endpoint (Aurora)
To retrieve the database endpoint (hostname) for Hyperdrive to connect to:
Go to Databases view under RDS in the AWS console.
Select the database you want Hyperdrive to connect to.
Under the Endpoints header, note down the Endpoint name with the type
Writer and the Port.
Retrieve the database endpoint (RDS PostgreSQL)
For regular RDS instances (non-Aurora), you will need to fetch the endpoint and port of the database:
Go to Databases view under RDS in the AWS console.
Select the database you want Hyperdrive to connect to.
Under the Connectivity & security header, note down the Endpoint and the Port.
The endpoint will resemble
YOUR_DATABASE_NAME.cpuo5rlli58m.AWS_REGION.rds.amazonaws.com and the port will default to
5432.
2. Create your user
Once your database is created, you will need to create a user for Hyperdrive to connect as. Although you can use the Master username configured during initial database creation, best practice is to create a less privileged user.
To create a new user, log in to the database and use the
CREATE ROLE command:
# Log in to the database
psql postgresql://MASTER_USERNAME:MASTER_PASSWORD@ENDPOINT_NAME:PORT/database_name
Run the following SQL statements:
-- Create a role for Hyperdrive
CREATE ROLE hyperdrive;
-- Allow Hyperdrive to connect
GRANT CONNECT ON DATABASE postgres TO hyperdrive;
-- Grant database privileges to the hyperdrive role
GRANT ALL PRIVILEGES ON DATABASE postgres to hyperdrive;
-- Create a specific user for Hyperdrive to log in as
CREATE ROLE hyperdrive_user LOGIN PASSWORD 'sufficientlyRandomPassword';
-- Grant this new user the hyperdrive role privileges
GRANT hyperdrive to hyperdrive_user;
Refer to AWS' documentation on user roles in PostgreSQL for more details.
With a database user, password, database endpoint (hostname and port) and database name (default:
postgres), you can now set up Hyperdrive.
3. Create a database configuration
Azure Database
import { Render } from "~/components";
This example shows you how to connect Hyperdrive to an Azure Database for PostgreSQL instance.
1. Allow Hyperdrive access
To allow Hyperdrive to connect to your database, you will need to ensure that Hyperdrive has valid credentials and network access.
Azure Portal
Public access networking
To connect to your Azure Database for PostgreSQL instance using public Internet connectivity:
In the Azure Portal, select the instance you want Hyperdrive to connect to.
Expand Settings > Networking > ensure Public access is enabled > in Firewall rules add
0.0.0.0 as Start IP address and
255.255.255.255 as End IP address.
Select Save to persist your changes.
Select Overview from the sidebar and note down the Server name of your instance.
With the username, password, server name, and database name (default:
postgres), you can now create a Hyperdrive database configuration.
Private access networking
To connect to a private Azure Database for PostgreSQL instance, refer to Connect to a private database using Tunnel.
2. Create a database configuration
ClickHouse Managed Postgres
import { PackageManagers, Render, Steps } from "~/components";
This example connects Hyperdrive to a ClickHouse Managed Postgres database in ClickHouse Cloud. ClickHouse Managed Postgres is a managed PostgreSQL service with local NVMe storage and built-in ClickHouse integration for analytics.
:::note
ClickHouse documents the platform availability and current product status of ClickHouse Managed Postgres. For details, refer to the ClickHouse Managed Postgres documentation.
:::
Prerequisites
Before you begin, you need:
An existing ClickHouse Managed Postgres instance.
A Workers project. Refer to Get started to create one.
Wrangler version
4.9.0 or later, authenticated with your Cloudflare account.
1. Get your connection details
In the ClickHouse Cloud console, select your Postgres instance and open the Connect menu.
Select Directly to use the direct PostgreSQL endpoint. Hyperdrive provides connection pooling.
Copy the hostname, port, database name, username, and password. Use a database role with the permissions your application needs.
In Settings, download the certificate authority (CA) certificate for this instance. Save it locally as
postgres-ca.pem.
For more information, refer to ClickHouse Managed Postgres connection details.
Your database must accept connections from Hyperdrive. If you restrict inbound connections by IP address, allow the Cloudflare IP address ranges.
2. Create a database configuration
Use the instance CA to verify the database server with Transport Layer Security (TLS). The CA certificate is specific to your Postgres instance.
Upload the CA certificate to your Cloudflare account:
Copy the certificate ID from the command output. Create a Hyperdrive configuration using that ID and your database connection details:
Replace each placeholder with your values. Use the direct endpoint port, which defaults to
5432. Keep the password and command output private.
Copy the Hyperdrive configuration ID from the output. Use this ID for the Worker binding in the next section.
The
verify-full mode validates the certificate and database hostname. Hyperdrive checks the connection when you create the configuration. For certificate configuration details, refer to SSL/TLS certificates.
This example turns off query caching so reads reach Postgres. Connection pooling still applies. For workloads that can tolerate cached results, refer to Query caching.
3. Use Hyperdrive from your Worker
To test the connection through Hyperdrive, deploy your Worker and request its URL. A successful response contains
success: true and the query results.
Next steps
Configure local development.
Review supported PostgreSQL features.
Diagnose connection errors with Troubleshoot and debug.
CockroachDB
import { Render } from "~/components";
This example shows you how to connect Hyperdrive to a CockroachDB database cluster. CockroachDB is a PostgreSQL-compatible distributed SQL database with strong consistency guarantees.
1. Allow Hyperdrive access
To allow Hyperdrive to connect to your database, you will need to ensure that Hyperdrive has valid user credentials and network access.
CockroachDB Console
The steps below assume you have an existing CockroachDB Cloud account and database cluster created.
To create and/or fetch your database credentials:
Go to the CockroachDB Cloud console and select the cluster you want Hyperdrive to connect to.
Select SQL Users from the sidebar on the left, and select Add User.
Enter a username (for example, `hyperdrive-user), and select Generate & Save Password.
Note down the username and copy the password to a temporary location.
To retrieve your database connection details:
Go to the CockroachDB Cloud console and select the cluster you want Hyperdrive to connect to.
Select Connect in the top right.
Choose the user you created, for example,
hyperdrive-user.
Select the database, for example
defaultdb.
Select General connection string as the option.
In the text box below, select Copy to copy the connection string.
By default, the CockroachDB cloud enables connections from the public Internet (
0.0.0.0/0). If you have changed these settings on an existing cluster, you will need to allow connections from the public Internet for Hyperdrive to connect.
2. Create a database configuration
Digital Ocean
import { Render, Steps } from "~/components";
This example shows you how to connect Hyperdrive to a Digital Ocean database instance.
1. Allow Hyperdrive access
To allow Hyperdrive to connect to your database, you will need to ensure that Hyperdrive has valid user credentials and network access.
DigitalOcean Dashboard
1. Go to the DigitalOcean dashboard and select the database you wish to
connect to. 2. Go to the **Overview** tab. 3. Under the **Connection Details**
panel, select **Public network**. 4. On the dropdown menu, select **Connection
string** > **show-password**. 5. Copy the connection string.
With the connection string, you can now create a Hyperdrive database configuration.
2. Create a database configuration
:::note
If you see a DNS-related error, it is possible that the DNS for your vendor's database has not yet been propagated. Try waiting 10 minutes before retrying the operation. Refer to DigitalOcean support page for more information.
:::
Fly
import { Render, Steps } from "~/components";
This example shows you how to connect Hyperdrive to a Fly Postgres database instance.
1. Allow Hyperdrive access
You can connect Hyperdrive to any existing Fly database by:
Allocating a public IP address to your Fly database instance
Configuring an external service
Deploying the configuration
Obtain the connection string, which is used to connect the database to Hyperdrive.
1. Run the following command to [allocate a public IP address](https://fly.io/docs/postgres/connecting/connecting-external/#allocate-an-ip-address).
```txt
fly ips allocate-v6 --app
```
:::note
Cloudflare recommends using IPv6, but some Internet service providers may not support IPv6. In this case, [you can allocate an IPv4 address](https://fly.io/docs/postgres/connecting/connecting-with-flyctl/).
:::
Configure an external service by modifying the contents of your
fly.toml file. Run the following command to download the
fly.toml file.
fly config save --app
Then, replace the
services and
services.ports section of the file with the following
toml snippet:
[[services]]
internal_port = 5432 # Postgres instance
protocol = "tcp"
[[services.ports]]
handlers = ["pg_tls"]
port = 5432
Deploy the new configuration.
Obtain the connection string, which is in the form of:
```txt
postgres://{username}:{password}@{public-hostname}:{port}/{database}?options
```
2. Create a database configuration
Google Cloud SQL
import { Render } from "~/components";
This example shows you how to connect Hyperdrive to a Google Cloud SQL Postgres database instance.
1. Allow Hyperdrive access
To allow Hyperdrive to connect to your database, you will need to ensure that Hyperdrive has valid user credentials and network access.
Cloud Console
When creating the instance or when editing an existing instance in the Google Cloud Console:
To allow Hyperdrive to reach your instance:
In the Cloud Console, select the instance you want Hyperdrive to connect to.
Expand Connections > Networking > ensure Public IP is enabled > Add a Network and input
0.0.0.0/0.
Select Done > Save to persist your changes.
Select Overview from the sidebar and note down the Public IP address of your instance.
To create a user for Hyperdrive to connect as:
Select Users in the sidebar.
Select Add User Account > select Built-in authentication.
Provide a name (for example,
hyperdrive-user) > select Generate to generate a password.
Copy this password to your clipboard before selecting Add to create the user.
With the username, password, public IP address and (optional) database name (default:
postgres), you can now create a Hyperdrive database configuration.
gcloud CLI
The gcloud CLI allows you to create a new user and enable Hyperdrive to connect to your database.
Use
gcloud sql to create a new user (for example,
hyperdrive-user) with a strong password:
gcloud sql users create hyperdrive-user --instance=YOUR_INSTANCE_NAME --password=SUFFICIENTLY_LONG_PASSWORD
Run the following command to enable Internet access to your database instance:
# If you have any existing authorized networks, ensure you provide those as a comma separated list.
# The gcloud CLI will replace any existing authorized networks with the list you provide here.
gcloud sql instances patch YOUR_INSTANCE_NAME --authorized-networks="0.0.0.0/0"
Refer to Google Cloud's documentation for additional configuration options.
2. Create a database configuration
Database Providers
import { DirectoryListing } from "~/components";
Materialize
import { Render } from "~/components";
This example shows you how to connect Hyperdrive to a Materialize database. Materialize is a Postgres-compatible streaming database that can automatically compute real-time results against your streaming data sources.
1. Allow Hyperdrive access
To allow Hyperdrive to connect to your database, you will need to ensure that Hyperdrive has valid user credentials and network access to your database.
Materialize Console
:::note
Read the Materialize Quickstart guide to set up your first database. The steps below assume you have an existing Materialize database ready to go.
:::
You will need to create a new application user and password for Hyperdrive to connect with:
Log in to the Materialize Console.
Under the App Passwords section, select Manage app passwords.
Select New app password and enter a name, for example,
hyperdrive-user.
Select Create Password.
Copy the provided password: it will only be shown once.
To retrieve the hostname and database name of your Materialize configuration:
Select Connect in the sidebar of the Materialize Console.
Select External tools.
Copy the Host, Port and Database settings.
With the username, app password, hostname, port and database name, you can now connect Hyperdrive to your Materialize database.
2. Create a database configuration
Neon
import { Render } from "~/components";
This example shows you how to connect Hyperdrive to a Neon Postgres database.
Nile
import { Render } from "~/components";
This example shows you how to connect Hyperdrive to a Nile PostgreSQL database instance.
Nile is PostgreSQL re-engineered for multi-tenant applications. Nile's virtual tenant databases provide you with isolation, placement, insight, and other features for your tenant's data and embedding. Refer to Nile documentation to learn more.
1. Allow Hyperdrive access
You can connect Cloudflare Hyperdrive to any Nile database in your workspace using its connection string - either with a new set of credentials, or using an existing set.
Nile console
To get a connection string from Nile console:
Log in to Nile console, then select a database.
On the left hand menu, click Settings (the bottom-most icon) and then select Connection.
Select the PostgreSQL logo to show the connection string.
Select "Generate credentials" to generate new credentials.
Copy the connection string (without the "psql" part).
You will have obtained a connection string similar to the following:
postgres://0191c898-...:4d7d8b45-...@eu-central-1.db.thenile.dev:5432/my_database
With the connection string, you can now create a Hyperdrive database configuration.
2. Create a database configuration
pgEdge Cloud
import { Render } from "~/components";
This example shows you how to connect Hyperdrive to a pgEdge Postgres database. pgEdge Cloud provides easy deployment of fully-managed, fully-distributed, and secure Postgres.
1. Allow Hyperdrive access
You can connect Hyperdrive to any existing pgEdge database with the default user and password provided by pgEdge.
pgEdge dashboard
To retrieve your connection string from the pgEdge dashboard:
Go to the pgEdge dashboard and select the database you wish to connect to.
From the Connect to your database section, note down the connection string (starting with
postgres://app@...) from the Connection String text box.
2. Create a database configuration
PlanetScale
import { Render } from "~/components";
This example shows you how to connect Hyperdrive to a PlanetScale PostgreSQL database.
1. Allow Hyperdrive access
You can connect Hyperdrive to any existing PlanetScale PostgreSQL database by creating a new role (optional) and retrieving a connection string to your database.
PlanetScale Dashboard
Go to the PlanetScale dashboard and select the database you wish to connect to.
Click Connect.
Create a new role for your Hyperdrive configuration (recommended):
Ensure the minimum required permissions for Hyperdrive to read and write data to your tables:
pg_read_all_data: Read data from all tables, views, and sequences
pg_write_all_data: Write data to all tables, views, and sequences
Click Create role.
Note the user, the password, the database host, and the database name (or
postgres as the default database). You will need these to create a database configuration in Hyperdrive.
With the host, database name, username and password, you can now create a Hyperdrive database configuration.
2. Create a database configuration
:::note
When connecting to a PlanetScale PostgreSQL database with Hyperdrive, you should use a driver like node-postgres (pg) or Postgres.js to connect directly to the underlying database instead of the PlanetScale serverless driver. Hyperdrive is optimized for database access for Workers and will perform global connection pooling and fast query routing by connecting directly to your database.
:::
Prisma Postgres
import { Render, TabItem, Tabs, Steps } from "~/components";
This example shows you how to connect Hyperdrive to a Prisma Postgres database.
1. Allow Hyperdrive access
You can connect Hyperdrive to any existing Prisma Postgres database by using your existing database connection string.
Prisma Data Platform
Go to the Prisma Data Platform Console and select the project (database) you wish to connect to.
Select Connect to your database > Any client.
Select Generate database credentials. Copy the connection string for your Prisma Postgres database.
Edit the connection string to make it compatible with Hyperdrive.
Add the database name after the port. You may remove any query parameters, such as
?sslmode=require.
The final string will look like:
postgres://USERNAME:PASSWORD@HOSTNAME_OR_IP_ADDRESS:PORT/database_name
```
:::note
An alternative to the Prisma Data Platform is to use the [`create-db`](https://www.npmjs.com/package/create-db) package. This package will generate a quick temporary Prisma Postgres database for you to use.
```bash
npx create-db@latest
:::
With this connection string, you can now create a Hyperdrive database configuration.
2. Create a database configuration
4. Configure Hyperdrive maximum connections
Prisma Postgres has limits on the number of direct connections that can be made to the database using Hyperdrive. Refer to Prisma Postgres limits.
:::note
There are two limits to consider here.
Origin database's connection limit, set by the origin database provider. This is the maximum number of direct database connections that can be made to the origin database.
Hyperdrive's origin connection limit, set by Hyperdrive. This is the maximum number of database connections that Hyperdrive can make to your origin database (in this case, Prisma Postgres).
Hyperdrive's origin connection limit should be lower than the Prisma Postgres connection limit, since Hyperdrive's origin connection limit is a soft limit, and Hyperdrive may create more connections if there are network disruptions that prevent existing connections from being used.
:::
From the Cloudflare Hyperdrive dashboard, select your newly created Hyperdrive configuration.
Go to Settings.
In Origin connection limit, select Edit Settings, and set your maximum connections to a number that is lower than your Prisma connection limit.
Edit your existing Hyperdrive configuration with the
--origin-connection-limit parameter:
npx wrangler hyperdrive update --origin-connection-limit=10
Replace
with your Hyperdrive configuration ID and set the connection limit to a number that is less than your Prisma connection limit.
Verify the configuration change:
npx wrangler hyperdrive get
:::note
When connecting to a Prisma Postgres database with Hyperdrive, you should use a driver like node-postgres (pg) or Postgres.js to connect directly to the underlying PostgreSQL database, instead of the Prisma Accelerate extension. Hyperdrive is optimized for database access for Workers, and connects directly to your database to perform global connection pooling and fast query routing.
:::
Supabase
import { Render } from "~/components";
This example shows you how to connect Hyperdrive to a Supabase Postgres database.
1. Allow Hyperdrive access
You can connect Hyperdrive to any existing Supabase database as the Postgres user which is set up during project creation.
Alternatively, to create a new user for Hyperdrive, run these commands in the SQL Editor.
CREATE ROLE hyperdrive_user LOGIN PASSWORD 'sufficientlyRandomPassword';
-- Here, you are granting it the postgres role. In practice, you want to create a role with lesser privileges.
GRANT postgres to hyperdrive_user;
The database endpoint can be found in the database settings page.
With a database user, password, database endpoint (hostname and port) and database name (default: postgres), you can now set up Hyperdrive.
:::note
When connecting to Supabase from Hyperdrive, you should use the Direct connection connection string rather than the pooled connection strings. Hyperdrive will perform pooling of connections to ensure optimal access from Workers.
:::
2. Create a database configuration
:::note
When connecting to a Supabase database with Hyperdrive, you should use a driver like node-postgres (pg) or Postgres.js to connect directly to the underlying database instead of the Supabase JavaScript client. Hyperdrive is optimized for database access for Workers and will perform global connection pooling and fast query routing by connecting directly to your database.
:::
Timescale
import { Render } from "~/components";
This example shows you how to connect Hyperdrive to a Timescale time-series database. Timescale is built on PostgreSQL, and includes powerful time-series, event and analytics features.
You can learn more about Timescale by referring to their Timescale services documentation.
1. Allow Hyperdrive access
You can connect Hyperdrive to any existing Timescale database by creating a new user and fetching your database connection string.
Timescale Dashboard
:::note
Similar to most services, Timescale requires you to reset the password associated with your database user if you do not have it stored securely. You should ensure that you do not break any existing clients if when you reset the password.
:::
To retrieve your credentials and database endpoint in the Timescale Console:
Select the service (database) you want Hyperdrive to connect to.
Expand Connection info.
Copy the Service URL. The Service URL is the connection string that Hyperdrive will use to connect. This string includes the database hostname, port number and database name.
If you do not have your password stored, you will need to select Forgot your password? and set a new SCRAM password. Save this password, as Timescale will only display it once.
You will end up with a connection string resembling the below:
postgres://tsdbadmin:YOUR_PASSWORD_HERE@pn79dztyy0.xzhhbfensb.tsdb.cloud.timescale.com:31358/tsdb
With the connection string, you can now create a Hyperdrive database configuration.
2. Create a database configuration
Xata
import { Render } from "~/components";
This example shows you how to connect Hyperdrive to a Xata PostgreSQL database instance.
Drizzle ORM
import { Render, Steps } from "~/components";
Drizzle ORM is a lightweight TypeScript ORM with a focus on type safety. This example demonstrates how to use Drizzle ORM with PostgreSQL via Cloudflare Hyperdrive in a Workers application.
Prerequisites
A Cloudflare account with Workers access
A PostgreSQL database
A Hyperdrive configuration to your PostgreSQL database
1. Install Drizzle
Install the Drizzle ORM and its dependencies such as the node-postgres (
pg) driver:
npm i drizzle-orm pg dotenv
npm i -D drizzle-kit tsx @types/pg @types/node
Add the required Node.js compatibility flags and Hyperdrive binding to your
wrangler.jsonc file:
2. Configure Drizzle
2.1. Define a schema
With Drizzle ORM, we define the schema in TypeScript rather than writing raw SQL.
1. Create a folder `/db/` in `/src/`.
2. Create a `schema.ts` file.
3. In `schema.ts`, define a `users` table as shown below.
```ts title="src/db/schema.ts"
// src/db/schema.ts
import { pgTable, serial, varchar, timestamp } from "drizzle-orm/pg-core";
export const users = pgTable("users", {
id: serial("id").primaryKey(),
name: varchar("name", { length: 255 }).notNull(),
email: varchar("email", { length: 255 }).notNull().unique(),
createdAt: timestamp("created_at").defaultNow(),
});
```
2.2. Connect Drizzle ORM to the database with Hyperdrive
Use your Hyperdrive configuration for your database when using the Drizzle ORM.
Populate your
index.ts file as shown below.
// src/index.ts
import { Client } from "pg";
import { drizzle } from "drizzle-orm/node-postgres";
import { users } from "./db/schema";
export interface Env {
HYPERDRIVE: Hyperdrive;
}
export default {
async fetch(request, env, ctx): Promise {
// Create a new client instance for each request.
const client = new Client({
connectionString: env.HYPERDRIVE.connectionString,
});
// Connect to the database
await client.connect();
// Create the Drizzle client with the node-postgres connection
const db = drizzle(client);
// Sample query to get all users
const allUsers = await db.select().from(users);
return Response.json(allUsers);
},
} satisfies ExportedHandler;
:::note
Use node-postgres with Drizzle ORM when connecting through Hyperdrive.
:::
:::caution[Known issue with Postgres.js]
Pairing Drizzle ORM with the Postgres.js driver over Hyperdrive is not currently supported. Switch your driver to node-postgres (
pg), the recommended driver for Drizzle ORM with Hyperdrive.
:::
2.3. Configure Drizzle-Kit for migrations (optional)
:::note
You need to set up the tables in your database so that Drizzle ORM can make queries that work.
If you have already set it up (for example, if another user has applied the schema to your database), or if you are starting to use Drizzle ORM and the schema matches what already exists in your database, then you do not need to run the migration.
:::
You can generate and run SQL migrations on your database based on your schema using Drizzle Kit CLI. Refer to Drizzle ORM docs for additional guidance.
1. Create a `.env` file the root folder of your project, and add your database connection string. The Drizzle Kit CLI will use this connection string to create and apply the migrations.
# .env
# Replace with your direct database connection string
DATABASE_URL='postgres://user:password@db-host.cloud/database-name'
Create a
drizzle.config.ts file in the root folder of your project to configure Drizzle Kit and add the following content:
// drizzle.config.ts
import "dotenv/config";
import { defineConfig } from "drizzle-kit";
export default defineConfig({
out: "./drizzle",
schema: "./src/db/schema.ts",
dialect: "postgresql",
dbCredentials: {
url: process.env.DATABASE_URL!,
},
});
Generate the migration file for your database according to your schema files and apply the migrations to your database.
Run the following two commands:
npx drizzle-kit generate
No config path provided, using default 'drizzle.config.ts'
Reading config file 'drizzle.config.ts'
1 tables
users 4 columns 0 indexes 0 fks
[✓] Your SQL migration file ➜ drizzle/0000_mysterious_queen_noir.sql 🚀
npx drizzle-kit migrate
No config path provided, using default 'drizzle.config.ts'
Reading config file 'drizzle.config.ts'
Using 'postgres' driver for database querying
3. Deploy your Worker
Deploy your Worker.
npx wrangler deploy
Libraries and Drivers
import { DirectoryListing } from "~/components";
node-postgres (pg)
import { Render } from "~/components";
node-postgres (pg) is a widely-used PostgreSQL driver for Node.js applications. This example demonstrates how to use node-postgres with Cloudflare Hyperdrive in a Workers application.
Postgres.js
import { Render } from "~/components";
Postgres.js is a modern, fully-featured PostgreSQL driver for Node.js. This example demonstrates how to use Postgres.js with Cloudflare Hyperdrive in a Workers application.
Prisma ORM
import { Render, Steps, PackageManagers } from "~/components";
Prisma ORM is a Node.js and TypeScript ORM with a focus on type safety and developer experience. This example demonstrates how to use Prisma ORM with PostgreSQL via Cloudflare Hyperdrive in a Workers application.
Prerequisites
A Cloudflare account with Workers access
A PostgreSQL database (such as Prisma Postgres)
A Hyperdrive configuration to your PostgreSQL database
An existing Worker project
1. Install Prisma ORM
Install Prisma CLI as a dev dependency:
Install the
pg driver and Prisma driver adapter for use with Hyperdrive:
If using TypeScript, install the types package:
Add the required Node.js compatibility flags and Hyperdrive binding to your Wrangler configuration file:
2. Configure Prisma ORM
2.1. Initialize Prisma
Initialize Prisma in your application:
npx prisma init
This creates a
prisma folder with a
schema.prisma file and an
.env file.
2.2. Define a schema
Define your database schema in the
prisma/schema.prisma file:
generator client {
provider = "prisma-client-js"
previewFeatures = ["driverAdapters"]
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id Int @id @default(autoincrement())
name String
email String @unique
createdAt DateTime @default(now())
}
2.3. Set up environment variables
Add your database connection string to the
.env file created by Prisma:
DATABASE_URL="postgres://user:password@host:port/database"
Add helper scripts to your
package.json:
"scripts": {
"migrate": "npx prisma migrate dev",
"generate": "npx prisma generate --no-engine",
"studio": "npx prisma studio"
}
2.4. Generate Prisma Client
Generate the Prisma client with driver adapter support:
npm run generate
2.5. Run migrations
Generate and apply the database schema:
npm run migrate
When prompted, provide a name for the migration (for example,
init).
3. Connect Prisma ORM to Hyperdrive
Use your Hyperdrive configuration when using Prisma ORM. Update your
src/index.ts file:
import { PrismaPg } from "@prisma/adapter-pg";
import { PrismaClient } from "@prisma/client";
export interface Env {
HYPERDRIVE: Hyperdrive;
}
export default {
async fetch(request, env, ctx): Promise {
// Create Prisma client using driver adapter with Hyperdrive connection string
const adapter = new PrismaPg({ connectionString: env.HYPERDRIVE.connectionString });
const prisma = new PrismaClient({ adapter });
// Sample query to create and fetch users
const user = await prisma.user.create({
data: {
name: "John Doe",
email: `john.doe.${Date.now()}@example.com`,
},
});
const allUsers = await prisma.user.findMany();
return Response.json({
newUser: user,
allUsers: allUsers,
});
},
} satisfies ExportedHandler;
:::note
When using Prisma ORM with Hyperdrive, you must use driver adapters to properly utilize the Hyperdrive connection string. The
@prisma/adapter-pg driver adapter allows Prisma ORM to work with the
pg driver and Hyperdrive's connection pooling. This approach provides connection pooling at the network level through Hyperdrive, so you don't need Prisma-specific connection pooling extensions like Prisma Accelerate.
:::
4. Deploy your Worker
Deploy your Worker:
npx wrangler deploy
Observability
import { DirectoryListing } from "~/components";
Metrics and analytics
import { DashButton } from "~/components";
Hyperdrive exposes analytics that allow you to inspect query volume, query latency, cache hit ratios, and connection pool metrics for each Hyperdrive configuration in your account.
Metrics
Hyperdrive currently exports metrics via the
hyperdriveQueriesAdaptiveGroups and
hyperdrivePoolSizesAdaptiveGroups GraphQL datasets.
Query metrics
The
hyperdriveQueriesAdaptiveGroups dataset contains the following metrics:
Metric
GraphQL Field Name
Description
Queries
count
The number of queries issued against your Hyperdrive in the given time period.
Cache Status
cacheStatus
Whether the query was cached or not. Can be one of
disabled,
hit,
miss,
uncacheable,
multiplestatements,
notaquery,
oversizedquery,
oversizedresult,
parseerror,
transaction, and
volatile.
Query Bytes
queryBytes
The size of your queries, in bytes.
Result Bytes
resultBytes
The size of your query results, in bytes.
Connection Latency
connectionLatency
The time (in milliseconds) required to establish new connections from Hyperdrive to your database, as measured from your Hyperdrive connection pool(s).
Query Latency
queryLatency
The time (in milliseconds) required to query (and receive results) from your database, as measured from your Hyperdrive connection pool(s).
Event Status
eventStatus
Whether a query responded successfully (
complete) or failed (
error).
The
volatile cache status indicates the query contains a PostgreSQL function categorized as
STABLE or
VOLATILE (for example,
NOW(),
RANDOM()). Refer to Query caching for details on which functions affect cacheability.
Pool size metrics
The
hyperdrivePoolSizesAdaptiveGroups dataset contains the following connection pool metrics:
Metric
GraphQL Field Name
Description
Avg. open connections
avg.currentPoolSize
Average number of connections currently open in the pool.
Avg. available slots
avg.availablePoolSlots
Average number of pool connections available for checkout.
Avg. waiting clients
avg.waitingClients
Average number of clients waiting for a connection from the pool.
Pool size maximum
max.maxPoolSize
Configured maximum size of the connection pool.
Peak open connections
max.currentPoolSize
Peak number of connections open in the pool.
Peak waiting clients
max.waitingClients
Peak number of clients waiting for a connection from the pool.
Connection contention appears as a spike in waiting clients, or when open connections consistently approach the pool size maximum. If your open connections regularly approach this limit, consider increasing your Hyperdrive connection limit.
Metrics can be queried (and are retained) for the past 31 days.
View metrics in the dashboard
Per-database analytics for Hyperdrive are available in the Cloudflare dashboard. To view current and historical metrics for a Hyperdrive configuration:
In the Cloudflare dashboard, go to the Hyperdrive page.
Select an existing Hyperdrive configuration.
Select the Metrics tab.
You can optionally select a time window to query. This defaults to the last 24 hours.
The dashboard includes a Pool connections chart, which displays waiting connections, open connections, and the pool size maximum. You can use the location selector to filter by specific Cloudflare locations.
Query via the GraphQL API
You can programmatically query analytics for your Hyperdrive configurations via the GraphQL Analytics API. This API queries the same datasets as the Cloudflare dashboard, and supports GraphQL introspection.
Hyperdrive's GraphQL datasets require an
accountTag filter with your Cloudflare account ID. Hyperdrive exposes the
hyperdriveQueriesAdaptiveGroups and
hyperdrivePoolSizesAdaptiveGroups datasets.
Write GraphQL queries
Examples of how to explore your Hyperdrive metrics.
Get the number of queries handled via your Hyperdrive config by cache status
query HyperdriveQueries(
$accountTag: string!
$configId: string!
$datetimeStart: Time!
$datetimeEnd: Time!
) {
viewer {
accounts(filter: { accountTag: $accountTag }) {
hyperdriveQueriesAdaptiveGroups(
limit: 10000
filter: {
configId: $configId
datetime_geq: $datetimeStart
datetime_leq: $datetimeEnd
}
) {
count
dimensions {
cacheStatus
}
}
}
}
}
Get the average query and connection latency for queries handled via your Hyperdrive config within a range of time, excluding queries that failed due to an error
query AverageHyperdriveLatencies(
$accountTag: string!
$configId: string!
$datetimeStart: Time!
$datetimeEnd: Time!
) {
viewer {
accounts(filter: { accountTag: $accountTag }) {
hyperdriveQueriesAdaptiveGroups(
limit: 10000
filter: {
configId: $configId
eventStatus: "complete"
datetime_geq: $datetimeStart
datetime_leq: $datetimeEnd
}
) {
avg {
connectionLatency
queryLatency
}
}
}
}
}
Get the total amount of query and result bytes flowing through your Hyperdrive config
query HyperdriveQueryAndResultBytesForSuccessfulQueries(
$accountTag: string!
$configId: string!
$datetimeStart: Date!
$datetimeEnd: Date!
) {
viewer {
accounts(filter: { accountTag: $accountTag }) {
hyperdriveQueriesAdaptiveGroups(
limit: 10000
filter: {
configId: $configId
datetime_geq: $datetimeStart
datetime_leq: $datetimeEnd
}
) {
sum {
queryBytes
resultBytes
}
}
}
}
}
Get the pool size metrics for your Hyperdrive config
query HyperdrivePoolSizes(
$accountTag: string!
$configId: string!
$datetimeStart: Time!
$datetimeEnd: Time!
) {
viewer {
accounts(filter: { accountTag: $accountTag }) {
hyperdrivePoolSizesAdaptiveGroups(
limit: 10000
filter: {
configId: $configId
datetime_geq: $datetimeStart
datetime_leq: $datetimeEnd
}
) {
avg {
currentPoolSize
availablePoolSlots
waitingClients
}
max {
maxPoolSize
currentPoolSize
waitingClients
}
dimensions {
coloCode
}
}
}
}
}
Troubleshoot and debug
Troubleshoot and debug errors commonly associated with connecting to a database with Hyperdrive.
Configuration errors
When creating a new Hyperdrive configuration, or updating the connection parameters associated with an existing configuration, Hyperdrive performs a test connection to your database in the background before creating or updating the configuration.
Hyperdrive will also issue an empty test query, a
; in PostgreSQL, to validate that it can pass queries to your database.
Error Code
Details
Recommended fixes
2008
Bad hostname.
Hyperdrive could not resolve the database hostname. Confirm it exists in public DNS.
2009
The hostname does not resolve to a public IP address, or the IP address is not a public address.
Hyperdrive can only connect to public IP addresses. Private IP addresses, like
10.1.5.0 or
192.168.2.1, are not currently supported.
2010
Cannot connect to the host:port.
Hyperdrive could not route to the hostname: ensure it has a public DNS record that resolves to a public IP address. Check that the hostname is not misspelled.
2011
Connection refused.
A network firewall or access control list (ACL) is likely rejecting requests from Hyperdrive. Ensure you have allowed connections from the public Internet.
2012
TLS (SSL) not supported by the database.
Hyperdrive requires TLS (SSL) to connect. Configure TLS on your database.
2013
Invalid database credentials.
Ensure your username is correct (and exists), and the password is correct (case-sensitive).
2014
The specified database name does not exist.
Check that the database (not table) name you provided exists on the database you are asking Hyperdrive to connect to.
2015
Generic error.
Hyperdrive failed to connect and could not determine a reason. Open a support ticket so Cloudflare can investigate.
2016
Test query failed.
Confirm that the user Hyperdrive is connecting as has permissions to issue read and write queries to the given database.
Failure to connect
Hyperdrive may also emit
Failed to connect to the provided database when it fails to connect to the database when attempting to create a Hyperdrive configuration. This is possible when the TLS (SSL) certificates are misconfigured. Here is a non-exhaustive table of potential failure to connect errors:
Error message
Details
Recommended fixes
Server return error and closed connection.
This message occurs when you attempt to connect to a database that has client certificate verification enabled.
Ensure you are configuring your Hyperdrive with client certificates if your database requires them.
TLS handshake failed: cert validation failed.
This message occurs when Hyperdrive has been configured with server CA certificates and is indicating that the certificate provided by the server has not been signed by the expected CA certificate.
Ensure you are using the correct CA certificate for Hyperdrive, or ensure you are connecting to the right database.
Connection errors
Hyperdrive may also return errors at runtime. This can happen during initial connection setup, or in response to a query or other wire-protocol command sent by your driver.
These errors are returned as
ErrorResponse wire protocol messages, which are handled by most drivers by throwing from the responsible query or by triggering an error event.
Hyperdrive errors that do not map 1:1 with an error message code documented by PostgreSQL use the
58000 error code.
Hyperdrive may also encounter
ErrorResponse wire protocol messages sent by your database. Hyperdrive will pass these errors through unchanged when possible.
Hyperdrive specific errors
Error Message
Details
Recommended fixes
Internal error.
Something is broken on our side.
Check for an ongoing incident affecting Hyperdrive, and contact Cloudflare Support. Retrying the query is appropriate, if it makes sense for your usage pattern.
Failed to acquire a connection from the pool.
Hyperdrive timed out while waiting for a connection to your database, or cannot connect at all.
If you are seeing this error intermittently, your Hyperdrive pool is being exhausted because too many connections are being held open for too long by your worker. This can be caused by a myriad of different issues, but long-running queries/transactions are a common offender.
Server connection attempt failed: connection_refused
Hyperdrive is unable to create new connections to your origin database.
A network firewall or access control list (ACL) is likely rejecting requests from Hyperdrive. Ensure you have allowed connections from the public Internet. Sometimes, this can be caused by your database host provider refusing incoming connections when you go over your connection limit.
Hyperdrive does not currently support MySQL COM_STMT_PREPARE messages
Hyperdrive does not support prepared statements for MySQL databases.
Remove prepared statements from your MySQL queries.
Node errors
Error Message
Details
Recommended fixes
Uncaught Error: No such module "node:"
Your Cloudflare Workers project or a library that it imports is trying to access a Node module that is not available.
Enable Node.js compatibility for your Cloudflare Workers project to maximize compatibility.
Stale reads after writes
If your application writes data and then a later read returns older data, Hyperdrive query caching may be serving a cached read query result. Check Hyperdrive metrics by
cacheStatus to confirm whether reads return
hit,
miss,
disabled, or
uncacheable. Refer to Metrics and analytics.
To resolve stale reads after writes, refer to Query caching for guidance on splitting fresh reads from cacheable reads, including using a cache-disabled Hyperdrive configuration for reads that must return fresh data.
Uncached queries
If your queries are not being cached despite Hyperdrive having caching enabled, check the following:
Stable or volatile PostgreSQL functions in your query: Queries that contain PostgreSQL functions categorized as
STABLE or
VOLATILE are not cacheable. Common examples include
NOW(),
CURRENT_TIMESTAMP,
CURRENT_DATE,
RANDOM(), and
LASTVAL(). To resolve this, move the function call to your application code and pass the result as a query parameter. For example, instead of
WHERE created_at > NOW(), compute the timestamp in your Worker and pass it as a parameter:
WHERE created_at > $1. Refer to Query caching for a full list of uncacheable functions.
Function names in SQL comments: Hyperdrive uses text-based pattern matching to detect some uncacheable functions. References to function names like
NOW() in SQL comments can cause the query to be treated as uncacheable, even if the function is not actually called. Remove references to uncacheable function names from query text, including comments.
Driver configuration: Your driver may be configured such that your queries are not cacheable by Hyperdrive. This may happen if you are using the Postgres.js driver with
prepare: false. To resolve this, enable prepared statements with
prepare: true.
Driver errors
Error Message
Details
Recommended fixes
Code generation from strings disallowed for this context
The database driver you are using is attempting to use the
eval() command, which is unsupported on Cloudflare Workers (common in
mysql2 driver).
Configure the database driver to not use
eval(). See how to configure
mysql2 to disable the usage of
eval().
Stale connection and I/O context errors
These errors occur when a database client or connection is created in the global scope (outside of a request handler) or is reused across requests. Workers do not allow I/O across requests, and database connections from a previous request context become unusable. Always create database clients inside your handlers.
Workers runtime errors
Error Message
Details
Recommended fixes
Disallowed operation called within global scope. Asynchronous I/O (ex: fetch() or connect()), setting a timeout, and generating random values are not allowed within global scope.
Your Worker is attempting to open a database connection or perform I/O during script startup, outside of a request handler.
Move the database client creation into your
fetch,
queue, or other handler function.
Cannot perform I/O on behalf of a different request. I/O objects (such as streams, request/response bodies, and others) created in the context of one request handler cannot be accessed from a different request's handler.
A database connection or client created during one request is being reused in a subsequent request.
Create a new database client on every request instead of caching it in a global variable. Hyperdrive's connection pooling already eliminates the connection startup overhead.
node-postgres (
pg) errors
Error Message
Details
Recommended fixes
Connection terminated
The client's
.end() method was called, or the connection was cleaned up at the end of a previous request.
Create a new
Client inside your handler instead of reusing one from a prior request.
Connection terminated unexpectedly
The underlying connection was dropped without an explicit
.end() call — for example, when a previous request's context was garbage collected.
Create a new
Client inside your handler for every request.
Client has encountered a connection error and is not queryable
A socket-level error occurred on the connection (common when reusing a client across requests).
Create a new
Client inside your handler. Do not store clients in global variables.
Client was closed and is not queryable
A query was attempted on a client whose
.end() method was already called.
Create a new
Client inside your handler instead of reusing one.
Cannot use a pool after calling end on the pool
pool.connect() was called on a
Pool instance that has already been ended.
Do not use
new Pool() in the global scope. Create a
new Client() inside your handler — Hyperdrive handles connection pooling for you.
Client has already been connected. You cannot reuse a client.
client.connect() was called on a client that was already connected in a previous invocation.
Create a new
Client per request. node-postgres clients cannot be reconnected once connected.
Postgres.js (
postgres) errors
Postgres.js error messages include the error code and the target host. The
code property on the error object contains the error code.
Error Message
Details
Recommended fixes
write CONNECTION_ENDED :
A query was attempted after
sql.end() was called, or the connection was cleaned up from a prior request. Error code:
CONNECTION_ENDED.
Create a new
postgres() instance inside your handler.
write CONNECTION_DESTROYED :
The connection was forcefully terminated — for example, during
sql.end({ timeout }) expiration, or because the connection was already terminated. Error code:
CONNECTION_DESTROYED.
Create a new
postgres() instance inside your handler for every request.
write CONNECTION_CLOSED :
The underlying socket was closed unexpectedly while queries were still pending. Error code:
CONNECTION_CLOSED.
Create a new
postgres() instance inside your handler. If this occurs within a single request, check for network issues or query timeouts.
mysql2 errors
Error Message
Details
Recommended fixes
Can't add new command when connection is in closed state
A query was attempted on a connection that has already been closed or encountered a fatal error.
Create a new connection inside your handler instead of reusing one from global scope.
Connection lost: The server closed the connection.
The underlying socket was closed by the server or was garbage collected between requests. Error code:
PROTOCOL_CONNECTION_LOST.
Create a new connection inside your handler for every request.
Pool is closed.
pool.getConnection() was called on a pool that has already been closed.
Do not use
createPool() in the global scope. Create a new
createConnection() inside your handler — Hyperdrive handles pooling for you.
mysql errors
Error Message
Details
Recommended fixes
Cannot enqueue Query after fatal error.
A query was attempted on a connection that previously encountered a fatal error. Error code:
PROTOCOL_ENQUEUE_AFTER_FATAL_ERROR.
Create a new connection inside your handler instead of reusing one from global scope.
Cannot enqueue Query after invoking quit.
A query was attempted on a connection after
.end() was called. Error code:
PROTOCOL_ENQUEUE_AFTER_QUIT.
Create a new connection inside your handler for every request.
Cannot enqueue Handshake after already enqueuing a Handshake.
.connect() was called on a connection that was already connected in a previous request. Error code:
PROTOCOL_ENQUEUE_HANDSHAKE_TWICE.
Create a new connection per request. mysql connections cannot be reconnected once connected.
Improve performance
Having query traffic written as transactions can limit performance. This is because in the case of a transaction, the connection must be held for the duration of the transaction, which limits connection multiplexing. If there are multiple queries per transaction, this can be particularly impactful on connection multiplexing. Where possible, we recommend not wrapping queries in transactions to allow the connections to be shared more aggressively.
Platform
import { DirectoryListing } from "~/components";
Limits
The following limits apply to Hyperdrive configurations, connections, and queries made to your configured origin databases.
Configuration limits
These limits apply when creating or updating Hyperdrive configurations.
Limit
Free
Paid
Maximum configured databases
10 per account
25 per account
Maximum username length [^1]
63 characters (bytes)
63 characters (bytes)
Maximum database name length [^1]
63 characters (bytes)
63 characters (bytes)
[^1]: This is a limit enforced by PostgreSQL. Some database providers may enforce smaller limits.
Connection limits
These limits apply to connections between Hyperdrive and your origin database.
Limit
Free
Paid
Initial connection timeout
15 seconds
15 seconds
Idle connection timeout
10 minutes
10 minutes
Maximum origin database connections (per configuration) [^2]
~20 connections
~100 connections
Hyperdrive does not limit the number of concurrent client connections from your Workers. However, Hyperdrive limits connections to your origin database because most hosted databases have connection limits.
[^2]: Hyperdrive is a distributed system, so a client may be unable to reach an existing pool. In this scenario, a new pool is established with its own connection allocation. This prioritizes availability over strict limit enforcement, which means connection counts may occasionally exceed the listed limits.
Connection errors
When Hyperdrive cannot acquire a connection to your origin database, you may see one of the following errors:
Error message
Cause
Failed to acquire a connection from the pool.
The connection pool is exhausted because connections are held open too long. Long-running queries or transactions are a common cause.
Server connection attempt failed: connection_refused
Your origin database is rejecting connections. This can occur when a firewall blocks Hyperdrive, or when your database provider's connection limit is exceeded.
For a complete list of error codes, refer to Troubleshoot and debug.
Query limits
These limits apply to queries sent through Hyperdrive.
Limit
Free
Paid
Maximum query (statement) duration
60 seconds
60 seconds
Maximum cached query response size
50 MB
50 MB
Queries exceeding the maximum duration are terminated. Query responses larger than 50 MB are not cached but are still returned to your Worker.
Request a limit increase
You can request adjustments to limits that conflict with your project goals by contacting Cloudflare. Not all limits can be increased.
To request an increase, submit a Limit Increase Request form. You can also ask questions in the Hyperdrive channel on Cloudflare's Discord community.
Pricing
import { Render } from "~/components";
Hyperdrive limits are automatically adjusted when subscribed to a Workers Paid plan. Hyperdrive's connection pooling and query caching are included in Workers Paid plan, so do not incur any additional charges.
PlanetScale Postgres & MySQL
You can create PlanetScale Postgres and MySQL databases from Cloudflare and bill PlanetScale database usage through your Cloudflare account as a pay-as-you-go customer.
PlanetScale database usage is separate from Hyperdrive usage. When you create a PlanetScale database from the Cloudflare dashboard, PlanetScale usage appears on your Cloudflare invoice each billing period as a dollar total at PlanetScale's standard pricing.
You can view per-database billing usage in the PlanetScale dashboard. To learn how PlanetScale databases work with Workers and Hyperdrive, refer to PlanetScale Postgres and MySQL with Hyperdrive.
Pricing FAQ
Does connection pooling or query caching incur additional charges?
No. Hyperdrive's built-in cache and connection pooling are included within the stated plans above. There are no hidden limits other than those published.
Are cached queries counted the same as uncached queries?
Yes, any query made through Hyperdrive, whether cached or uncached, whether query or mutation, is counted according to the limits above.
Does Hyperdrive charge for data transfer / egress?
No.
:::note
For questions about pricing, refer to the pricing FAQs.
:::
Release notes
import { ProductReleaseNotes } from "~/components";
{/* */}
FAQ
Below you will find answers to our most commonly asked questions regarding Hyperdrive.
Connectivity
Does Hyperdrive use specific IP addresses to connect to my database?
Hyperdrive connects to your database using Cloudflare's IP address ranges. These are shared by all Hyperdrive configurations and other Cloudflare products.
You can use this to configure restrictions in your database firewall to restrict the IP addresses that can access your database.
Does Hyperdrive support connecting to D1 databases?
Hyperdrive does not support D1 because D1 provides fast connectivity from Workers by design.
Hyperdrive is designed to speed up connectivity to traditional, regional SQL databases such as PostgreSQL. These databases are typically accessed using database drivers that communicate over TCP/IP.
Unlike D1, creating a secure database connection to a traditional SQL database
involves multiple round trips between the client (your Worker) and your database server.
See How Hyperdrive works for more detail on why round trips are needed
and how Hyperdrive solves this.
D1 does not require round trips to create database connections. D1 is designed to be performant for access from Workers by default, without needing Hyperdrive.
Should I use Placement with Hyperdrive?
Yes, if your Worker makes multiple queries per request. Placement runs your Worker near your database, reducing per-query latency from 20-30ms to 1-3ms. Hyperdrive handles connection pooling and setup. Placement reduces the network distance for query execution.
Use
placement.region if your database runs in AWS, GCP, or Azure. Use
placement.host for databases hosted elsewhere.
Caching
Does Hyperdrive invalidate cached reads when I write to my database
No. Hyperdrive does not invalidate cached read query results when your application writes to your database. A matching read can return a cached result until the configured
max_age expires, and Hyperdrive can serve that result during the
stale_while_revalidate window while it refreshes the cache.
Use a cache-disabled Hyperdrive configuration for reads that must return fresh data, such as authentication, sessions, permissions, or reads immediately after a write. Refer to Query caching to choose a caching strategy.
Can I use Hyperdrive if some reads need read-after-write consistency
Yes. Configure two Hyperdrive bindings to the same database: one with query caching enabled for reads that can tolerate short staleness, and one with query caching disabled for reads that must be fresh. The cache-disabled binding still gives you Hyperdrive's connection pooling and fast connection setup.
If an object-relational mapping (ORM) library or authentication library owns the SQL, create separate database clients for each binding and pass the cache-disabled client to the code that needs fresh reads.
Pricing
Does Hyperdrive charge for data transfer / egress?
No.
Is Hyperdrive available on the Workers Free plan?
Yes. Refer to pricing.
Does Hyperdrive charge for additional compute?
Hyperdrive itself does not charge for compute (CPU) or processing (wall clock) time. Workers querying Hyperdrive and computing results: for example, serializing results into JSON and/or issuing queries, are billed per Workers pricing.
Limits
Are there any limits to Hyperdrive?
Refer to the published limits documentation.
Reference
import { DirectoryListing } from "~/components";
Supported databases and features
The following table shows which database engines and/or specific database providers are supported.
Database Engine
Supported
Known supported versions
Details
PostgreSQL
✅
9.0 to
18.x
Both self-hosted and managed (AWS, Azure, Google Cloud, Oracle) instances are supported.
MySQL
✅
5.7 to
8.x
Both self-hosted and managed (AWS, Azure, Google Cloud, Oracle) instances are supported. MariaDB is also supported.
SQL Server
Not currently supported.
MongoDB
Not currently supported.
Supported database providers
Hyperdrive supports managed Postgres and MySQL databases provided by various providers, including AWS, Azure, and GCP. Refer to Examples to see how to connect to various database providers.
Hyperdrive also supports databases that are compatible with the Postgres or MySQL protocol. The following is a non-exhaustive list of Postgres or MySQL-compatible database providers:
Database Engine
Supported
Known supported versions
Details
AWS Aurora
✅
All
Postgres-compatible and MySQL-compatible. Refer to AWS Aurora examples for MySQL and Postgres.
ClickHouse Managed Postgres
✅
All
Refer to the ClickHouse Managed Postgres guide to connect.
Neon
✅
All
Neon currently runs Postgres 15.x
Supabase
✅
All
Supabase currently runs Postgres 15.x
Timescale
✅
All
See the Timescale guide to connect.
Materialize
✅
All
Postgres-compatible. Refer to the Materialize guide to connect.
CockroachDB
✅
All
Postgres-compatible. Refer to the CockroachDB guide to connect.
PlanetScale
✅
All
PlanetScale provides MySQL-compatible and PostgreSQL databases
MariaDB
✅
All
MySQL-compatible.
Supported TLS (SSL) modes
PostgreSQL
Hyperdrive supports the following PostgreSQL TLS (SSL) connection modes when connecting to your origin database:
Mode
Supported
Details
none
No
Hyperdrive does not support insecure plain text connections.
prefer
No (use
require)
Hyperdrive will always use TLS.
require
Yes (default)
TLS is required, and server certificates are validated (based on WebPKI).
verify-ca
Yes
Verifies the server's TLS certificate is signed by a root CA on the client. This ensures the server has a certificate the client trusts.
verify-full
Yes
Identical to
verify-ca, but also requires the database hostname must match a Subject Alternative Name (SAN) present on the certificate.
MySQL
Hyperdrive supports the following MySQL TLS (SSL) connection modes when connecting to your origin database:
Mode
Supported
Details
DISABLED
No
Hyperdrive does not support insecure plain text connections.
PREFERRED
No (use
REQUIRED)
Hyperdrive will always use TLS.
REQUIRED
Yes (default)
TLS is required, and server certificates are validated (based on WebPKI).
VERIFY_CA
Yes
Verifies the server's TLS certificate is signed by a root CA on the client. This ensures the server has a certificate the client trusts.
VERIFY_IDENTITY
Yes
In addition to
VERIFY_CA checks, Hyperdrive requires the database hostname to match a Subject Alternative Name (SAN) or Common Name (CN) on the certificate.
Refer to SSL/TLS certificates documentation for details on how to configure these TLS (SSL) modes for Hyperdrive.
Supported PostgreSQL authentication modes
Hyperdrive supports the following authentication modes for connecting to PostgreSQL databases:
Password Authentication (
md5)
Password Authentication (
password) (clear-text password)
SASL Authentication (
SCRAM-SHA-256)
Unsupported PostgreSQL features:
Hyperdrive does not support the following PostgreSQL features:
SQL-level management of prepared statements, such as using
PREPARE,
DISCARD,
DEALLOCATE, or
EXECUTE.
Advisory locks (PostgreSQL documentation).
LISTEN and
NOTIFY.
PREPARE and
DEALLOCATE.
Any modification to per-session state not explicitly documented as supported elsewhere.
Unsupported MySQL features:
Hyperdrive does not support the following MySQL features:
Non-UTF8 characters in queries
USE statements
Multi-statement queries
Prepared statement queries via SQL (using
PREPARE and
EXECUTE statements) and protocol-level prepared statements.
COM_INIT_DB messages
Authentication plugins other than
caching_sha2_password or
mysql_native_password
In cases where you need to issue these unsupported statements from your application, the Hyperdrive team recommends setting up a second, direct client without Hyperdrive.
Wrangler commands
import { WranglerNamespace } from "~/components";
The following Wrangler commands apply to Hyperdrive.
Tutorials
import { GlossaryTooltip, ListTutorials } from "~/components"
View tutorials to help you get started with Hyperdrive.
Create a serverless, globally distributed time-series API with Timescale
import { Render, PackageManagers, WranglerConfig } from "~/components";
In this tutorial, you will learn to build an API on Workers which will ingest and query time-series data stored in Timescale (they make PostgreSQL faster in the cloud).
You will create and deploy a Worker function that exposes API routes for ingesting data, and use Hyperdrive to proxy your database connection from the edge and maintain a connection pool to prevent us having to make a new database connection on every request.
You will learn how to:
Build and deploy a Cloudflare Worker.
Use Worker secrets with the Wrangler CLI.
Deploy a Timescale database service.
Connect your Worker to your Timescale database service with Hyperdrive.
Query your new API.
You can learn more about Timescale by reading their documentation.
1. Create a Worker project
Run the following command to create a Worker project from the command line:
Make note of the URL that your application was deployed to. You will be using it when you configure your GitHub webhook.
Change into the directory you just created for your Worker project:
cd timescale-api
2. Prepare your Timescale Service
:::note
If you have not signed up for Timescale, go to the signup page where you can start a free 30 day trial with no credit card.
:::
If you are creating a new service, go to the Timescale Console and follow these steps:
Select Create Service by selecting the black plus in the upper right.
Choose Time Series as the service type.
Choose your desired region and instance size. 1 CPU will be enough for this tutorial.
Set a service name to replace the randomly generated one.
Select Create Service.
On the right hand side, expand the Connection Info dialog and copy the Service URL.
Copy the password which is displayed. You will not be able to retrieve this again.
Select I stored my password, go to service overview.
If you are using a service you created previously, you can retrieve your service connection information in the Timescale Console:
Select the service (database) you want Hyperdrive to connect to.
Expand Connection info.
Copy the Service URL. The Service URL is the connection string that Hyperdrive will use to connect. This string includes the database hostname, port number and database name.
:::note
If you do not have your password stored, you will need to select Forgot your password? and set a new SCRAM password. Save this password, as Timescale will only display it once.
You should ensure that you do not break any existing clients if when you reset the password.
:::
Insert your password into the Service URL as follows (leaving the portion after the @ untouched):
postgres://tsdbadmin:YOURPASSWORD@...
This will be referred to as SERVICEURL in the following sections.
3. Create your Hypertable
Timescale allows you to convert regular PostgreSQL tables into hypertables, tables used to deal with time-series, events, or analytics data. Once you have made this change, Timescale will seamlessly manage the hypertable's partitioning, as well as allow you to apply other features like compression or continuous aggregates.
Connect to your Timescale database using the Service URL you copied in the last step (it has the password embedded).
If you are using the default PostgreSQL CLI tool psql to connect, you would run psql like below (substituting your Service URL from the previous step). You could also connect using a graphical tool like PgAdmin.
psql
Once you are connected, create your table by pasting the following SQL:
CREATE TABLE readings(
ts timestamptz DEFAULT now() NOT NULL,
sensor UUID NOT NULL,
metadata jsonb,
value numeric NOT NULL
);
SELECT create_hypertable('readings', 'ts');
Timescale will manage the rest for you as you ingest and query data.
4. Create a database configuration
To create a new Hyperdrive instance you will need:
Your SERVICEURL from step 2.
A name for your Hyperdrive service. For this tutorial, you will use hyperdrive.
Hyperdrive uses the
create command with the
--connection-string argument to pass this information. Run it as follows:
npx wrangler hyperdrive create hyperdrive --connection-string="SERVICEURL"
:::note
Hyperdrive will attempt to connect to your database with the provided credentials to verify they are correct before creating a configuration. If you encounter an error when attempting to connect, refer to Hyperdrive's troubleshooting documentation to debug possible causes.
:::
This command outputs your Hyperdrive ID. You can now bind your Hyperdrive configuration to your Worker in your Wrangler configuration by replacing the content with the following:
{
"$schema": "./node_modules/wrangler/config-schema.json",
"name": "timescale-api",
"main": "src/index.ts",
"upload_source_maps": true,
"compatibility_date": "$today",
"compatibility_flags": [
"nodejs_compat"
],
"hyperdrive": [
{
"binding": "HYPERDRIVE",
"id": "your-id-here"
}
]
}
Install the Postgres driver into your Worker project:
Now copy the below Worker code, and replace the current code in
./src/index.ts. The code below:
Uses Hyperdrive to connect to Timescale using the connection string generated from
env.HYPERDRIVE.connectionString directly to the driver.
Creates a
POST route which accepts an array of JSON readings to insert into Timescale in one transaction.
Creates a
GET route which takes a
limit parameter and returns the most recent readings. This could be adapted to filter by ID or by timestamp.
import { Client } from "pg";
export interface Env {
HYPERDRIVE: Hyperdrive;
}
export default {
async fetch(request, env, ctx): Promise {
// Create a new client on each request. Hyperdrive maintains the underlying
// database connection pool, so creating a new client is fast.
const client = new Client({
connectionString: env.HYPERDRIVE.connectionString,
});
await client.connect();
const url = new URL(request.url);
// Create a route for inserting JSON as readings
if (request.method === "POST" && url.pathname === "/readings") {
// Parse the request's JSON payload
const productData = await request.json();
// Write the raw query. You are using jsonb_to_recordset to expand the JSON
// to PG INSERT format to insert all items at once, and using coalesce to
// insert with the current timestamp if no ts field exists
const insertQuery = `
INSERT INTO readings (ts, sensor, metadata, value)
SELECT coalesce(ts, now()), sensor, metadata, value FROM jsonb_to_recordset($1::jsonb)
AS t(ts timestamptz, sensor UUID, metadata jsonb, value numeric)
`;
const insertResult = await client.query(insertQuery, [
JSON.stringify(productData),
]);
// Collect the raw row count inserted to return
const resp = new Response(JSON.stringify(insertResult.rowCount), {
headers: { "Content-Type": "application/json" },
});
return resp;
// Create a route for querying within a time-frame
} else if (request.method === "GET" && url.pathname === "/readings") {
const limit = url.searchParams.get("limit");
// Query the readings table using the limit param passed
const result = await client.query(
"SELECT * FROM readings ORDER BY ts DESC LIMIT $1",
[limit],
);
// Return the result as JSON
const resp = new Response(JSON.stringify(result.rows), {
headers: { "Content-Type": "application/json" },
});
return resp;
}
},
} satisfies ExportedHandler;
5. Deploy your Worker
Run the following command to redeploy your Worker:
npx wrangler deploy
Your application is now live and accessible at
timescale-api..workers.dev. The exact URI will be shown in the output of the wrangler command you just ran.
After deploying, you can interact with your Timescale IoT readings database using your Cloudflare Worker. Connection from the edge will be faster because you are using Cloudflare Hyperdrive to connect from the edge.
You can now use your Cloudflare Worker to insert new rows into the
readings table. To test this functionality, send a
POST request to your Worker’s URL with the
/readings path, along with a JSON payload containing the new product data:
[
{ "sensor": "6f3e43a4-d1c1-4cb6-b928-0ac0efaf84a5", "value": 0.3 },
{ "sensor": "d538f9fa-f6de-46e5-9fa2-d7ee9a0f0a68", "value": 10.8 },
{ "sensor": "5cb674a0-460d-4c80-8113-28927f658f5f", "value": 18.8 },
{ "sensor": "03307bae-d5b8-42ad-8f17-1c810e0fbe63", "value": 20.0 },
{ "sensor": "64494acc-4aa5-413c-bd09-2e5b3ece8ad7", "value": 13.1 },
{ "sensor": "0a361f03-d7ec-4e61-822f-2857b52b74b3", "value": 1.1 },
{ "sensor": "50f91cdc-fd19-40d2-b2b0-c90db3394981", "value": 10.3 }
]
This tutorial omits the
ts (the timestamp) and
metadata (the JSON blob) so they will be set to
now() and
NULL respectively.
Once you have sent the
POST request you can also issue a
GET request to your Worker’s URL with the
/readings path. Set the
limit parameter to control the amount of returned records.
If you have curl installed you can test with the following commands (replace
with your subdomain from the deploy command above):
curl --request POST --data @- 'https://timescale-api..workers.dev/readings' <.workers.dev/readings?limit=10"
In this tutorial, you have learned how to create a working example to ingest and query readings from the edge with Timescale, Workers, Hyperdrive, and TypeScript.
Next steps
Learn more about How Hyperdrive Works.
Learn more about Timescale.
Refer to the troubleshooting guide to debug common issues.