planetscale
Expert guidance for PlanetScale, the serverless MySQL platform built on Vitess (the database clustering system powering YouTube). Helps developers set up databases with Git-like branching for schema changes, non-blocking schema migrations, and connection pooling for serverless environments.
Usage
Getting Started
- Install the skill using the command above
- Open your AI coding agent (Claude Code, Codex, Gemini CLI, or Cursor)
- Reference the skill in your prompt
- The AI will use the skill's capabilities automatically
Example Prompts
- "Review the open pull requests and summarize what needs attention"
- "Generate a changelog from the last 20 commits on the main branch"
Documentation
Overview
PlanetScale, the serverless MySQL platform built on Vitess (the database clustering system powering YouTube). Helps developers set up databases with Git-like branching for schema changes, non-blocking schema migrations, and connection pooling for serverless environments.
Instructions
CLI Operations
# Install PlanetScale CLI
brew install planetscale/tap/pscale
# Authenticate
pscale auth login
# Create a database
pscale database create my-app --region us-east
# Connect to your database (opens a local proxy)
pscale connect my-app main --port 3306
# Now connect your app to localhost:3306 with no password
# Create a branch (like git branch, for schema changes)
pscale branch create my-app add-orders-table
# Connect to the branch for testing
pscale connect my-app add-orders-table --port 3307
# Open a shell on the branch
pscale shell my-app add-orders-table
Schema Branching
-- On the "add-orders-table" branch, make schema changes safely
-- These changes don't affect the main branch until you merge
CREATE TABLE orders (
id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
user_id BIGINT NOT NULL,
amount DECIMAL(10, 2) NOT NULL,
currency VARCHAR(3) NOT NULL DEFAULT 'USD',
status ENUM('pending', 'processing', 'completed', 'refunded') NOT NULL DEFAULT 'pending',
metadata JSON,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_user_id (user_id),
INDEX idx_status_created (status, created_at)
);
-- Add columns to existing tables
ALTER TABLE users ADD COLUMN stripe_customer_id VARCHAR(255);
ALTER TABLE users ADD INDEX idx_stripe_customer (stripe_customer_id);
# Create a deploy request (like a pull request for schema changes)
pscale deploy-request create my-app add-orders-table
# Review the deploy request
pscale deploy-request diff my-app 1
# Deploy (non-blocking — zero downtime)
pscale deploy-request deploy my-app 1
# Schema changes are applied without locking tables
# PlanetScale uses Vitess's online DDL (gh-ost) under the hood
Application Integration
// src/lib/db.ts — Connect to PlanetScale
import { connect } from "@planetscale/database";
// Serverless driver (HTTP-based, works in edge functions)
const db = connect({
host: process.env.DATABASE_HOST,
username: process.env.DATABASE_USERNAME,
password: process.env.DATABASE_PASSWORD,
});
// Query
async function getOrders(userId: string) {
const results = await db.execute(
"SELECT * FROM orders WHERE user_id = ? ORDER BY created_at DESC LIMIT 20",
[userId]
);
return results.rows;
}
// Insert
async function createOrder(order: { userId: string; amount: number; currency: string }) {
const result = await db.execute(
"INSERT INTO orders (user_id, amount, currency) VALUES (?, ?, ?)",
[order.userId, order.amount, order.currency]
);
return result.insertId;
}
// Transaction
async function processRefund(orderId: string) {
await db.transaction(async (tx) => {
await tx.execute(
"UPDATE orders SET status = 'refunded' WHERE id = ? AND status = 'completed'",
[orderId]
);
const order = await tx.execute("SELECT * FROM orders WHERE id = ?", [orderId]);
await tx.execute(
"INSERT INTO refunds (order_id, amount) VALUES (?, ?)",
[orderId, order.rows[0].amount]
);
});
}
With Prisma ORM
// prisma/schema.prisma — PlanetScale with Prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
relationMode = "prisma" // Required: PlanetScale doesn't support foreign keys
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String
plan String @default("free")
orders Order[]
createdAt DateTime @default(now()) @map("created_at")
@@map("users")
}
model Order {
id Int @id @default(autoincrement())
userId Int @map("user_id")
amount Decimal @db.Decimal(10, 2)
status String @default("pending")
user User @relation(fields: [userId], references: [id])
createdAt DateTime @default(now()) @map("created_at")
@@index([userId])
@@index([status, createdAt])
@@map("orders")
}
# Push schema changes via Prisma (on a branch)
pscale connect my-app add-orders-table --port 3309 &
DATABASE_URL="mysql://root@localhost:3309/my-app" npx prisma db push
Insights and Monitoring
# View query insights (slow queries, most frequent queries)
pscale query-insights my-app main
# View database size and row counts
pscale database show my-app
# Audit log
pscale audit-log list my-app
Installation
# CLI
brew install planetscale/tap/pscale
# Serverless driver (Node.js)
npm install @planetscale/database
# With Prisma
npm install prisma @prisma/client
Examples
Example 1: Setting up Planetscale with a custom configuration
User request:
I just installed Planetscale. Help me configure it for my TypeScript + React workflow with my preferred keybindings.
The agent creates the configuration file with TypeScript-aware settings, configures relevant plugins/extensions for React development, sets up keyboard shortcuts matching the user's preferences, and verifies the setup works correctly.
Example 2: Extending Planetscale with custom functionality
User request:
I want to add a custom schema branching to Planetscale. How do I build one?
The agent scaffolds the extension/plugin project, implements the core functionality following Planetscale's API patterns, adds configuration options, and provides testing instructions to verify it works end-to-end.
Guidelines
- Branch for every schema change — Never modify main directly; create a branch, test, then deploy via deploy request
- No foreign key constraints — PlanetScale (Vitess) doesn't support FK constraints; use
relationMode = "prisma"or enforce in application code - Serverless driver for edge — Use
@planetscale/database(HTTP-based) for Vercel Edge, Cloudflare Workers; use mysql2 for Node.js servers - Non-blocking migrations — PlanetScale applies ALTER TABLE without locking; deploy schema changes during business hours safely
- Deploy request review — Treat deploy requests like pull requests; review the diff before deploying to production
- Index before you need them — Add indexes on columns you filter/sort by; PlanetScale's query insights shows which queries need them
- Connection string from environment — Use
pscale connectfor local dev (no password needed); use connection strings in production - Read replicas for read-heavy apps — PlanetScale supports read-only regions; route read queries to replicas for lower latency
Information
- Version
- 1.0.0
- Author
- terminal-skills
- Category
- Development
- License
- Apache-2.0