Export & import
Export/import is how a questionnaire moves between environments — staging to production, one deployment to another, or just into version control.
Exporting
Section titled “Exporting”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.)
Importing
Section titled “Importing”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.