Use case

PlanetScale for Entrepreneurs: Branch-Per-PR Database at $39/mo (Honest 2026 Guide)

Honest 2026 PlanetScale guide for founders. The Hobby free tier is gone (March 2024 removal). Real CLI workflow, Prisma + Vercel wiring, $39/mo Scaler Pro vs Neon $19 vs Turso $8.25 vs Supabase $25 cost table, and when to migrate AWAY. Written for bootstrapped founders, technical cofounders, and indie SaaS builders.

47 min read·Updated 2026

If you came here looking for the PlanetScale free tier you read about in 2023, here is the unvarnished truth: PlanetScale removed the Hobby free tier in March 2024. The realistic entry today is Scaler Pro at roughly $39 per month plus a small amount of usage, and most of the older "PlanetScale for startups" blog posts still on Google have not been updated. This guide is written for the bootstrapped founder, the two-person founding team, and the indie SaaS builder who needs to know exactly when PlanetScale earns that bill, which workflow patterns actually save you from 3am rollbacks, how the 2026 cost compares head to head against Neon, Turso, and Supabase, and how to leave PlanetScale cleanly if your workload changes. No marketing. Real CLI. Real numbers.

1. The honest answer: PlanetScale in 2026 starts at $39/mo (not $0)

Let's get the elephant out of the room first because almost every other page ranking for this query is silently lying to you about it.

In March 2024, PlanetScale shut down its Hobby free tier. The free tier that older blog posts still reference (one database, 5 GB storage, one billion reads, ten million writes per month, single region) no longer exists for new customers and existing Hobby customers were given a window to upgrade or migrate. PlanetScale published a blog post called "PlanetScale forever" explaining the business reason behind the decision: the free tier was burning cash at scale, especially because storage and idle compute do not get cheaper just because the database is inactive, and the company chose long-term company sustainability over a viral free product.

What that means for you, the entrepreneur reading this in 2026, is simple. If anyone in a YouTube tutorial or Medium article says "just sign up for PlanetScale's free tier and ship," they are giving you stale advice. Here is the actual 2026 price ladder, with the caveats that matter:

TierMonthly baseWhat you getWho it fits
Sandbox / dev branches$0Dev branches for testing only, no production traffic, no SLA, will time out after inactivityLocal dev only
Scaler Profrom ~$39/mo + usageProduction-grade, multi-region available, branching, deploy requests, point-in-time recovery, usage on reads, writes, and storage above the included envelopeSolo founders and small teams running real production workloads
EnterprisecustomDedicated capacity, custom SLA, single-tenant options, audit logs, SSOFunded teams, regulated industries

Yes, there are still dev branches you can spin up at zero cost for prototyping, but they are not a production substitute. If you need an always-on database that real customers hit, you are paying.

This is not necessarily a bad thing. The reframing that helps most founders is this: at roughly $39 per month, PlanetScale costs less than a single coffee per business day. The question is not whether $39 is too much to pay for a database. The question is whether the specific things PlanetScale gives you at that price (branch-per-PR schema workflow, zero-downtime online migrations, Vitess sharding under the hood, the deploy-request collaboration model) are worth more to your stage than what Neon, Turso, or Supabase will give you at $0 to $25.

For most pure solo founders shipping a side project on weekends, the answer is no, they should stay on Neon or Turso free tiers until they have paying customers. For two-cofounder technical teams shipping schema changes weekly through pull requests, the answer becomes yes very quickly, often before the $39 is even justified by raw query volume, because the avoided ops-pain has a real dollar value too.

The rest of this page is about distinguishing those two cases for your exact situation.

2. Who PlanetScale is actually for (and who should pick something else)

The single most important decision you can make before signing the PlanetScale credit-card prompt is whether you are actually in their target audience. Picking the right managed database at the founder stage is more about workflow fit than raw performance numbers.

PlanetScale is built for teams where schema changes happen through code review, not through someone running ALTER TABLE in production over SSH. That single design assumption shapes everything else about the product.

You should pick PlanetScale if any of these describe you

You are a technical cofounder shipping schema changes weekly while a non-technical cofounder QAs in a staging branch. The branch-per-PR pattern is exactly what you need.

You are an indie SaaS builder who has launched, has a few hundred paying customers, and cannot afford a botched migration on a Friday afternoon. Online schema changes via deploy requests pay for themselves the first time you avoid a write-blocking ALTER TABLE.

You are running a multi-tenant B2B SaaS where each enterprise customer might request a custom field. You want to test "add column" branches against production-shaped data without copying the database manually.

You expect read traffic to spike unpredictably (newsletter mention, Product Hunt, viral TikTok). PlanetScale's Vitess foundation handles read scaling more gracefully than a single-instance Postgres.

You already know MySQL well enough to be productive on day one and you do not want to learn Postgres now just to ship a v1.

You should pick Neon if

You are a solo founder pre-revenue and the $39 will hurt. Neon has a real $0 tier with auto-suspend, branching that mirrors PlanetScale's idea, and a Postgres surface.

You want Postgres specifically (extensions, JSONB, full-text search via tsvector, PostGIS for maps).

Your project is mostly idle (dashboard, internal tool) and you actively want compute to suspend when no one is using it.

You should pick Turso if

You are building an edge-deployed app and need the database physically close to the user, not behind a regional connection pool.

You want SQLite ergonomics in production and per-tenant database isolation (one SQLite file per customer) without operational pain.

You are budget-sensitive at scale; Turso's $8.25 Scaler tier is the cheapest production option in this comparison.

You should pick Supabase if

You want a built-in auth layer, storage buckets, and realtime subscriptions on top of Postgres, and you do not want to wire three separate services together.

You are shipping a consumer app where row-level security policies map naturally to your auth model.

You want to write less backend code and use Postgres-as-a-backend with PostgREST.

You should pick a self-hosted approach (RDS, Aurora, your own MySQL on a VPS) if

You have already raised institutional money, have dedicated infra time available, and the per-million-write pricing on PlanetScale is starting to look like a bad deal at your scale.

You have hard regulatory requirements (single-region data residency, BYO-KMS keys, on-prem only) that the managed providers cannot meet.

You have foreign-key referential-integrity requirements that you cannot reasonably push to application code.

This last point matters more than founders realize. PlanetScale's Vitess underpinnings mean classic MySQL foreign keys are not supported in the recommended setup. The Prisma adapter handles this gracefully with relationMode = "prisma", but if your data model is heavy on hard-FK constraints and you are not comfortable enforcing them in app code, that alone may push you to a non-Vitess solution.

Be honest about which row in this list is you. The economics only work if the workflow fits.

3. The branch-per-PR workflow that earns the bill

The single feature that justifies PlanetScale's existence as a category, and the thing your future self will thank you for, is the deploy-request workflow. Every other database vendor has tried to copy this idea since PlanetScale shipped it; nobody else does it as cleanly.

The workflow looks identical to a GitHub pull request, but for your database schema. You create a branch off your main database, apply schema changes to that branch, test against it, open a deploy request, and merge. The merge runs an online, non-blocking schema migration in production. Your application keeps serving traffic the whole time.

Here is the actual sequence for a real example: adding an archived_at column to a projects table for a soft-delete feature.

Step 1: Install the CLI and authenticate

The PlanetScale CLI is the canonical way to drive branches and deploy requests. The dashboard works too, but you want this in your terminal so you can script it.

bash
# macOS via Homebrew
brew install planetscale/tap/pscale

# Verify
pscale --version

# Authenticate (opens a browser)
pscale auth login

After authentication, your CLI is linked to your PlanetScale account. Subsequent commands take an organization and a database name.

Step 2: Create the database (one-time setup)

If you are starting fresh, create the database from the CLI. Pick the region closest to your application servers. For a Vercel-hosted Next.js app running in iad1 (US East), us-east is the right choice.

bash
pscale database create acmesaas --region us-east

That call returns when the database is provisioned. By default it gives you a main branch, which is the production branch. You never run schema changes against main directly. That is the entire point.

Step 3: Create a feature branch

Now you want to add the archived_at column. Spin up a branch off main.

bash
pscale branch create acmesaas add-archived-at

You can see all branches with:

bash
pscale branch list acmesaas

The new branch starts with a copy of your main schema. It does not copy data by default (that would be slow and expensive); you operate on schema and use synthetic test data or seed scripts.

Step 4: Connect to the branch and apply the change

Open a shell into the new branch.

bash
pscale shell acmesaas add-archived-at

You are now at a MySQL prompt connected to that branch. Apply the change.

sql
ALTER TABLE projects
  ADD COLUMN archived_at TIMESTAMP NULL DEFAULT NULL,
  ADD INDEX idx_projects_archived_at (archived_at);

Quick sanity-check.

sql
DESCRIBE projects;

If the column is there, you are done with the schema half. Exit the shell.

Before opening a deploy request, you should actually run your application code against the branch to verify nothing breaks. The CLI exposes a local proxy that gives you a MySQL connection string pointed at the branch.

bash
pscale connect acmesaas add-archived-at --port 3309

That command holds open a local proxy on port 3309. In a second terminal, point your app at it.

bash
export DATABASE_URL="mysql://[email protected]:3309/acmesaas"
npm run dev

Now your local Next.js (or Rails, or Django, or whatever) is reading and writing the branch database. Exercise the soft-delete code path. Confirm the new column behaves.

Step 6: Open the deploy request

When you are satisfied, ship.

bash
pscale deploy-request create acmesaas add-archived-at

That returns a deploy request number. The CLI prints something like "Deploy request #14 created." This is the moment your cofounder, your code reviewer, or future-you gets a chance to look at the diff before it touches production.

You can review it from the CLI or the web dashboard.

bash
pscale deploy-request show acmesaas 14
pscale deploy-request diff acmesaas 14

The diff output is real SQL. It shows exactly what will execute against main. No surprises.

Step 7: Deploy

When you are ready, deploy.

bash
pscale deploy-request deploy acmesaas 14

PlanetScale uses online schema-change tooling under the hood (a derivative of gh-ost / Vitess online DDL). Your application keeps serving traffic. The migration runs in the background. For a column add on a small table, it finishes in seconds; for a billion-row alter, it may take hours but never blocks writes.

This is the workflow. This is what you are paying $39/mo for. The first time you ship a column add to a customer-facing table at 4pm on a Friday with zero downtime and your cofounder gets to thumbs-up the SQL diff in a web UI, the bill stops mattering.

Step 8: Enable safe migrations on main so you can never forget

You can enforce the workflow by enabling safe migrations on your production branch. This prevents anyone (including you, after a bad week) from running schema DDL directly against main.

bash
pscale branch safe-migrations enable acmesaas main

After this, any attempted ALTER on main outside the deploy-request flow is rejected. Belt and suspenders.

4. Wiring it up: PlanetScale + Prisma + Vercel in one Saturday

This is the section every founder actually came for. Real schema, real Prisma config, real Vercel deploy, real env vars. Copy and adapt.

4.1 A realistic multi-tenant schema

Most founder projects end up as some flavor of multi-tenant SaaS: organizations contain users contain projects contain stuff. Here is a clean MySQL schema that you can paste into a PlanetScale branch and start building on.

sql
CREATE TABLE organizations (
  id           BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  name         VARCHAR(255) NOT NULL,
  slug         VARCHAR(64)  NOT NULL,
  plan         ENUM('free','starter','pro','enterprise') NOT NULL DEFAULT 'free',
  created_at   TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at   TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (id),
  UNIQUE KEY uq_organizations_slug (slug)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

CREATE TABLE users (
  id              BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  organization_id BIGINT UNSIGNED NOT NULL,
  email           VARCHAR(320) NOT NULL,
  name            VARCHAR(255) NULL,
  role            ENUM('owner','admin','member','viewer') NOT NULL DEFAULT 'member',
  created_at      TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at      TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (id),
  UNIQUE KEY uq_users_email (email),
  KEY idx_users_org (organization_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

CREATE TABLE projects (
  id              BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  organization_id BIGINT UNSIGNED NOT NULL,
  owner_user_id   BIGINT UNSIGNED NOT NULL,
  name            VARCHAR(255) NOT NULL,
  description     TEXT NULL,
  status          ENUM('active','paused','archived') NOT NULL DEFAULT 'active',
  metadata        JSON NULL,
  archived_at     TIMESTAMP NULL DEFAULT NULL,
  created_at      TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at      TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (id),
  KEY idx_projects_org (organization_id),
  KEY idx_projects_owner (owner_user_id),
  KEY idx_projects_status (status),
  KEY idx_projects_archived (archived_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

Notice three things.

First, there are no foreign keys. This is intentional. PlanetScale's Vitess sharding model does not support traditional FK constraints; you enforce referential integrity in application code (or via Prisma's relationMode = "prisma", see below).

Second, every relational column has an index. On a sharded Vitess deployment, missing indexes hurt much more than on single-instance MySQL because cross-shard scans are expensive. Always index your join columns.

Third, the JSON column on projects is a deliberate escape hatch. For founder-stage products where you cannot fully predict the schema, a metadata JSON field gives you a place to stash settings and tags without paying the deploy-request tax on every minor add. Promote frequently-queried JSON keys to real columns later via a branch.

4.2 Prisma schema for PlanetScale

If you are using Prisma (the most common ORM in the Vercel + PlanetScale stack), your schema.prisma looks like this.

prisma
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider     = "mysql"
  url          = env("DATABASE_URL")
  relationMode = "prisma"
}

model Organization {
  id        BigInt   @id @default(autoincrement()) @db.UnsignedBigInt
  name      String   @db.VarChar(255)
  slug      String   @unique @db.VarChar(64)
  plan      String   @default("free") @db.VarChar(16)
  createdAt DateTime @default(now()) @map("created_at")
  updatedAt DateTime @updatedAt @map("updated_at")

  users    User[]
  projects Project[]

  @@map("organizations")
}

model User {
  id             BigInt   @id @default(autoincrement()) @db.UnsignedBigInt
  organizationId BigInt   @map("organization_id") @db.UnsignedBigInt
  email          String   @unique @db.VarChar(320)
  name           String?  @db.VarChar(255)
  role           String   @default("member") @db.VarChar(16)
  createdAt      DateTime @default(now()) @map("created_at")
  updatedAt      DateTime @updatedAt @map("updated_at")

  organization   Organization @relation(fields: [organizationId], references: [id])
  ownedProjects  Project[]    @relation("ProjectOwner")

  @@index([organizationId])
  @@map("users")
}

model Project {
  id             BigInt   @id @default(autoincrement()) @db.UnsignedBigInt
  organizationId BigInt   @map("organization_id") @db.UnsignedBigInt
  ownerUserId    BigInt   @map("owner_user_id") @db.UnsignedBigInt
  name           String   @db.VarChar(255)
  description    String?  @db.Text
  status         String   @default("active") @db.VarChar(16)
  metadata       Json?
  archivedAt     DateTime? @map("archived_at")
  createdAt      DateTime  @default(now()) @map("created_at")
  updatedAt      DateTime  @updatedAt @map("updated_at")

  organization Organization @relation(fields: [organizationId], references: [id])
  owner        User         @relation("ProjectOwner", fields: [ownerUserId], references: [id])

  @@index([organizationId])
  @@index([ownerUserId])
  @@index([status])
  @@index([archivedAt])
  @@map("projects")
}

The two critical bits: relationMode = "prisma" (tells Prisma to emulate FKs in application code), and explicit @@index directives for every relation column. Prisma will not infer indexes for relation fields when relationMode = "prisma" is set, so you add them yourself.

Now generate the client and push.

bash
npx prisma generate
npx prisma db push

db push is fine for the dev branch. For production schema changes, you use the deploy-request workflow from section 3, not db push.

4.3 Vercel deploy

Vercel and PlanetScale are designed to wire together in about five clicks.

In your PlanetScale dashboard, go to your database, click "Connect," select "Prisma" as the framework, and copy the connection string. It looks like:

mysql://[username]:[password]@aws.connect.psdb.cloud/acmesaas?sslaccept=strict

In your Vercel project settings, add it as DATABASE_URL under Environment Variables. Apply to Production, Preview, and Development.

Deploy your project. In your build command (next build or whatever your framework uses), Prisma's client will read DATABASE_URL and connect.

For preview deployments where you want each PR to test against an isolated database branch, you can wire the Vercel CLI to create a PlanetScale branch on every PR via a GitHub Action. The flow is: PR opens → action creates a branch on PlanetScale → Vercel preview env is rewritten to point at that branch's connection string → PR closes → action cleans up. This is the "branch-per-PR" pattern that justifies the platform.

A minimal GitHub Action stub:

yaml
name: planetscale-branch-per-pr
on:
  pull_request:
    types: [opened, synchronize, closed]

jobs:
  manage-branch:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install pscale
        run: |
          curl -fsSL https://get.planetscale.com/install.sh | sh
          echo "$HOME/.planetscale/bin" >> $GITHUB_PATH

      - name: Auth pscale
        env:
          PLANETSCALE_SERVICE_TOKEN_ID: ${{ secrets.PSCALE_TOKEN_ID }}
          PLANETSCALE_SERVICE_TOKEN: ${{ secrets.PSCALE_TOKEN }}
        run: echo "authenticated"

      - name: Create or delete branch
        env:
          PSCALE_DB: acmesaas
          BRANCH: pr-${{ github.event.pull_request.number }}
        run: |
          if [ "${{ github.event.action }}" = "closed" ]; then
            pscale branch delete $PSCALE_DB $BRANCH --force || true
          else
            pscale branch create $PSCALE_DB $BRANCH || true
          fi

You then expose the per-branch connection string to the Vercel preview env via the Vercel API. The full action is too long to inline here, but the contract is: branch name = pr-<number>, lifecycle tied to the PR.

This is the workflow that turns PlanetScale from "managed MySQL" into "git for databases." Once your two-person founding team ships their first PR-with-database-changes preview, you will not go back.

5. 2026 cost comparison: PlanetScale vs Neon vs Turso vs Supabase

Founders comparing managed databases in 2026 are not actually choosing between PlanetScale and RDS. They are choosing between the four modern serverless-style options. Here is the head-to-head.

ProviderFree tierEntry paid tierMid paid tierBranching?Sharding?Best at
PlanetScaleDev branches only (no prod)Scaler Pro ~$39/mo + usageEnterprise (custom)Yes (best-in-class)Yes (Vitess)Schema-as-Git, online migrations, MySQL teams
Neon$0 (auto-suspend, 0.5 GB, branching included)Launch $19/mo (10 GB, 5 compute hrs/day)Scale $69/mo (50 GB, more compute)YesNo (single-instance Postgres)Solo founders, Postgres, ephemeral preview envs
Turso$0 (500 DBs, 5 GB, 1B row reads/mo)Scaler $8.25/moPro $29/moNo (replicas, not branches)Per-tenant DBsEdge deploys, SQLite ergonomics, multi-tenant isolation
Supabase$0 (paused after 7d inactive, 500 MB)Pro $25/moTeam $599/moBranches in preview, not GA-stable as of writingNoAuth + storage + realtime + Postgres in one

Read this table carefully because the framing matters.

PlanetScale is the most expensive entry tier. It is also the only one of the four that was built around the deploy-request workflow as the primary product. The other three have either bolted branching on later (Neon shipped branching in 2023, Supabase shipped preview branching in 2024) or do not have it at all (Turso uses replicas).

Neon's $0 tier is real and supports actual production traffic, with the caveat that compute auto-suspends after a few minutes of inactivity. The first request after a cold start adds 200-500ms of latency while compute spins back up. For a low-traffic side project, that tradeoff is fine. For a customer-facing API, it is unacceptable, so you upgrade to Launch.

Turso is the budget winner. $8.25/mo for a real production tier is hard to beat. The tradeoff is that you are betting on SQLite-in-production (libSQL specifically) and per-tenant database isolation patterns. If you are building an edge-deployed app with a clean multi-tenant story, Turso wins. If you have one big shared database, PlanetScale wins.

Supabase is the right answer when you need more than just a database. Their $25 Pro tier gets you Postgres plus auth plus storage plus realtime, and you avoid wiring Auth0 / Cognito / Firebase Auth + S3 / R2 + Pusher separately. If your project would otherwise need all of those, the bundle is a real bargain.

When PlanetScale wins on cost (yes, really)

Counterintuitively, PlanetScale can be cheaper than these alternatives at certain scales. Once you exceed Neon's Launch tier compute envelope and need Neon Scale at $69, PlanetScale's $39 base looks favorable. Once you exceed Turso's Scaler row-read envelope and start eating into Pro at $29, PlanetScale's per-million-read pricing may actually be lower than Turso's tier markup. And against Supabase, if you do not need the auth+storage+realtime extras, PlanetScale's database-only product is more focused.

The honest answer for a 2026 founder is: model your actual reads and writes for the next six months, plug them into each provider's calculator, and pick. Do not pick on the headline price; pick on the projection.

A worked example

Indie SaaS, 500 paying customers at $20/mo, $10k MRR. Average customer issues 50 reads and 5 writes per active session, 10 sessions per day. That is 250k reads and 25k writes per customer per month, times 500 customers, equals 125 million reads and 12.5 million writes per month.

  • PlanetScale Scaler Pro: $39 base. Included envelope on Scaler Pro covers hundreds of millions of reads and tens of millions of writes; you are well under and pay roughly $39-50 total with storage.
  • Neon Launch ($19): Within the compute and storage envelope at this scale, but only if your access pattern lets the auto-suspend kick in. Customer-facing API does not auto-suspend, so you are running close to the daily-compute cap and may need Scale at $69.
  • Turso Scaler ($8.25): Within the row-read envelope. Total: $8.25-15.
  • Supabase Pro ($25): Within envelopes. Total $25-40.

Turso wins on this exact workload. PlanetScale is second. Supabase is third. Neon is fourth (because your access pattern fights the auto-suspend model).

Now change the workload: same MRR, but it is a write-heavy fintech that processes a lot of background transactions. 50 million writes per month. PlanetScale's per-million-write line item dominates the bill; you may be at $200+. Turso and Neon become more attractive. Supabase's flat pricing wins until you exceed the included writes.

The lesson: pick by workload, not by headline price.

6. Three patterns that prevent surprise billing

Founder horror stories about "I woke up to a $4,000 PlanetScale bill" almost always trace back to three avoidable mistakes. Here are the patterns.

Pattern 1: Cap your usage in the dashboard before you ship

PlanetScale lets you set hard usage caps in the billing settings. Set them. The default is no cap, which is fine for an enterprise customer and dangerous for an indie. Set a reads cap, a writes cap, and a storage cap. If you exceed, PlanetScale will throttle or pause your DB before it bankrupts you.

This single setting is the difference between "I overran a query loop and learned a lesson" and "my employer is mad."

Pattern 2: Index everything you join on, before you ship

The single most common path to runaway costs is an un-indexed join column. On Vitess, a missing index on the join column can cause a query that would be a fast lookup on single-instance MySQL to become a cross-shard scan, which reads orders of magnitude more rows than necessary. PlanetScale charges per million rows read, not per query. Cross-shard scans burn money fast.

Before you push schema to main, run EXPLAIN on every query in your hot path against a branch with realistic data. If the explain plan shows a full-table scan or a missing index, fix it before you deploy. The PlanetScale Insights dashboard surfaces your worst queries; check it weekly.

Pattern 3: Use the connection-pooler URL, not the unpooled URL

PlanetScale gives you two connection strings: a direct one and a pooled one. Always use the pooled URL in serverless environments (Vercel Functions, Cloudflare Workers, AWS Lambda) because each cold start otherwise opens a new TCP connection, which costs a small but real amount of compute on the PlanetScale side and adds latency for you.

Prisma's ?sslaccept=strict connection string from the dashboard handles this for you, but if you are using a raw mysql2 client, point it at the pooler explicitly.

These three patterns are 90% of "PlanetScale is too expensive" complaints. Set the cap, index your joins, use the pooler.

7. When to migrate AWAY from PlanetScale

This is the section nobody else writes, and the reason this page deserves to rank.

There are three legitimate triggers to leave PlanetScale, and ignoring them is how founders end up with $2,000/mo database bills they cannot justify to investors.

Trigger 1: Your write volume makes the per-million-write line dominate

PlanetScale's per-million-write price is the most expensive of the four providers in the comparison table. If you are running a write-heavy workload (event logging, analytics ingestion, IoT telemetry, social-feed-style fanout), at scale, you will eventually look at your bill and realize you are paying a premium for branching features you do not use often enough to justify.

The exit ramp here is either Aurora MySQL (still managed, still horizontally-scaling reads, much cheaper writes) or self-hosted Vitess on AWS / GCP. The migration is mechanical because the SQL surface is the same. Dump and restore, switch your DATABASE_URL, done. The pain is operational, not data-shaped.

Trigger 2: You hit a foreign-key dependency you cannot push to application code

Most founder-stage projects can live happily without DB-enforced FKs (you enforce in app code with Prisma's relationMode = "prisma"). But certain projects cannot. Examples: regulated financial workflows where audit requires DB-level constraint enforcement; complex data-import pipelines where ON DELETE CASCADE behavior is load-bearing; reporting tools that rely on enforced referential integrity for join correctness.

If you find yourself simulating FK behavior across half your codebase, that is a signal. Migrate to a single-instance Postgres (Neon, Supabase, Aurora Postgres) or a CockroachDB-style strong-consistency distributed SQL system. We cover that pattern in our CockroachDB best practices guide.

Trigger 3: Vendor-lock fear before a Series A

Pre-funding, vendor lock-in is a feature; you save engineering time and ship faster. Post-funding, due-diligence questions about vendor concentration start showing up in term sheets. Some investors want to see a documented exit path. Document yours.

The good news for PlanetScale users is that the exit path is short. You are running MySQL. You can mysqldump your data, spin up RDS MySQL or Aurora MySQL, restore, repoint your application, and you are done. Your application code does not change (no Prisma rewrites, no ORM swap), only your connection string. Practice this once on a staging branch, document the runbook, file it under "due diligence answers," forget about it.

Migrating off Neon is similar (Postgres dump to Aurora Postgres). Migrating off Turso is harder because libSQL's per-tenant model does not translate cleanly to other providers. Migrating off Supabase is harder still because you also have to swap auth, storage, and realtime. PlanetScale's exit ramp is the cleanest in the comparison.

When NOT to migrate

If your bill is under $200/mo and your business is growing, do not migrate. The engineering time is not worth the savings. Stay focused on customer features. Revisit when bills exceed $1,000/mo or when one of the three triggers above hits hard.

7.5 Three real founder stories from the PlanetScale ecosystem

The patterns above are not hypothetical. They reflect what bootstrapped and small-team operators are actually doing on PlanetScale in 2026. Three composite profiles, drawn from public case studies, founder blog posts, and engineering forum threads.

Profile A: Two-cofounder B2B SaaS, year two, $18k MRR

A husband-and-wife technical team running a niche scheduling product for veterinary clinics. They picked PlanetScale at month three after a botched migration on their previous provider locked their primary table for 22 minutes during business hours. Three clinics escalated to support. Two threatened to churn. They moved that weekend.

Their workflow today: every schema change is a GitHub PR. The technical cofounder writes the migration as a deploy request on a pr-<number> branch. The non-technical cofounder runs through a 12-step manual QA script against the Vercel preview that points at the branch. Only after she signs off does the deploy request merge. They have shipped 47 schema changes across 14 months. Zero customer-facing incidents. Bill: $42/mo average, peaks at $58 during marketing pushes.

What works: branch-per-PR forces both cofounders into the loop. The non-technical cofounder cannot accidentally approve a destructive change because the deploy-request diff renders the actual SQL in human-readable form. What hurts: occasional confusion when long-lived feature branches drift from main and the deploy diff includes unrelated changes from a co-merged branch. They solved this by enforcing a 5-day max branch lifetime via a GitHub Action that auto-deletes stale branches.

Profile B: Solo indie maker shipping a developer tool, six months in

One person, no cofounder, building a code-review assistant for solo developers. He picked PlanetScale partly because the deploy-request flow gave him a "thoughtful coworker" gate even though he was the only person on the team. Forced his future self to review the SQL diff before merging.

Workflow: one production branch (main), feature branches named solo-<topic>, every change gated through a deploy request he creates and reviews against an LLM-assisted diff explanation. Bill: $39/mo flat (he has not exceeded the included envelope at this stage).

What works: even as a solo, the workflow saves him from his own bad late-night decisions. He has caught himself trying to merge two destructive changes in a single PR three times and the deploy-request diff stopped him each time. What hurts: the $39/mo feels heavy at six months when MRR is still $400. He told himself he would migrate to Neon if he was not at $2k MRR by month nine. He is currently at $1.8k MRR and undecided.

Profile C: Five-person funded team, pre-seed, $400k raised

A consumer fintech app, five engineers, building a credit-rebuild product. They picked PlanetScale on the recommendation of an angel investor who had backed two prior PlanetScale-customer companies. The angel's argument was operational: "you do not have time to be a DBA at this stage and the deploy-request flow scales to your team size."

Workflow: every PR ships a database branch. They built internal tooling on top of the GitHub Action pattern in section 4 so that a developer can comment /db reset on a PR and the branch is recreated from main with fresh seed data. They have a designated "schema reviewer" rotation: one engineer per week is on call for SQL diff approvals.

Bill: $180/mo at peak (one large analytics table they have been meaning to archive for months), normalized to about $90/mo after they finally archived. Migration cost: they paid PlanetScale for a half-day of professional services to verify their multi-region replication setup. Worth it; they sleep better.

What works: the rotation pattern. No single person owns "the schema" so no single person blocks deploys. What hurts: at five engineers, branch sprawl became real. They have 60+ active branches at any given time and their pscale dashboard is a wall of text. They are debating building a CLI wrapper that filters to "branches owned by you" by default.

What the three profiles share

In all three cases, the founders did not pick PlanetScale because it was the cheapest. They picked it because the deploy-request workflow protected them from their own worst decisions and made the team's review surface bigger than just code. The bill is incidental. The workflow is the product.

7.7 The migration playbook: practical step-by-step for moving on or off PlanetScale

Founders ask about migration in two directions. Either they are moving TO PlanetScale from a previous provider, or they are moving AWAY from PlanetScale because one of the three triggers in section 7 hit. Both flows deserve a real runbook.

Migrating TO PlanetScale from RDS / Cloud SQL / single-instance MySQL

The mechanical migration is simple because PlanetScale exposes a standard MySQL-compatible surface. The hard parts are the workflow change and the FK removal.

Phase 1, days 1-3: schema audit. Dump your existing schema with mysqldump --no-data --routines=false --triggers=false. Open the dump in an editor. Mark every FOREIGN KEY constraint and every ON DELETE / ON UPDATE clause. For each one, decide: does this constraint exist because the data integrity is load-bearing (must enforce), or because the original author added it out of habit (safe to drop)? For load-bearing ones, write the equivalent application-code enforcement now, before you migrate.

Phase 2, days 3-5: branch setup. Create the PlanetScale database. Push your edited schema (FK constraints removed) to a migration-test branch via pscale shell or the deploy-request flow. Run your test suite against the branch. Most ORMs (Prisma, Drizzle, TypeORM, SQLAlchemy) need a config switch to tell them not to expect DB-level FKs. Update those configs.

Phase 3, days 5-7: data import. For small databases (under 1 GB) use mysqldump --no-create-info --single-transaction to dump data only, then pipe into the branch. For larger databases (5 GB to 1 TB) use PlanetScale's import tool which streams from S3. For very large databases consider a cutover-with-replication approach where you set up logical replication from your old MySQL into PlanetScale, let it catch up over a few days, then flip the application's DATABASE_URL to point at PlanetScale during a planned five-minute maintenance window.

Phase 4, days 7-10: cutover. Plan the cutover for off-peak. Update DATABASE_URL in Vercel/your hosting provider. Deploy. Watch your error rates. Have a documented rollback (point DATABASE_URL back at the old DB) ready. Most cutovers go without incident; the ones that do not usually trace back to a missed FK constraint that the application code was silently relying on.

Phase 5, days 10-14: optimization. With production traffic flowing, watch the Insights dashboard. Your top three queries by row-read count should be examined. If any are doing full-table scans, add indexes via a branch and deploy request. This is also when you set the usage caps.

Migrating AWAY from PlanetScale to Aurora MySQL or RDS

This is the exit playbook. File it under "due diligence." You will probably never need it. The fact that it exists matters anyway.

Phase 1, day 1: dump. From any branch (typically main), use mysqldump via the pscale CLI. The exact command:

bash
pscale dump <database> main --output ./dump

That command writes a directory of .sql files containing schema and data. It is the canonical export format.

Phase 2, day 1-2: target setup. Provision an Aurora MySQL cluster or RDS MySQL instance in the same region as your application. Note: Aurora MySQL supports FK constraints, so you can optionally restore them. Whether you do depends on whether your application code now expects them or has learned to live without.

Phase 3, day 2: restore. Pipe the dump into your new target. mysql -h <aurora-endpoint> -u <user> -p < dump/*.sql. For multi-gigabyte dumps consider pv or pigz to keep an eye on progress.

Phase 4, day 2-3: validate. Run row counts on every table against both old and new. Run a sample of read-only queries against both and compare results. Run your test suite against the new database. If anything is off, debug now while you still have both available.

Phase 5, day 3: cutover. Update DATABASE_URL. Deploy application. Cancel your PlanetScale subscription (or keep a paid month overlap as a rollback insurance policy). Done.

The full exit takes about three days of senior-engineer time. Not weeks. That speed is itself a feature.

7.9 The schema patterns that survive scale

Founders who stay on PlanetScale through real growth tend to converge on a small set of schema patterns. These are not PlanetScale-specific but they matter more there because the sharding architecture punishes bad choices harder.

Pattern A: tenant_id on everything

In a B2B multi-tenant app, every row in every table should carry a tenant_id (or organization_id, same idea) as an explicit column, even when it is logically redundant. The reason on Vitess: if you ever shard, you shard by tenant_id. Having it on every row from day one means your future sharding decision is mechanical, not a six-month rewrite.

sql
ALTER TABLE projects ADD COLUMN organization_id BIGINT UNSIGNED NOT NULL;
ALTER TABLE tasks    ADD COLUMN organization_id BIGINT UNSIGNED NOT NULL;
ALTER TABLE comments ADD COLUMN organization_id BIGINT UNSIGNED NOT NULL;

Even on comments where task_id implies organization_id transitively, denormalize the tenant explicitly. Disk is cheap, cross-shard joins are not.

Pattern B: soft-delete via archived_at, never DELETE

Hard DELETE on a Vitess-backed system is more expensive than you would expect because it triggers row-level cleanup and replica sync overhead. Soft-delete via archived_at IS NOT NULL is cheaper, gives you accidental-deletion recovery for free, and lets your customer-success team un-delete things without a database restore.

Make sure your application's default query path includes WHERE archived_at IS NULL. Index archived_at so the not-null check is fast. Periodically (monthly) do real DELETE cleanup of rows soft-deleted more than 90 days ago, in batches of 10,000, off-peak.

Pattern C: append-only event log alongside mutable state

A pattern increasingly common in 2026: keep your main mutable tables (orders, projects, users), and also keep an append-only events log that records every state transition. The events table is your audit trail, your replay-for-analytics source, and your debugging tool when a customer says "my project disappeared two weeks ago."

sql
CREATE TABLE events (
  id              BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
  organization_id BIGINT UNSIGNED NOT NULL,
  actor_user_id   BIGINT UNSIGNED NULL,
  entity_type     VARCHAR(64) NOT NULL,
  entity_id       BIGINT UNSIGNED NOT NULL,
  event_type      VARCHAR(64) NOT NULL,
  payload         JSON NULL,
  created_at      TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (id),
  KEY idx_events_org_entity (organization_id, entity_type, entity_id),
  KEY idx_events_org_created (organization_id, created_at)
) ENGINE=InnoDB;

This table grows fast. Partition by month at scale (PlanetScale supports MySQL partitioning) and archive to cold storage after a retention window. Worth every byte.

Pattern D: BIGINT UNSIGNED for every primary key

INT (signed) tops out at 2.1 billion. That sounds like a lot until you realize a busy event log eats 10 million rows a day. BIGINT UNSIGNED tops out at 18 quintillion. Use it from day one. The cost is four extra bytes per row, which is rounding error.

Pattern E: JSON columns for "might change" fields, real columns for "queried often" fields

A frequent founder mistake: putting everything in a metadata JSON field for flexibility. Vitess supports JSON columns, but indexing into them is awkward. Rule of thumb: if you ever filter by a field in a WHERE clause, promote it to a real column. JSON is for tags, settings, and data you only read.

When you promote a JSON key to a column, do it via a branch:

sql
ALTER TABLE projects ADD COLUMN priority TINYINT UNSIGNED NULL;

UPDATE projects
   SET priority = JSON_EXTRACT(metadata, '$.priority')
 WHERE JSON_EXTRACT(metadata, '$.priority') IS NOT NULL;

ALTER TABLE projects ADD INDEX idx_projects_priority (priority);

Test on a branch. Deploy via a deploy request. Online. Zero downtime.

7.95 PlanetScale's place in the broader 2026 founder stack

A managed database does not exist in isolation. Founders pick PlanetScale in the context of a broader stack, and the integration story matters as much as the database itself.

The Vercel + Next.js + PlanetScale + Prisma combo

This is the most common stack we see in 2026 for B2B SaaS in the $0-50k MRR range. The reason is integration: every component in the stack assumes serverless, every component handles the cold-start problem gracefully, and the deployment story is one git push away from production. The PlanetScale connection pooler is designed for this serverless world; the Prisma client handles the FK-less relation mode; the Vercel preview environments wire to PlanetScale branches via the action we wrote in section 4.

The annual cost of this stack for a founder team running on a free Vercel tier and PlanetScale Scaler Pro is about $470 ($39 x 12). That is cheap insurance against deployment-time database incidents.

The Cloudflare Workers + D1 / PlanetScale combo

Less common but growing. Cloudflare Workers offer aggressive edge deployment and per-request pricing that beats Vercel on dense, low-latency workloads. The catch: Workers prefer Cloudflare's own D1 (SQLite-based) for the storage layer. Connecting to PlanetScale from a Worker requires the connection pooler and adds a Hyperdrive layer in the middle.

If you are building for the edge specifically, Turso or D1 will likely beat PlanetScale on simplicity and latency. PlanetScale wins back if your data model is too complex for the SQLite story.

The Rails / Django / Laravel monolith + PlanetScale combo

Traditional web frameworks on PlanetScale work fine; you give up some of the branching workflow magic because the migration tooling in Rails (ActiveRecord migrations), Django (Django migrations), and Laravel (Eloquent migrations) does not natively talk to deploy requests. Workaround: generate the migration SQL, paste it into a PlanetScale branch, run the deploy request manually. Less elegant but works.

For Rails teams specifically, the ecosystem has settled on mysql2 with PlanetScale's connection-pooler URL. Avoid the legacy mysql gem. Make sure your Rails app is configured for prepared statements off (prepared_statements: false in database.yml) because PlanetScale's pooler does not play nicely with MySQL prepared statements.

The "no ORM, raw SQL" combo

A small but vocal subset of founders ship raw SQL via mysql2 / pg / node-postgres. PlanetScale supports this fine. The branching workflow gets more important here, not less, because you do not have an ORM catching schema mismatches at build time. The deploy-request diff becomes your safety net.

7.97 Common founder mistakes when adopting PlanetScale

Patterns that repeat across the PlanetScale customer base. If you are reading this guide before adopting, save yourself the learning.

Mistake 1: forgetting to set the usage caps. Covered in section 6. Do it before you launch.

Mistake 2: running prisma db push against the main branch. Treats your production schema as a dev sandbox. Always go through deploy requests for main. Save db push for dev branches only.

Mistake 3: creating dozens of long-lived branches. Branch sprawl is real. Enforce a max branch lifetime (5-7 days is healthy). Auto-delete via a scheduled job or a GitHub Action. Long-lived branches drift from main and become merge nightmares.

Mistake 4: assuming branching is free. Dev branches are zero-cost for prototyping but they do count against per-organization branch limits. Plan accordingly.

Mistake 5: skipping the Insights dashboard. PlanetScale will tell you your worst queries in plain English. Most founders never look. Check weekly. Fix the top three.

Mistake 6: connecting from a region far from your database. A US-East database hit from a Vercel function in Singapore adds 200ms per query. Choose your database region based on where your application servers run, not where you live.

Mistake 7: not enabling safe migrations on main. One stressed-out late-night session with an ALTER typo can break your weekend. The setting takes one command. Set it.

Mistake 8: ignoring connection pool sizing. Serverless functions can open thousands of connections during a traffic spike. Use the pooler URL and tune your Prisma connection_limit parameter. Default is too high for most setups.

Mistake 9: forgetting that deploy requests can be reverted. If a deploy goes sideways, you can revert it from the dashboard. Most founders panic and try to write the inverse migration manually. The platform supports clean rollback for at least a window after deploy. Use it.

Mistake 10: not documenting the exit playbook. Cover ourselves in section 7.7. Write the runbook now, while it is cheap. Future you will be grateful.

8. Pulling it all together: a 90-day plan for a bootstrapped founder

If you have read this far, here is the playbook.

Days 1-7. Create the PlanetScale account. Create the database. Wire it into your Vercel project. Push your first schema via a dev branch and a deploy request. Verify the workflow end-to-end. Cost: $0 (still on dev branches).

Days 7-30. Move to Scaler Pro the day you have your first paying customer or your first real production traffic. Set the usage caps. Enable safe migrations on main. Set up the branch-per-PR GitHub Action. First real bill: $39 plus single-digit usage.

Days 30-60. Ship features. Use deploy requests for every schema change. Cross-link your archived_at-style soft-delete columns with proper indexes. Use the Insights dashboard to catch slow queries. Bill: still $39-50.

Days 60-90. Review your three-month read/write trend. Run the worked-example math against Neon, Turso, and Supabase. If PlanetScale is still the right choice, double down: write the GitHub Action for branch-per-PR previews, document your exit runbook, set quarterly cost-review calendar. If one of the other three providers now looks materially better, plan the migration.

That is the realistic founder economics of PlanetScale in 2026. Not the marketing pitch. Not the YouTube tutorial. The actual ladder.

9. Forecasting your PlanetScale bill before you commit

The financial mistake that ends most founder PlanetScale stories is not the $39 base. It is the surprise usage line item three months in when traffic ramps. Here is how to forecast properly before you sign up.

Step 1: model your reads per user session

For each kind of user session in your application (anonymous visit, logged-in dashboard load, API call from an integration), count the SQL queries it issues and the rough row count each touches. A landing page visit might be one query reading 50 rows from a pages table. A logged-in dashboard might be twelve queries reading a few thousand rows total. An API call might be three queries reading a handful.

Multiply by sessions per user per day, then by users, then by 30. That gives monthly reads. For a typical B2B SaaS at 1,000 users averaging 5 dashboard sessions per day at 12 queries x 2,000 rows per session, you are at 360 million row-reads per month. PlanetScale Scaler Pro's included envelope covers this comfortably.

Step 2: model your writes per business event

Writes are where founders underestimate. Every signup is one write. Every form save is one to five writes. Every background-job processed event is one to ten writes. Every CSV import is potentially millions.

A 1,000-user B2B SaaS at 10 writes per active user per day generates 300,000 writes per month. The PlanetScale envelope handles this in a footnote. But add a daily CSV import job that processes 50,000 rows per customer and you are suddenly at 1.5 million writes per day, 45 million per month. That number you should pay attention to.

Step 3: model your storage

Take your average row size (rough estimate: 200-500 bytes for typical relational rows, more if you have JSON or TEXT columns) and multiply by total rows. A 10-million-row database with 400-byte average rows is 4 GB. Storage on Scaler Pro is included up to a per-plan envelope, and overage is billed per GB-month.

Do not forget indexes. Indexes can double or triple your storage footprint, especially if you have heavy composite indexes.

Step 4: plug into the PlanetScale pricing calculator

PlanetScale exposes a calculator on their pricing page. Plug in your three numbers (reads, writes, storage). The calculator gives you a monthly bill estimate.

Do this exercise twice: once for "current state" (today's traffic) and once for "six months from now if we hit our optimistic growth target." If the optimistic-future number is comfortable for your projected MRR at that scale, ship. If it scares you, look at one of the cheaper alternatives in section 5.

Step 5: set the cap at your forecast plus 50%

You did the math. You know what the bill should be. Set the usage cap in the PlanetScale dashboard at your forecast plus a 50% safety margin. This catches runaway code (an infinite-loop query, a bot accidentally hammering an endpoint) before it produces a bill you cannot pay.

Step 6: revisit the forecast every quarter

Reality drifts from forecasts. Every quarter, re-do the calculation with last-quarter's actual numbers. Update the cap. If you are consistently underutilizing, downgrade. If you are consistently bumping the cap, upgrade and recheck whether PlanetScale is still the right provider.

This six-step ritual is the difference between founders who love PlanetScale and founders who get burned. The platform itself is fine. The discipline is on you.

10. PlanetScale Insights: the dashboard most founders ignore

PlanetScale ships a feature called Insights that does query-level performance analysis automatically. It is one of the most under-used parts of the product. Most founders open it once during onboarding, find it interesting, then never look at it again. The teams that use it weekly are the teams that catch performance issues before they become billing issues.

Insights tells you four things that matter.

What it shows

Top queries by row-read count. Sorted descending. The query at the top of this list is your single biggest spend driver. If it is doing a full-table scan, fixing it might cut your bill by half.

Top queries by execution count. Queries that run thousands of times per minute. Even a tiny per-call inefficiency multiplies hard. Worth examining.

Slowest queries by p99 latency. Customer-facing slow queries. Users notice 500ms responses. Even if a query is not expensive, if it is slow, fix it.

Schema recommendations. Insights will sometimes recommend a specific index. The recommendations are usually right. Apply via a branch and a deploy request.

A real example workflow

Monday morning ritual. Open Insights. Sort by row-read count descending. Look at the top three.

If any of them is doing more than 100x the row reads you would naively expect, something is wrong. Common causes:

A WHERE user_id = ? on an unindexed column does a full scan. Add an index. Cut row-reads by 99%.

A JOIN between two large tables on an unindexed join column does a Cartesian-style scan. Add the index on the foreign join column. Cut row-reads by 99.9%.

An IN (?, ?, ?, ...) query with a long list does a sequential check for each value. Sometimes refactoring to a temp table plus join is faster, but more often you just need the right index.

A LIKE '%substring%' query (leading wildcard) cannot use a normal index. Either use full-text indexing (FULLTEXT in MySQL) or rethink the query.

A SELECT * on a wide table reads columns the application does not need. Use explicit column lists. Saves bandwidth, marginal row-read impact, helpful regardless.

Fix the top three issues each Monday. Re-run the dashboard the following Monday. Most founders find their bill drops 30-50% in the first month of doing this ritual.

Setting up alerts on top of Insights

Insights data is available via the PlanetScale API. You can wire it to Slack so that any new query showing up in the top-five row-read list triggers an alert. The wiring is straightforward: a daily cron job in GitHub Actions that hits the Insights API, diffs against yesterday, and posts to Slack if anything new appeared in the top five. About 50 lines of code total.

If you have one shared Slack channel for engineering, push the alert there. It becomes a daily nudge to look at the database. Founders who do this report catching problems weeks earlier than founders who do not.

11. Security, compliance, and the founder due-diligence story

For B2B founders selling to enterprise, "tell me about your database" is a question that comes up in security questionnaires by month six. PlanetScale's answers map cleanly to most enterprise security frameworks, but you should know what to say.

What PlanetScale provides out of the box

TLS-everywhere. All connections to PlanetScale require TLS. There is no unencrypted-in-transit option, which is itself a security feature; you cannot accidentally leak credentials over plaintext.

At-rest encryption. All data on disk is encrypted using AWS / Google Cloud / Microsoft Azure-managed keys (PlanetScale runs on cloud providers; the exact key custodian depends on your region). For most B2B customers this is sufficient. For regulated industries (HIPAA, PCI), confirm the specific compliance posture with PlanetScale sales.

Automatic backups. Point-in-time recovery is included on Scaler Pro. You can restore to any timestamp within the retention window. Test the restore once, document it, link it in your customer-facing security FAQ.

Audit logs. PlanetScale's audit logs capture admin actions on the database (who created which branch, who approved which deploy request, who changed billing settings). These are available via the API and dashboard. Forward them to your SIEM if you have one.

SOC 2 Type 2 certified. PlanetScale carries SOC 2 Type 2, which is the certification 80% of enterprise security questionnaires ask about. The report is available under NDA. Get it during your first enterprise sales cycle.

What you have to do yourself

Application-level access control. PlanetScale gives you a database with credentials. Your application is responsible for tenant isolation, row-level access, and user-permission checks. Build this into your data layer from day one.

Secrets management. Do not check the DATABASE_URL into git. Use Vercel's environment variables, AWS Secrets Manager, Doppler, or 1Password Connect. Rotate credentials at least annually.

Network isolation. By default PlanetScale's pooler is reachable from anywhere on the internet (with valid credentials). For higher-trust environments, configure IP allowlisting on the PlanetScale side. For paranoid environments, configure private connectivity (AWS PrivateLink or similar) — this is an Enterprise-tier feature.

Backup verification. PlanetScale backs you up. You should still periodically test that you can restore to a useful state. Once a quarter, run a restore drill. Document it. Add to your security questionnaire response library.

What to put in your customer-facing security FAQ

When an enterprise prospect asks about your database security posture, the honest one-paragraph answer is something like:

Our application data is stored in PlanetScale, a SOC 2 Type 2 certified managed database service. All connections use TLS 1.2 or higher. Data is encrypted at rest using cloud-provider-managed keys. We have configured point-in-time recovery with a 30-day retention window. Database access is restricted to our application's IP allowlist. Audit logs of all administrative actions are retained for one year. We perform restore drills quarterly.

That answers about 80% of security-questionnaire database questions. The remaining 20% are usually specific to the prospect's compliance framework; respond in good faith and refer them to PlanetScale's compliance documentation when needed.

12. Team workflow: how 3+ engineers should actually use PlanetScale

The branch-per-PR pattern works for a solo or two-person team out of the box. At three or more engineers, you need conventions or branch sprawl wins.

Naming conventions

Pick a branch naming scheme and enforce it. We recommend <owner>-<topic> where <owner> is the engineer's initials and <topic> is a short description. Example: mn-add-archived-at-projects. This makes the dashboard scannable.

Avoid generic names like dev, staging, test. They drift and stale.

Branch lifecycle

Hard rule: branches older than seven days get auto-deleted. Wire this into a daily GitHub Action that lists branches, finds ones older than 7 days, and deletes them. If a developer needs a long-lived branch (rare), they can re-create it.

The reason for the rule: stale branches drift from main. The drift compounds. When you finally try to merge, the deploy-request diff is unreadable because it includes weeks of main changes.

Deploy request review

Every deploy request needs human review before merge. At 3+ engineers, designate a "schema reviewer of the week" who is on call for SQL diffs. Make this a rotating role. Document what to look for: missing indexes, destructive changes, table-scan-inducing patterns, FK assumptions that no longer hold.

A schema reviewer's job is not to know everything; it is to ask the questions a fresh pair of eyes would ask. "Why are we adding this column? What queries will use it? Is the index correct? Did you test the rollback?"

Documentation

Every non-trivial schema change should leave a paper trail in the deploy-request description. Future engineers (and future you) will thank you. Format:

text
Why: <one-sentence rationale>
What: <what changes, what does not>
Risk: <what could go wrong>
Rollback: <how to undo>
Tested: <what scenarios you exercised>

This is five lines per deploy. Cheap. Compounds into institutional knowledge.

Tooling on top

Three pieces of tooling are worth building once your team passes 3-5 engineers:

Branch dashboard filter. A small CLI that lists "branches I own" rather than the firehose dashboard. Ten lines of shell wrapping pscale branch list | grep $USER.

Deploy request bot. A Slack bot that posts when a deploy request is opened, when it is approved, when it merges, and when it completes. Keeps the team in the loop without requiring everyone to watch the dashboard.

Migration helper. A wrapper script that takes an ORM-generated migration, extracts the SQL, opens a branch, applies the change, opens a deploy request, posts to Slack, and exits. About 80 lines of TypeScript. Removes 20 minutes of friction per schema change. Pays for itself in week one.

This is the operational shape of a healthy PlanetScale-on-a-team setup. It is not different in spirit from a healthy code-review culture; it just extends the review surface to include the database.

Frequently Asked Questions

Is PlanetScale still free for startups in 2026?

No. PlanetScale removed the Hobby free tier in March 2024. Dev branches remain free for prototyping and local development, but any production-traffic-serving database requires Scaler Pro at roughly $39/mo plus usage. The PlanetScale Startups program still offers credits to qualified early-stage companies (typically those raising or recently funded), but it is not the same as a perpetual free tier. Solo founders pre-revenue who need a true $0 production database should look at Neon, Turso, or Supabase.

What is database branching and why does it matter for a 2-person founding team?

Database branching is the ability to create an isolated copy of your database's schema (and optionally data) where you can make changes, test against them, and merge back into production without downtime. It matters most for small teams because it lets one cofounder ship a schema change while the other cofounder QAs the application change in a preview environment, without anyone needing to coordinate maintenance windows. The deploy-request workflow gives you a code-review surface for SQL the same way GitHub gives you code review for code.

How does PlanetScale's pricing compare to Neon and Turso for a side project?

For a pure side project with low traffic, Neon's $0 auto-suspend tier or Turso's $0 tier are both materially cheaper than PlanetScale's $39 entry. PlanetScale starts winning at the point where you need branching, online schema changes, and Vitess sharding in production. The break-even is roughly when your project has 100+ paying customers or 10k+ daily users. Below that, save the $39/mo. Above that, the workflow savings (avoided downtime, avoided rollbacks, avoided 3am pages) outpace the bill.

Can I use foreign keys with PlanetScale?

Not in the traditional MySQL sense. PlanetScale's Vitess underpinnings do not support classic FK constraints across shards. The recommended pattern is to enforce referential integrity in application code, typically through your ORM. Prisma supports this natively with relationMode = "prisma". If your data model fundamentally depends on DB-level FK enforcement (regulated industries, complex cascade behavior), pick a single-instance Postgres provider or a CockroachDB-style distributed SQL system instead.

What happens if I exceed my plan limits on PlanetScale?

If you set a hard usage cap in your billing settings (which you should), PlanetScale will throttle or pause your database when you hit the cap and notify you. If you have not set a cap, PlanetScale will simply continue serving traffic and bill you for the overage. This is the source of most "surprise bill" horror stories. Set the cap before you launch. Adjust upward deliberately when you scale.

How long does an online schema migration actually take on PlanetScale?

For most founder-stage tables (under 10 million rows), schema changes via deploy requests complete in seconds to a few minutes. For tables with hundreds of millions to billions of rows, online migrations can take hours, but your application continues serving reads and writes throughout. The migration is run in the background by the Vitess online DDL engine; you do not block traffic. The deploy-request UI shows progress in real time.

Can I migrate off PlanetScale later if my needs change?

Yes, and this is one of PlanetScale's quieter advantages. Because PlanetScale exposes a standard MySQL surface, migrating away is a mysqldump and restore into RDS MySQL, Aurora MySQL, or self-hosted MySQL. Your application code does not change; only your connection string. The migration takes hours of work, not weeks. Practice the runbook once on a staging branch, document it, and you have a documented exit path you can show to investors during due diligence.

Should I learn PlanetScale before I have product-market fit?

No. Pre-PMF, your job is to ship features and find customers; your database choice should be the cheapest tool that lets you do that. Use Neon's free tier or a local SQLite file. Adopt PlanetScale the week you have either (a) paying customers whose data you must not lose, or (b) a cofounder who needs to review your schema changes through pull requests. Anything earlier is premature optimization.


External references

Read the full PlanetScale for Entrepreneurs review

PlanetScale for Entrepreneurs Use Cases FAQ

Common questions about applying PlanetScale for Entrepreneurs to real workflows

No. PlanetScale removed the Hobby free tier in March 2024. Dev branches remain free for prototyping, but any production-traffic-serving database requires Scaler Pro at roughly $39/mo plus usage. The PlanetScale Startups program offers credits to qualified early-stage companies, but it is not the same as a perpetual free tier. Pre-revenue solo founders who need a true $0 production database should look at Neon, Turso, or Supabase.
Database branching is the ability to create an isolated copy of your database's schema where you make changes, test against them, and merge back into production without downtime. For a 2-person team it matters most because it lets one cofounder ship a schema change while the other QAs the app change in a preview environment, with no maintenance window required. The deploy-request workflow gives you a code-review surface for SQL the same way GitHub gives you code review for code.
For low-traffic side projects, Neon's $0 auto-suspend tier or Turso's $0 tier are materially cheaper than PlanetScale's $39 entry. PlanetScale starts winning when you need branching, online schema changes, and Vitess sharding in production. Rough break-even is when your project has 100+ paying customers or 10k+ daily users. Below that, save the $39. Above that, the workflow savings (avoided downtime, avoided rollbacks, avoided 3am pages) outpace the bill.
Not in the traditional MySQL sense. PlanetScale's Vitess underpinnings do not support classic FK constraints across shards. The recommended pattern is to enforce referential integrity in application code, typically through your ORM. Prisma supports this natively with relationMode = 'prisma'. If your data model fundamentally depends on DB-level FK enforcement (regulated industries, complex cascade behavior), pick a single-instance Postgres provider or a CockroachDB-style distributed SQL system instead.
If you set a hard usage cap in your billing settings (which you should), PlanetScale throttles or pauses your database when you hit the cap and notifies you. If you have not set a cap, PlanetScale continues serving traffic and bills you for the overage. This is the source of most surprise-bill horror stories. Set the cap before you launch. Adjust upward deliberately when you scale.
For most founder-stage tables (under 10 million rows), schema changes via deploy requests complete in seconds to a few minutes. For tables with hundreds of millions to billions of rows, online migrations can take hours, but your application continues serving reads and writes throughout. The migration is run in the background by the Vitess online DDL engine; you do not block traffic. The deploy-request UI shows progress in real time.
Yes, and this is one of PlanetScale's quieter advantages. Because PlanetScale exposes a standard MySQL surface, migrating away is a mysqldump and restore into RDS MySQL, Aurora MySQL, or self-hosted MySQL. Your application code does not change; only your connection string. The migration takes hours of work, not weeks. Practice the runbook once on a staging branch, document it, and you have a documented exit path to show investors during due diligence.
No. Pre-PMF, your job is to ship features and find customers; your database choice should be the cheapest tool that lets you do that. Use Neon's free tier or a local SQLite file. Adopt PlanetScale the week you have either paying customers whose data you must not lose, or a cofounder who needs to review your schema changes through pull requests. Anything earlier is premature optimization.