Migrating a WordPress SQL database to Supabase is one of those tasks where the obvious approach is the wrong one. Copying the raw WordPress MySQL tables into Supabase gives you an unusable copy of WordPress’s internals, not clean data. WordPress spreads your content across wp_posts (mixed with revisions and autosaves), serializes metadata as PHP in wp_postmeta, and links everything indirectly. The right move is to extract the content, reshape it into purpose-built Supabase tables, and load that, keeping the slugs so URLs map. WPBuildAI extracts the content, designs the Supabase schema, and produces the redirect list, so the data migrates clean.

Target the right major version from the start: Supabase recorded self-hosted instances upgrading from Postgres 15 to 17 as a breaking change on 18 May 2026, so a dump shaped for the older image is worth re-checking against 17 before you rely on it as your migration path.

Why a direct dump fails

The WordPress schema is built for WordPress, not for a modern application, so a straight dump moves the wrong shape. Content sits in wp_posts alongside every revision and autosave, so a dump duplicates each post many times over. Metadata is serialized PHP in wp_postmeta, an encoded blob a normal SQL query cannot read as columns. Relationships run through join tables and indirect references rather than clean foreign keys. The 2024 Web Almanac reflects how much of a WordPress site is this runtime-oriented structure rather than stored, queryable content. Load it as-is and you have replicated the tangle in a new database, not migrated the data, and your AI-built front end still cannot query it cleanly because the structure assumes WordPress is interpreting it.

What the WordPress schema actually looks like

Knowing the shape explains the fix. wp_posts holds posts, pages, attachments, revisions, autosaves, and menu items all in one table, distinguished by a post_type column, so “your content” is a subset mixed in with system rows. wp_postmeta holds arbitrary key-value metadata, much of it serialized PHP arrays, keyed back to posts by id. Taxonomies, your categories and tags, live across wp_terms, wp_term_taxonomy, and wp_term_relationships, three tables to express “this post is in this category.” None of this is wrong for WordPress; it is flexible and plugin-friendly. But it is the opposite of the lean, purpose-built schema a modern app wants, which is why the migration is a reshape, not a copy: you are translating from WordPress’s general-purpose structure into tables designed for your specific site.

Reshape around your app

Design the Supabase schema for your new app, then map the content into it during extraction:

  • A posts or pages table keyed by slug, with title, body, excerpt, date, author, and clean meta columns.
  • A media table and a categories table, with real foreign-key relationships.
  • Dropped revisions, autosaves, and orphaned meta that the app does not need.

Keep the slug so URLs map cleanly to the new site. This is the database-level version of the content export in exporting WordPress data for Supabase, and the same care that protects content in rebuilding without losing data. Designing the target schema first, then shaping the extraction to fill it, is what turns the migration from a tangle into a direct, queryable load.

A worked example: 500 posts extracted

Picture a blog whose WordPress database has 500 published posts but 8,000 rows in wp_posts, the rest being revisions, autosaves, attachments, and menu items. A naive dump carries all 8,000 plus a wp_postmeta table full of serialized blobs. The clean migration instead queries for post_type = ‘post’ and status = ‘published’, pulls the 500 real posts, unpacks the meta fields it needs (SEO title, description) from the serialized data, resolves each post’s categories through the three taxonomy tables into a simple list, and writes the result into a Supabase posts table keyed by slug plus a categories table. Revisions and autosaves are dropped. The outcome is 500 clean, queryable rows instead of 8,000 tangled ones, each carrying its slug and original URL so the redirect map follows directly. The reshape is the whole job; the load is trivial once the shape is right.

Designing the Supabase schema

The target schema should reflect how your front end queries content, not how WordPress stored it. A typical design: a posts table with id, slug, title, body (clean HTML or Markdown), excerpt, published_at, author, and a few meta columns like meta_description; a categories table with id, name, and slug; a join table linking posts to categories with proper foreign keys; and a media table listing images with their URLs and alt text. The front end then reads a post by slug in one query and its categories in another, simple, fast, and clear. This is the payoff of reshaping: where WordPress needed several tables and serialized blobs to answer “show me this post and its categories,” your schema answers it with clean joins, which is both faster to query and far easier to maintain than a transplanted WordPress structure.

What to drop

Part of a clean migration is deciding what not to bring, because much of a WordPress database is operational noise your app does not need. Drop revisions and autosaves, which can outnumber real posts many times over. Drop orphaned metadata left by removed plugins, transient and cache rows, and spam or trashed comments. Drop menu and widget structures, which you will rebuild natively in the new front end. The goal is to carry only the content and the metadata your app actually uses, leaving WordPress’s housekeeping behind. Being deliberate about this is what keeps the new database lean; a migration that copies everything “to be safe” just recreates the bloat you were trying to escape. The reshape is as much about pruning as about translating.

Keeping slugs for URL mapping

The slug is the thread that connects the database migration to the SEO step, so preserve it deliberately. If your Supabase posts table is keyed by, or at least stores, the original WordPress slug, the new site can render each post at a URL that matches or maps cleanly to the old one, which makes the redirects mechanical: old URL to new URL is often the same slug under a new path. Lose the slug during extraction, or let the new system generate fresh ones, and every redirect becomes a manual match. So carry the slug through as a first-class column, not an afterthought. This small discipline is what lets the redirect map below be derived directly from the migrated data rather than reconstructed separately, tying the clean database and the preserved rankings together.

The redirect job is separate

A clean database does not, by itself, protect rankings; that is a separate job that must also be done. Old URLs still need 301s to their new homes, because rankings attach to URLs, not to rows in a table. Ahrefs found in its search traffic study that a small set of pages drives most traffic, so include every URL in the extraction and redirect it per Google’s site move guidance and redirects guidance, verifying the high-traffic ones first. Because you kept the slug, building the map is a direct derivation from the migrated data. The catalogue version of this database move is in importing WooCommerce inventory with Supabase, and the full site move in converting to an AI website. The clean load and the redirect map are two requirements, and both are needed for the move to keep its traffic.

Common mistakes migrating the database

The recurring errors all come from copying instead of reshaping. Dumping the raw MySQL tables into Supabase recreates WordPress’s tangle of revisions and serialized meta in a database that cannot query it cleanly. Leaving metadata serialized makes it unreadable as columns. Carrying revisions and autosaves bloats the new database. Flattening the taxonomy tables wrong loses category relationships. Dropping the slug forces every redirect to be matched by hand. And treating the clean load as the finish line skips the 301s and loses the rankings. Each is avoided by the same approach: design the target schema first, extract and reshape the real content into it, unpack serialized meta, drop the housekeeping rows, keep slugs, and build the redirect map from the same data, which is what makes the migration both clean and ranking-safe.

Key points to remember

Migrate a WordPress SQL database to Supabase by extracting and reshaping the content, never by dumping the raw MySQL tables, because WordPress spreads content across wp_posts, wp_postmeta, and three taxonomy tables, with metadata serialized and revisions duplicating every post. Design the Supabase schema around your app, a posts table keyed by slug, clean category and media tables, real relationships, then map the real content into it, unpacking serialized meta and dropping revisions, autosaves, and orphaned rows. Keep slugs so URL mapping is mechanical, and remember the clean load is only half the job: 301 every old URL so rankings hold. WPBuildAI extracts the content into Supabase and builds the redirect map together, so the data migrates clean and the rebuilt site keeps its rankings; send your site URL for a fixed quote.

Not affiliated with Supabase, WordPress, or Lovable.