Overview
Apps are now organized by folder convention undersrc/app/ (see App structure). Apps created before this layout register their entry points in a central app.ts file. That still works, but it is deprecated, and the CLI can convert an existing app automatically:
- a dirty git working tree
- files that fail to parse
- registrations that cannot be resolved statically, or duplicate ids
- entry points imported via namespace imports or star re-exports
- a settings
Pagethat is wrapped, computed, or declared insideapp.tsitself - destination files that already exist
What it migrates
- Extensions. Every entry point registered in
app.ts(all seven surfaces) moves tosrc/app/extensions/<id>/extension.tsx, each default-exporting adefineExtensioncall. Files that imported a moved entry point are rewritten to match. - Workspace settings.
src/app.settings.tsand the registered workspacePagemove tosrc/app/settings/schema.tsandsrc/app/settings/page.tsxas one unit, and the settings calls inside the page are rewritten to the schema-boundSettingsAPIs. Legacy settings calls outside the settings page are left unchanged and listed in the plan. Update those toSettings.getSettings/Settings.setSettingsby hand. - Events and webhooks.
src/events/**andsrc/webhooks/**move tosrc/app/events/**andsrc/app/webhooks/**, preserving handler names and fixing relative imports. - Workflow blocks.
src/blocks/**moves tosrc/app/blocks/**, preserving block folders as they are. - Cleanup.
app.tsis deleted only when nothing meaningful remains in it after the migration; otherwise it stays.
.server.ts files can live anywhere in src/).
Migration steps
1
Update the attio package
Make sure you’re on the latest CLI:
2
Start from a clean git tree
The command refuses to run with uncommitted changes, so the migration is always one clean,
revertable commit. Commit or stash your work first.
3
Preview the plan
4
Apply the migration
--yes to
skip the prompt.5
Review and commit
Review the diff, check that
attio build (or your dev server) is happy, and commit. If
anything went wrong during apply, all changes are rolled back automatically; the tree is
never left half-migrated.Migrating by hand
You don’t have to use the command: the legacy and folder-based conventions can coexist while you move entry points over one at a time (if the same extension id exists in both, the folder-based one wins). The exception is settings: defining settings both ways is a build error, so settings must move in one step. See Using a legacy app.ts.Handing the migration to an AI agent
If the migrator refuses your app and the blockers aren’t practical to fix, or you can’t run the command at all, the migration is mechanical enough to hand to a coding agent. The prompt below encodes the same moves and safety rules the migrator follows. Paste it as-is, then review the diff as you would any migration.Copyable migration prompt
Copyable migration prompt
Flags
--json cannot host an interactive prompt, so a --json invocation without --yes prints the plan and writes nothing.
Running bare
attio migrate opens a picker listing the available migrations;
folder-structure is one of them.