Skip to content

Export & import

Export/import is how a questionnaire moves between environments — staging to production, one deployment to another, or just into version control.

Export in a questionnaire’s row menu (on the list page) downloads a JSON file:

{
"formsEngineExport": 1,
"exportedAt": "2026-08-16T12:00:00Z",
"name": "Onboarding Intake",
"definition": { "schemaVersion": 2, "steps": ["…"], "tabs": [], "questions": [] }
}

What travels: the draft definition and the name. What deliberately doesn’t: the public id, allowed origins, submission policy, responses, and version history — those belong to a deployment, not to the questionnaire’s content. (Exporting the draft rather than the live version means you can move work-in-progress; publish on the source first if you want the live content.)

Import on the list page’s toolbar takes such a file and creates a new questionnaire — it never overwrites an existing one and never auto-publishes:

  • a fresh public id is minted (the source’s id is never reused, so two environments can’t collide);
  • allowed origins start empty and the submission policy at its default — configure them for the new environment;
  • the definition lands as an unpublished draft, so the questionnaire isn’t live until you publish it;
  • a name collision gets suffixed: importing “Onboarding Intake” where one exists creates “Onboarding Intake (imported)”.

Imports are validated at full publish strictness before anything is created — a file with a dangling rule reference or an invalid configuration is rejected with the complete list of problems, and nothing half-imported is left behind. Files from a different export-format version, or with a definition schema this backend doesn’t support, are rejected with an explicit version-mismatch message.

The seed script in the tool repo (examples/seed/seed.mjs) is exactly this import endpoint plus a publish call — the same format works for scripting environment setup.