To export WordPress data for a Supabase backend, you reshape your content into clean CSV or JSON that maps to Supabase tables, rather than trying to load the raw WordPress XML. The export is one row per item, with the body as clean HTML or Markdown, plus the title, slug, date, author, categories, image URLs, and metadata. The slug and the URL matter as much as the body, because they are what you redirect. WPBuildAI crawls the site, cleans the content, and produces the structured CSV or JSON that imports straight into Supabase, along with the URL list for redirects.
Check which Postgres you are landing on before shaping the CSV, because Supabase logged self-hosted instances moving from Postgres 15 to 17 as a breaking change on 18 May 2026, and column types that imported cleanly under the old image do not always behave the same way under the new one.
Why the XML will not load
The mismatch is between shapes. Supabase wants tabular data that maps to columns, rows with named fields it can load into a table. WordPress XML is the opposite: a nested backup format full of serialized fields, custom post types, taxonomies, and shortcodes, designed to move between WordPress installs where another WordPress decodes it. Its importer cannot turn that into rows, because the structure assumes a WordPress on the other end. The 2024 Web Almanac shows how much shortcode and theme markup a typical WordPress post carries, all of which has to be stripped before the content maps into clean table rows. So the first step is always a conversion to a flat schema, not a direct load; the XML is the wrong shape, not the wrong data, and reshaping it is the whole task.
What “clean” data means for Supabase
Clean, here, has a specific meaning: content reduced to the fields your tables need, with WordPress-specific cruft removed. The body should be clean HTML or Markdown, with shortcodes resolved into real content or stripped, and theme wrappers gone. Serialized metadata should be unpacked into plain columns. Each item should carry only the fields you will actually store and query, title, body, excerpt, date, author, categories, image references, slug, and URL, rather than the full bag of WordPress internals. The test is whether each piece of data maps cleanly to a column: if it does, it belongs in the export; if it is WordPress bookkeeping, it does not. Producing genuinely clean data is what turns the import from a fight into a direct load, and it is the same clean-content discipline that underlies feeding any modern tool from WordPress.
Designing the export to match the tables
The export is easiest when it mirrors your Supabase schema, so design both together:
- A posts or pages table keyed by slug, with title, body, excerpt, date, author, and meta columns.
- Related tables for categories and media, linked by id.
- The original URL carried through on every row, so redirects are possible.
Keep the slug intact so URLs map cleanly to the new site. Done this way, each CSV column lines up with a table column and the import is a direct load rather than a reshape after the fact. Designing the schema first and shaping the export to fit it, rather than exporting whatever WordPress gives and trying to model around it, is what keeps the whole process clean. The related approaches are in importing WooCommerce inventory with Supabase and migrating the SQL database to Supabase.
A worked example: a blog into a posts table
Picture a 400-post blog moving to a Supabase-backed site. The schema is a posts table keyed by slug, with columns for title, body (Markdown), excerpt, published date, author, and meta description, plus a categories table and a post-categories link table. The export produces one CSV row per post, each carrying its slug and original URL, with the body converted from WordPress’s shortcode-laced HTML to clean Markdown. A second CSV holds the categories, and a third the relationships. These load directly into the matching tables, and the AI front end renders each post by querying the posts table on slug. Because every row kept its original URL, the redirect map is built straight from the export. What made it a direct load rather than a struggle was designing the three tables first and shaping the CSVs to match, so nothing needed reshaping after import.
Keeping slugs for URL mapping
The single most important field to preserve, after the body, is the slug, because it is the bridge between the old URLs and the new ones. If the posts table is keyed by the original slug, the new site can render each post at a URL that matches or maps cleanly to the old one, which makes the redirects trivial: old URL to new URL is often just the same slug under a new structure. Lose the slug, or let the new system generate fresh ones, and every redirect becomes a manual match instead of a mechanical mapping. So carry the slug through the export deliberately and use it as the key, not an afterthought column. This small discipline is what connects the database move to the SEO step, turning the redirect map from a research project into a direct derivation from the data you already exported.
Handling shortcodes, media, and serialized fields
Three kinds of WordPress data need deliberate handling, because they do not map cleanly on their own. Shortcodes, the bracketed tags that WordPress expands at render time, mean nothing outside WordPress, so they must be resolved into real content or removed before export; left in, they appear as literal text in your Supabase content. Media references point into the WordPress library, so the export must list image URLs and the migration must re-host them, or they break when WordPress is retired. Serialized metadata, PHP-encoded fields, has to be unpacked into plain values before it fits a column. These three are where a naive export goes wrong, leaving shortcodes as noise, images hotlinked, and metadata unreadable. Handling each explicitly is the difference between content that loads clean and content that arrives full of WordPress residue, which is why a deliberate conversion beats a raw export every time.
The SEO half: redirects
The database move handles the content; the rankings need their own step, and the two are separate jobs. Ahrefs found in its search traffic study that a small share of pages drives most traffic, so include every URL in the export and 301 each one per Google’s site move guidance and redirects guidance. Because you carried the slug and original URL through the export, building the redirect map is a direct derivation: each row already holds its old URL, and the new URL follows from the slug. A clean Supabase load with no redirects still loses the rankings, so the redirect map is not optional polish, it is half the migration. The content loading cleanly into the database and the old URLs resolving to the new pages are two requirements, and an export designed with both in mind, content fields plus the URL column, satisfies them together.
Headless as the alternative
If reshaping and moving the data feels like more than you want, there is an alternative worth weighing: keep WordPress as the backend and pull its content through the REST API into the new front end, the approach in connecting to the WordPress REST API. That avoids the export-to-Supabase step entirely, at the cost of continuing to run WordPress as a content store. So the choice is between fully moving the data into Supabase, leaner, one system, but a real migration, and keeping WordPress headless, no data move, but two systems to maintain. Neither is wrong; they trade migration effort now against ongoing maintenance later. For teams that want to leave WordPress behind entirely, the Supabase export is the path; for those attached to the WordPress editor, headless may fit better, which is the same fork covered across the AI-builder bridge.
Common mistakes exporting to a structured backend
The recurring errors all come from treating the export as a dump rather than a reshape. Trying to load the raw WordPress XML into Supabase fails because it is the wrong shape. Exporting the body with shortcodes and theme markup intact fills your tables with noise. Dropping the slug forces every redirect to be matched by hand. Forgetting the URL column makes the redirect map impossible to derive. Leaving images referenced on the old WordPress domain breaks them when it is retired. And treating the clean database load as the finish line skips the 301s and loses the rankings. Each is avoided by designing the schema first, shaping a clean export to match it with slugs and URLs included, handling shortcodes and media deliberately, and building the redirect map from the same data, the full process behind converting to an AI website.
Key points to remember
Export WordPress data for Supabase by reshaping it into clean CSV or JSON that mirrors your tables, one row per item with the body as clean Markdown plus slug, metadata, image references, and the original URL, because raw WordPress XML is the wrong shape and will not load. Design the schema first, resolve shortcodes, unpack serialized fields, and re-host media so the content arrives clean. Keep the slug as the key so URL mapping is mechanical, and carry every URL so the redirect map derives straight from the export, since the database load is only half the job and the 301s are the other half. WPBuildAI produces the Supabase-ready export and the redirect map together, so the content loads cleanly and the rebuild keeps its rankings; send your site URL for a fixed quote.
Not affiliated with Supabase, WordPress, or Lovable.