PlanetScale Vitess vs Xata for Serverless Postgres: Branching, Free Tiers, and Real Query Costs
You've got a side project or a new production service to build, and you need a serverless database that won't charge you $200 a month before you have a single paying user. You've narrowed it down to PlanetScale and Xata. Both promise zero-ops scaling, both have free tiers, and both have strong DX stories β but underneath the marketing they work very differently, and picking the wrong one will cost you time during migrations and money after launch.
This review covers what you actually need to know before committing: how branching works in practice, where the free tiers break down, and how query costs scale once real traffic hits.
- How PlanetScale's Vitess-backed branching model differs from Xata's Postgres-native approach
- What the free tiers actually include, and the exact limits that matter
- How each platform bills for reads, writes, and storage at scale
- Which workflow fits solo developers vs. small teams
- The gotchas that reviewers usually skip
What Each Platform Actually Is
PlanetScale is a managed MySQL database built on top of Vitess, the same sharding layer that YouTube uses internally. It's MySQL-compatible, not Postgres. That distinction matters if your stack is already Postgres-oriented or if you depend on specific Postgres extensions. PlanetScale's headline feature is its Git-style branching model for schema changes, which it built directly into the Vitess workflow.
Xata is a newer entrant that offers a Postgres-compatible serverless database with branching, a built-in search index (backed by Elasticsearch), and a structured record API. It runs on real Postgres under the hood, so you can connect any Postgres client, use pg in Node.js, or point SQLAlchemy at it without adapter gymnastics.
Database Branching: The Core Differentiator
Both platforms sell branching as a first-class feature, but they implement it in fundamentally different ways.
PlanetScale's deploy request workflow
In PlanetScale, every database has a production branch and you create development branches off it. A development branch is a full copy of the schema (not the data). You run your migrations on the dev branch, then open a deploy request β think of it as a pull request for your schema. PlanetScale analyzes the diff and applies the change to production online, using Vitess's internal online schema change tooling to avoid locking tables.
This is genuinely excellent for teams. Schema changes that would cause a 30-second lock on a busy table are applied non-destructively, and you can revert them within a short window after deploy. The catch: because Vitess handles the actual migration, foreign key constraints are not supported by default. PlanetScale has been slowly relaxing this restriction in newer plans, but it's still a real limitation if your existing schema relies on FK enforcement at the database level.
Xata's branch model
Xata branches copy both schema and a configurable subset of data. Each branch gets its own connection string, so your staging environment can have real (anonymized) data for testing without touching production. Migrations in Xata are schema-aware: you describe the target state and Xata generates the migration path.
Because Xata runs real Postgres, it does support foreign keys. However, the branching workflow is less opinionated than PlanetScale's. There's no built-in equivalent of a deploy request gate. You're responsible for coordinating who merges what and when, which is less friction for solo developers but more risky for multi-developer teams.
Free Tier Comparison
Free tier limits change frequently, so treat these as directional rather than exact. Verify current limits on each platform's pricing page before making a decision.
| Feature | PlanetScale Hobby | Xata Free |
|---|---|---|
| Storage | 5 GB | 15 GB |
| Row reads / month | 1 billion | 75 million (approx) |
| Row writes / month | 10 million | 15 million (approx) |
| Branches | 1 production + 1 dev | Up to ~5 branches |
| Connections | 1,000 | Pooled via PgBouncer |
| Postgres compatible | No (MySQL/Vitess) | Yes |
| Built-in search | No | Yes (Elasticsearch-backed) |
PlanetScale's free tier is more generous on reads by a significant margin, which matters for read-heavy public apps. Xata's free tier gives you more storage and more branches, which matters more during active development. If you're building something where users query a lot of records but rarely write, PlanetScale's billion-read allowance is hard to beat.
Both platforms sleep inactive free-tier databases, though the behavior differs. PlanetScale has historically kept databases alive longer; Xata free-tier branches may pause after a period of inactivity. Check current sleep policies before deploying anything user-facing on a free tier.
Real Query Costs at Scale
Once you exceed the free tier, pricing gets more nuanced. PlanetScale bills on a row reads and row writes model. Xata also uses a read/write unit model but adds charges for search requests separately.
PlanetScale's Scaler Pro pricing
PlanetScale's paid plans (Scaler and Scaler Pro) are structured around allocated resources rather than pure consumption. You pick a cluster size with a defined read/write capacity, and you pay a flat monthly rate for that. This means you won't get a surprise bill if a single query accidentally scans a large table β you're capped at your plan's limits. The trade-off is that you pay for capacity even when you're not using it.
For teams running production workloads, this predictability is worth something. A startup that knows its traffic envelope in advance can size a PlanetScale plan and budget accurately. An experimental project with unpredictable spikes is less well-served by a fixed-resource model.
Xata's consumption model
Xata charges per unit of read and write operations beyond the free tier. The per-unit cost is low, but consumption pricing means your bill can grow proportionally with usage. If your app runs a poorly-optimized query that scans a large table on every page load, you'll see it in your bill at the end of the month. This is the standard serverless database tradeoff β you pay only for what you use, but what you use is entirely in your hands.
Xata also bills for search separately. If you're using the built-in Elasticsearch-backed search, those requests count independently. For apps that need full-text search without running a separate service, having it baked in is convenient. If you're not using search at all, it doesn't cost you anything.
Connection Handling and Serverless Compatibility
Both platforms are designed with serverless runtimes in mind, but they solve the connection problem differently.
PlanetScale ships a driver called @planetscale/database that works over HTTP rather than the MySQL binary protocol. This means you can use it from edge runtimes like Cloudflare Workers or Vercel Edge Functions where TCP connections are not available. The trade-off is that you're using a custom driver rather than the standard mysql2 library, so some ORMs need a compatibility shim.
Xata provides a Postgres-compatible endpoint with PgBouncer-style connection pooling. Standard Postgres clients work out of the box. For Vercel and similar serverless environments where each function invocation creates a new connection, pooling handles the connection burst cleanly. You can also use Xata's own TypeScript SDK if you prefer a structured record API over raw SQL.
Schema Migrations in Practice
This is where the two platforms diverge most sharply for working developers.
With PlanetScale, your typical migration flow looks like this:
# Create a development branch
pscale branch create my-database add-user-preferences
# Connect to the branch and run your migration
pscale connect my-database add-user-preferences --port 3309
# Apply migration via your ORM or migration tool
npx prisma migrate dev
# Open a deploy request to merge to production
pscale deploy-request create my-database add-user-preferencesThe deploy request goes through PlanetScale's dashboard or CLI. You review the schema diff, check for blocking warnings (like a foreign key that Vitess can't handle), and then apply. PlanetScale runs the online schema change in the background. Your production app keeps running without downtime.
With Xata, migrations are more SQL-native. You write a migration file and apply it against a branch:
# Create a branch
xata branch create staging
# Switch your connection string to the branch and apply migrations
prisma migrate dev --schema=./prisma/schema.prisma
# When ready, apply the same migration against production
xata branch merge staging mainBecause it's real Postgres, tools like prisma migrate, flyway, or raw psql work without modification. The workflow is less opinionated but also more familiar to anyone who's done Postgres migrations before.
Common Pitfalls to Watch For
PlanetScale: No foreign keys (on most plans). If your application relies on FK constraints for data integrity, you'll either need to enforce those constraints at the application layer or upgrade to a plan that supports them. Many developers discover this late in a migration from an existing relational schema.
PlanetScale: It's MySQL, not Postgres. SQL dialects differ in subtle ways. Functions available in Postgres (like gen_random_uuid(), window function nuances, or RETURNING in INSERT statements) may not be available or behave identically in MySQL/Vitess. If you're porting an existing Postgres-based project, plan for time to audit your queries.
Xata: Search index storage costs. Xata maintains a search index alongside your Postgres tables. This roughly doubles the storage footprint of your data. On the free tier that's absorbed, but on paid plans it affects your storage bill. If you don't need full-text search, it's worth checking whether you can disable the search index for certain tables.
Xata: Fewer connection options at the edge. Xata's Postgres endpoint requires TCP, which means it doesn't work in Cloudflare Workers or other strict edge runtimes. For Vercel or AWS Lambda, this is not a problem. For edge-first architectures, PlanetScale's HTTP driver gives you more deployment options.
Both platforms: Free tier sleep behavior. Neither platform is suitable for production user-facing traffic on the free tier if your database may go to sleep. Build a small warm-up path or upgrade to a paid plan before you launch publicly.
Which One Should You Pick?
The honest answer depends on your stack and your team.
Pick PlanetScale if: you're building on a MySQL-compatible stack, your team makes frequent schema changes and needs a gated deployment workflow, you're running a read-heavy public application where the billion-row-read free tier matters, or you need edge runtime compatibility via the HTTP driver.
Pick Xata if: you're already on Postgres and want to stay there, you need foreign key enforcement at the database level, you want built-in full-text search without running Elasticsearch yourself, or you prefer a more flexible (less opinionated) branching model for solo or small-team development.
Wrapping Up
Both platforms are solid choices for serverless development, and both have matured significantly. The key is matching the tool to your actual constraints rather than picking based on buzz.
Here are the concrete next steps:
- Verify current free tier limits directly on each platform's pricing page β these numbers change and what's published today may differ from what you read six months ago.
- If you're migrating an existing schema, run it through PlanetScale's lint tools or Xata's migration preview to catch FK issues and dialect differences before you're deep in the project.
- Prototype your most complex query on each platform's free tier. Actual query latency from your deployment region matters more than theoretical throughput numbers.
- For teams, evaluate the deploy-request workflow in PlanetScale against your current PR process β it adds a step but it also adds a safety gate that junior developers will thank you for.
- If you need edge runtime support (Cloudflare Workers, Deno Deploy), PlanetScale's HTTP driver is currently the cleaner path. Test your ORM compatibility before committing.
π€ Share this article
Sign in to saveRelated Articles
Affiliate Reviews
Grafana Cloud vs Datadog for Metrics: Free Tier Limits, Retention, and Real Costs
3m read
Affiliate Reviews
Tigris vs Cloudflare R2: Global Object Storage Tested for Latency, Pricing, and S3 API Coverage
9m read
Affiliate Reviews
Axiom vs Datadog for Log Management: Ingestion, Retention, and DX Compared
7m read
Comments (0)
No comments yet. Be the first!