Files
twenty/packages/twenty-sdk
Weiko 1a475d0edd feat(twenty-sdk): terraform-style plan/apply for app metadata sync (#22372)
## What & why

Syncing a Twenty app's metadata is destructive (removing a field/object
drops the backing column/table), but the only preview was `dev --once
--dry-run`, which collapsed every change into one line per entity — no
before/after, no color, no destructive warning, and no confirmation
before a real sync.

This introduces a `terraform plan`-style flow. The server's
`syncApplication(manifest, dryRun)` already returns a complete
`SyncAction[]` (create/update/delete with per-attribute
`before`/`after`), so this is a CLI-only change — **no server changes**.

## Command surface

`plan` previews, `apply` applies; `dev` is the watch wrapper over the
same engine.

| Command | Behavior |
| --- | --- |
| `twenty plan [appPath]` | Render the full plan, read-only |
| `twenty apply [appPath]` | Plan → confirm on destructive → apply |
| `twenty dev --once` | **Deprecated** alias of `twenty apply` (still
works, warns) |
| `twenty dev --once --dry-run` | **Deprecated** alias of `twenty plan`
(still works, warns) |
| `twenty dev` (watch) | Compact summary; inline `[y/N]` confirm on
destructive saves |
| `-f, --force` | Skip the destructive gate (on `apply` and `dev`) |

## Plan output

```
Twenty will perform the following actions:

  # objectMetadata "rocket" will be created
  + nameSingular  = "rocket"
  + labelSingular = "Rocket"

  # fieldMetadata "name" will be updated in-place
  ~ label      = "Name" -> "Launch name"
  ~ isNullable = true -> false

  # fieldMetadata "legacyCode" will be destroyed
  - name  = "legacyCode"

Plan: 1 to add, 1 to change, 1 to destroy.

Warning: 1 destructive change(s) will permanently delete data.
  - fieldMetadata "legacyCode" — drops the column and its data
Destroys are irreversible. Review carefully before applying.
```

Grouped by metadata type, ordered create → update → destroy, `=` aligned
per block. Internal keys (`id`, `workspaceId`, `*Id`, timestamps, nulls)
are filtered; updates show only changed keys via the server `diff`.

## Destructive safety gate

The server applies the manifest diff atomically, so every apply path
computes the plan read-only first, then decides whether to apply:

- **`twenty apply` / `dev --once`** — interactive `y/N` prompt when the
plan deletes metadata; `--force` skips; **fails closed** (exit 1) in CI
/ non-TTY.
- **`dev` (watch)** — creates/updates auto-apply with the compact
summary; a save that deletes metadata shows an inline `y/N` prompt in
the Ink UI. **Declining cleanly stops the watch** (exit 1) rather than
leaving the session in a nagging/blocked state — since the atomic apply
would otherwise also block the additive changes on every subsequent save
until resolved. `dev --force` applies deletions without asking.

## Notes

- `twenty apply` / `dev --once` now do one extra **read-only** dry-run
before applying (to compute the plan + gate). `--force` skips it.
- The watch sync step now skips API-client regeneration on any
non-synced outcome (error or decline), avoiding a partial client write
during shutdown.
- The Ink watch UI keeps its existing compact summary; the full plan
renders only on the plain-console surfaces — `dev` watch output is
unchanged in the common case.

## Test plan

- `npx nx typecheck twenty-sdk` ✓
- `npx nx lint twenty-sdk` ✓
- Unit tests (vitest): renderer (`format-sync-actions-plan.spec.ts`) +
confirm gate (`confirm-destructive-apply.spec.ts`); existing summary /
sync-step specs still green.
- Manual against `simple-app` + a local server: `plan`, `apply`
(destructive prompt + `--force` + non-TTY fail-closed), and the `dev`
watch inline confirm (incl. decline → stop).
2026-07-01 14:26:28 +02:00
..
2026-03-09 15:32:13 +00:00

Twenty logo

Twenty SDK

NPM version License Join the community on Discord

A CLI and SDK to develop, build, and publish applications that extend Twenty CRM.

Quick start

The recommended way to start is with create-twenty-app:

npx create-twenty-app@latest my-twenty-app
cd my-twenty-app
yarn twenty dev

Documentation

Full documentation is available at docs.twenty.com/developers/extend/apps:

  • Getting Started — scaffolding, local server, authentication, dev mode
  • Building Apps — entity definitions, API clients, testing, CLI reference
  • Publishing — deploy, npm publish, marketplace

Guides in this repository:

Manual installation

If you are adding twenty-sdk to an existing project instead of using create-twenty-app:

yarn add twenty-sdk twenty-client-sdk

Then add a twenty script to your package.json:

{
  "scripts": {
    "twenty": "twenty"
  }
}

Run yarn twenty help to see all available commands.

Configuration

The CLI stores credentials per remote in ~/.twenty/config.json. Run yarn twenty remote:add to configure a remote, or yarn twenty remote:list to see existing ones.

Troubleshooting

  • Auth errors: run yarn twenty remote:add to re-authenticate.
  • Typings out of date: restart yarn twenty dev to refresh the client and types.
  • Not seeing changes in dev: make sure dev mode is running (yarn twenty dev).

Contributing

Development setup

git clone https://github.com/twentyhq/twenty.git
cd twenty
yarn install

Development mode

npx nx run twenty-sdk:dev

Production build

npx nx run twenty-sdk:build

Running the CLI locally

npx nx run twenty-sdk:start -- <command>

Resources