Files
twenty/packages/twenty-sdk
martmull 11b2990dd6 fix(twenty-sdk): stop dev-mode OOM by caching compiled manifest modules (#22435)
## Context

Closes twentyhq/core-team-issues#2601

`twenty dev` crashed with a Node.js heap OOM (`FATAL ERROR: Reached heap
limit — JavaScript heap out of memory`) after a while of editing.

## Root cause

`loadModule()` in `manifest-extract-config-from-file.ts` compiled every
manifest-defining file with **`vm.compileFunction`** on every manifest
rebuild. V8 pins every function compiled through the `vm` module and
never releases it
([nodejs/node#35375](https://github.com/nodejs/node/issues/35375)).

In the dev loop this is on the hottest path and heavily amplified:
- `runSyncPipeline` → `buildManifest` re-globs **all** `.ts/.tsx` files
and recompiles every entity file on **every** sync — not just the edited
one.
- A single save triggers 2+ full rebuilds (the manifest watcher change →
`scheduleSync`, then the esbuild watcher's `handleFileBuilt` →
`scheduleSync` again).
- Each compiled unit is the full esbuild bundle — hundreds of KB, up to
MBs for front components (React/JSX inlined).

So over an hour of editing, thousands of `vm.compileFunction` calls ×
large source, all permanently retained → multi-GB heap → crash. This
matches the reported profile exactly.

Investigation ruled out (with evidence): chokidar watchers (disposed on
restart), ts-morph/`createProgram` (dead code, not in the dev loop —
typecheck runs in child `tsc` processes), the event log (hard-capped at
200), Ink timers/subscriptions (all cleaned up), and graphql-sse (only
used by `logs`).

## Change

Keep only the **latest build per file**, keyed by file path. Each cache
entry stores the file's last bundled-output hash and its compiled
wrapper:
- Rebuild with **unchanged** output → reuse the existing wrapper (no
recompile).
- Output **changed** → overwrite the entry, so the file's previous build
is dropped instead of accumulating.

This bounds the cache to one entry per file rather than one per rebuild,
so old builds no longer pile up in the heap. The wrapper is still
executed fresh into a new module shim on every call, so extraction
behavior is unchanged.

One file changed:
`packages/twenty-sdk/src/cli/utilities/build/manifest/manifest-extract-config-from-file.ts`.

## Test

- Behavior of `extractManifestFromFile` is unchanged (fresh execution
per call); only redundant recompilation is eliminated and stale builds
are dropped.
- Note: `yarn install` could not complete in the authoring sandbox (a
git-based transitive dep of `twenty-desktop` is blocked by the proxy),
so lint/typecheck/tests were not run locally — relying on CI.

## Follow-ups (not in this PR)

- Redundant **double-sync per save**
(`start-watchers-orchestrator-step.ts`) triggers two full rebuilds per
edit.
- Latent **event-log display bug**: new events stop appearing once the
200-event cap is reached.
2026-07-02 15:12:54 +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