Dev.to WebDev 🛠 Dev 👁 0 📖 5 min read

Database Schema Design for a SaaS MVP in 2026

You've sketched your SaaS idea on a whiteboard — users, accounts, billing, some core feature. Now you need a database schema. The temptation is to over-design: normalize everything to 5NF, plan for millions of users, add

You've sketched your SaaS idea on a whiteboard — users, accounts, billing, some core feature. Now you need a database schema. The temptation is to over-design: normalize everything to 5NF, plan for millions of users, add every index you can think of. The reality is that 80% of schema decisions made in week one get rewritten by month six as product direction shifts.

This framework isn't about academic database design principles. It's about making the minimum set of structural decisions that won't block your development velocity or require painful migrations later.

Quick Answer

Start with a single Postgres database, a users table (using UUIDs, not auto-increment IDs), an accounts/organizations table if you have multi-tenant users, and a subscriptions table that references your payment provider's IDs. Use JSONB columns for flexible attribute storage (pricing plans, user preferences, feature flags) — you can normalize them into proper tables once the data model stabilizes. Skip composite indexes until you have query EXPLAIN output to justify them.

Why This Matters in 2026

Three trends make schema design decisions particularly impactful this year:

  • AI-generated code — The next generation of development tools (Cursor, Aider, Copilot) produce better code when your schema is self-documenting. Clear table and column names with correct types reduce hallucinations in AI-generated queries.
  • Serverless database adoption — Your 2026 schema needs to work with Neons scale-to-zero or Planetscales branching workflow. Complex relational designs with heavy trigger usage and custom data types may not port cleanly to serverless databases. Pricing visibility — Every query you write has a measurable API cost on serverless databases. A schema that requires 5 JOINs for a simple dashboard view costs more than one that surfaces the same data in 2-3 JOINs.

Common Schema Mistakes Solo Founders Make

Mistake 1: Auto-Increment IDs Everywhere

Auto-increment integers are fine for internal joins but break in distributed databases, expose record count to users, and create migration pain when you move from Postgres to a serverless alternative. Use UUID v7 (time-sorted UUIDs that support indexing) for all primary keys. The 16-byte storage cost is negligible at startup scale and saves migration pain later.

Mistake 2: Premature Normalization

Splitting user settings into 5 tables (notification_preferences, display_preferences, privacy_settings...) before you know which settings you actually need creates pain for every feature iteration. Use JSONB columns for flexible settings, then normalize once the schema stabilizes after 3-6 months of real usage data.

Mistake 3: No Audit Columns

Every table should have created_at, updated_at, and optionally deleted_at. These columns save hours of debugging — "when did this record change?" is the most common question you can't answer if you didn't track timestamps.

Minimum Viable Schema Template

Core Tables for Any SaaS

Table Key Columns Purpose
users id (UUID v7), email, name, auth_provider_id, avatar_url, created_at, updated_at Authentication and user identity
accounts id (UUID v7), name, slug, billing_email, plan_tier, created_at, updated_at Multi-tenant account/org structure
account_members account_id, user_id, role (enum: admin/member/viewer), joined_at User-to-account membership
subscriptions id, account_id, provider (Stripe/LemonSqueezy), provider_subscription_id, status, current_period_start, current_period_end Billing subscription tracking
feature_flags account_id, flag_name (varchar), enabled (boolean), metadata (JSONB) Per-account feature rollout

``

Optional but Recommended

Table Key Columns Purpose
audit_logs id, actor_id, action (varchar), target_type, target_id, changes (JSONB), created_at Track all state-changing operations for debugging and compliance
api_keys id, account_id, key_hash (not plaintext), name, scopes (JSONB), expires_at, created_at API access for integrations and programmatic usage
webhook_endpoints id, account_id, url, secret, enabled_events (text[]), created_at Webhook delivery configuration

``

Indexing Strategy (Start Minimal)

  • Always create: Primary key index (auto), unique index on users.email, composite index on account_members(account_id, user_id), index on subscriptions.account_id
  • Add when needed: Composite indexes for specific queries you've profiled. Use EXPLAIN ANALYZE on slow queries before adding indexes — premature indexing adds write overhead without query benefit. Avoid: Indexes on boolean columns, indexes on JSONB paths until confirmed in EXPLAIN output, and covering indexes until you have actual query performance data.

Migration Strategy

Use additive migrations whenever possible. Adding a column or table is reversible. Dropping or renaming a column requires coordination. Rules:

  • Always add columns as nullable first, backfill data, then add NOT NULL constraint.
  • Never rename columns — add the new column, dual-write for one release cycle, then drop the old column. Use Drizzle Kit or Prisma Migrate for auto-generated migration SQL, but always review the SQL before applying in production.

Limitations of This Framework

  • Not for time-series data — If your app tracks events, metrics, or logs at high volume (>100K events/day), consider a time-series database (TimescaleDB, InfluxDB) or a dedicated log service. Postgres can handle 100K rows/table but query performance degrades without careful partitioning.
  • Not for full-text search-heavy apps — Postgres full-text search works for basic search, but if your app's primary feature is search across millions of documents, you need Meilisearch, Typesense, or Elasticsearch alongside Postgres.
  • Not for real-time collaboration — If your app requires live multi-user editing (like Notion or Figma), the schema needs CRDT-aware data structures. This framework assumes a conventional request-response data model. UUID performance — UUID v7 is better than v4 for index performance but still slightly slower than integer IDs on inserts (~5-10% overhead tested on Postgres 17). For most indie SaaS apps, this is negligible.

The Bottom Line

Your MVP schema should be minimal, additive, and self-documenting. Use UUIDs, JSONB for flexible attributes, and additive migrations. Don't design for scale you don't have — design for developer speed and easy refactoring. A schema that takes two hours to design and gets rewritten in month three is cheaper than a schema that takes two days to design and locks you into choices that don't fit your actual product.

Related Articles

Related reading on PikVue:

Originally published at pikvue.com — independent 2026 reviews and comparisons of developer tools, AI products, and SaaS platforms.

📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.