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.
What this skill does
# PlanetScale — Serverless MySQL Platform
## 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
```bash
# 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
```sql
-- 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);
```
```bash
# 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
```typescript
// 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
```typescript
// 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")
}
```
```bash
# 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
```bash
# 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
```bash
# 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
1. **Branch for every schema change** — Never modify main directly; create a branch, test, then deploy via deploy request
2. **No foreign key constraints** — PlanetScale (Vitess) doesn't support FK constraints; use `relationMode = "prisma"` or enforce in application code
3. **Serverless driver for edge** — Use `@planetscale/database` (HTTP-based) for Vercel Edge, Cloudflare Workers; use mysql2 for Node.js servers
4. **Non-blocking migrations** — PlanetScale applies ALTER TABLE without locking; deploy schema changes during business hours safely
5. **Deploy request review** — Treat deploy requests like pull requests; review the diff before deploying to production
6. **Index before you need them** — Add indexes on columns you filter/sort by; PlanetScale's query insights shows which queries need them
7. **Connection string from environment** — Use `pscale connect` for local dev (no password needed); use connection strings in production
8. **Read replicas for read-heavy apps** — PlanetScale supports read-only regions; route read queries to replicas for lower latency
Related in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.