Skip to content
Built with

MySQL ​

Build & Deploy

Connect a MySQL database through Cloudflare Hyperdrive, then define tables and query them with Drizzle. The SDK configures the connection and applies your migrations when you deploy.

On this pageConnect MySQL through Hyperdrive · Configure local development · Deploy with migrations

Configure ​

This step sets the dialect in void.config.ts.

json
{
  "database": "mysql"
}

This step adds a direct connection for local development.

dotenv
DATABASE_URL=mysql://user:password@host:3306/app

The SDK reads .env for the dev server and void db commands. In production, the Worker connects through the inferred HYPERDRIVE binding.

Define a schema ​

ts
// db/schema.ts
import { int, mysqlTable, text, timestamp } from 'void/schema-mysql';

export const messages = mysqlTable('messages', {
  id: int('id').autoincrement().primaryKey(),
  text: text('text').notNull(),
  createdAt: timestamp('created_at').notNull().defaultNow(),
});

void gen model generates MySQL builders automatically when the project uses the MySQL dialect.

Migrations ​

This step runs the normal migration workflow.

sh
void db generate
void db migrate

Example output: A new migration file, then the migration applied locally.

sh
void deploy

Example output: Pending migrations applied remotely, then the deployed URL.

For direct Cloudflare deploys, export the production DATABASE_URL in the shell running void deploy --platform cloudflare. The SDK uses it to provision Hyperdrive and apply pending migrations before uploading the Worker. It is not written to the Worker config.

Only one migration run changes a database at a time, whether it comes from void db migrate, void db reset, the reset that void db seed does before it loads data, void deploy --platform cloudflare, or a void deploy of any project that uses the database. Better Auth's table changes run inside the same run. Another run waits for it, up to about 20 seconds for a command that connects with DATABASE_URL and about 2 minutes for a void deploy to SDK platform, then stops with an error that asks you to try again.

Failed migrations ​

Each migration file runs in a transaction. A failed file that only changes data leaves the database unchanged. On a sharded Vitess keyspace, such as a sharded PlanetScale database, a commit that fails on one shard does not undo the shards that already committed. MySQL commits schema changes such as CREATE TABLE and ALTER TABLE at once. If a file with schema changes fails partway, its earlier statements stay applied. The error names the file that failed.

This step recovers. Undo the applied statements, fix the file, then run void db migrate or void deploy again.

sh
void db execute "DROP TABLE comments"
void db execute --remote "DROP TABLE comments" # deployed database

Example output: The statement runs against the local database, then against the deployed one.

MySQL rejects IF NOT EXISTS on ADD COLUMN and CREATE INDEX. Undoing a statement is usually simpler than making it rerunnable. Small migrations leave less to undo.

Database commands ​

void db push, generate, migrate, status, reset, seed, execute, studio, export, rename-migrations, and set-url all understand MySQL. Local commands use DATABASE_URL from .env. --remote and Studio use the encrypted URL stored for a linked SDK project.

Next steps ​

implemented.stream AI