Site packages: the migration story that doesn’t suck

Host hopping shouldn’t require a consultant

Most CMS “migrations” are archaeology: database dumps, upload folders, half-broken URLs, and a prayer that plugins survive the flight.

Forma’s bet is simpler: the site is a package.

What’s in the zip

From Settings → Backup (or GET /api/v1/export/site with backup:read):

Piece | Why it’s there
manifest.json | format=formax-site, format_version, schema_version, app_version
data.json | Portable content snapshot (pages, posts, settings, redirects…)
database/forma.db | The live SQLite file
uploads/ | Every binary the site actually uses

That’s the whole product surface that matters for this site. Not the PHP app tree — the content + media + settings.

Two exports, two jobs

Site package (/export/site) — binaries included. Use this to move hosts or clone staging.

Versioned JSON (/export) — no binaries. Handy for diffs, audits, and agent-readable snapshots.

Import is the reverse: Admin → Backup → Import, or POST /api/v1/import/site with multipart field package.

Schema version is the forward gear

schema_version exists so future Forma releases can migrate older packages instead of rejecting them cold. Packages newer than the running app get rejected on purpose — you upgrade the app first, then import.

That’s how you avoid the WordPress trap of “restore succeeded, site broken.”

A migration that feels like shipping a box

Export package from production (or ask an agent to).

Drop a clean Forma instance on the new host.

Import the zip (replace DB; merge or replace uploads as needed).

Point DNS. Flush cache. Check /sitemap.xml and a couple of pages.

No plugin compatibility matrix. No “which MySQL version.” One file database, one uploads tree, one manifest.

Agents and backups

Give a trusted agent backup:read and it can pull a package before a risky rewrite. Give settings:write and it can import into staging. That’s not magic — it’s treating backup/restore as API surface instead of a ritual you only remember after the outage.

What packages are not

A site package is not an app update. It won’t replace admin/, lib/, or api/. Content moves in the zip; Forma the product moves with git releases / deploy. Keep those stories separate and both stay honest.

Portability isn’t a slogan if you can’t put the whole site in one artifact. Now you can.