PostgreSQL
Connect a PostgreSQL database through Cloudflare Hyperdrive, then use the same Drizzle schema and queries as with D1.
On this pageLearn what Hyperdrive does · Configure PostgreSQL locally and in production · Deploy with migrations
What is Hyperdrive?
Hyperdrive pools connections between your Worker and PostgreSQL. Requests reuse a connection instead of opening a new TCP and TLS connection each time.
The SDK can provision the Hyperdrive configuration from your connection string. Direct Cloudflare deploys also need an API token the first time. See the Cloudflare guide.
Configuration
1. Set the database
This step sets the database in void.config.ts.
{
"database": "pg"
}2. Add your connection string
This step adds DATABASE_URL to .env for local development.
DATABASE_URL=postgresql://user:password@host:5432/mydb?sslmode=requireLocal Vite development then connects straight to Postgres.
3. Deploy
On an SDK platform, deploy asks for the connection string if needed. You can also set it with void db set-url. For direct Cloudflare deploys, export the production DATABASE_URL in your shell.
The SDK provisions Hyperdrive without saving the connection string in project config. Both postgres:// and postgresql:// URLs are supported, including provider query strings such as ?sslmode=require.
The Hyperdrive that the SDK creates connects with TLS in Cloudflare's default require mode. Hyperdrive does not use the sslmode=verify-ca, sslmode=verify-full, or sslrootcert settings from your connection string. To have Hyperdrive verify your database against a specific certificate authority on a direct Cloudflare deploy, create the Hyperdrive in Cloudflare with that certificate and add its ID to cloudflare.hyperdrive.
Schema definition
This step imports schema helpers from void/schema-pg.
// db/schema.ts
import { pgTable, serial, text, timestamp, boolean } from 'void/schema-pg';
export const users = pgTable('users', {
id: serial('id').primaryKey(),
name: text('name').notNull(),
email: text('email').notNull().unique(),
role: text('role').notNull().default('user'),
active: boolean('active').notNull().default(true),
createdAt: timestamp('created_at').notNull().defaultNow(),
updatedAt: timestamp('updated_at').notNull().defaultNow(),
});void gen model generates PostgreSQL-appropriate code when database is set to "pg".
Migrations
This step runs the same migration workflow as D1.
# Generate migration files from schema changes
void db generate
# Apply pending migrations locally
void db migrateExample output: A new migration file, then the migration applied locally.
# Check migration status
void db statusExample output: The applied and pending migrations.
The difference is transactional DDL. Each migration runs inside BEGIN and COMMIT. A failure rolls back the whole migration and never leaves the database half-updated.
void deploy applies pending migrations before making the new version live. See Deployment.
Updating the connection string
Requires: login or token
The database URL contains credentials. Keep it out of code and chat.
This step updates a linked project's connection, for example after a database move.
void db set-urlExample output: A prompt for the database URL, which is stored as a secret.
The command asks for the new string and updates Hyperdrive.