## Summary
Logic-function bundles produced by the SDK CLI were ~1.2 MB each (source
maps ~3.1 MB) because esbuild was inlining `twenty-sdk/define` and its
transitive dependencies (zod + locales, twenty-shared, etc.). Those
`define*` factories are pure build-time metadata used only by the
manifest extractor — the Lambda runtime only ever invokes
`default.config.handler`, so the factories are dead weight at runtime.
This PR shrinks the bundles to ~9.5 KB each (~99% reduction) without
changing runtime behaviour.
## What changes
- **Stub `twenty-sdk/define` at user-app build time.** New esbuild
plugin
(`packages/twenty-sdk/src/cli/utilities/build/common/plugins/stub-twenty-sdk-define.plugin.ts`)
intercepts every import of `twenty-sdk/define` during user-app builds
and replaces it with a tiny virtual module:
- Factory functions (`defineLogicFunction`,
`definePostInstallLogicFunction`, …) become `(config) => ({ success:
true, config, errors: [] })`.
- Enums and helpers become `Proxy`-based no-ops.
- Wired into both the one-shot build (`build-application.ts`) and the
watcher (`esbuild-watcher.ts`), for logic functions and front
components.
- **New runtime barrel `twenty-sdk/logic-function`.** Re-exports only
the types logic-function authors need (`InstallPayload`, `RoutePayload`,
`CronPayload`, `DatabaseEventPayload`, `LogicFunctionConfig`,
`InputJsonSchema`, …). Compiled `.mjs` is 36 bytes. Wired into Vite,
Rollup `.d.ts` bundling, `package.json#exports`, and `typesVersions`.
- **Lint enforcement.** Added an oxlint `no-restricted-imports` rule
that forbids `twenty-shared` / `twenty-shared/*` imports from
`**/*.logic-function.ts` and `**/logic-functions/**/*.ts`, with a help
message pointing at the new barrel. Applied to the `create-twenty-app`
template and to `github-connector`, `hello-world`, `postcard`.
- **Migrated existing sources.** All logic-function files across
`community/{github-connector, apollo-enrich}`, `examples/{hello-world,
postcard}`, and `internal/{twenty-for-twenty, self-hosting, exa}` now
import types from `twenty-sdk/logic-function` instead of
`twenty-sdk/define` or `twenty-shared/*`. Renamed leftover
`InstallLogicFunctionPayload` references to `InstallPayload`.
## Why this is safe
- `define*` exports from `twenty-sdk/define` are metadata factories
whose call expressions are statically inspected by the manifest
extractor (`manifest-extract-config.ts`). They're never evaluated at
runtime — the Lambda executor only walks `default.config.handler`
(`logic-function-drivers/constants/executor/index.mjs`).
- The stub keeps the same call shape (`{ success, config, errors }`), so
any logic-function module that re-exports
`defineX(config).config.handler` still resolves to the user's handler at
runtime.
- Front-component bundles are unaffected by the stub because the
pre-existing JSX transform plugin
(`jsx-transform-to-remote-dom-worker-format-plugin.ts`) unwraps
`defineFrontComponent(...)` earlier in the pipeline. That's intentional
— front-component bloat is React/Preact, not in scope here.
## Measurements (github-connector)
| Asset | Before | After |
|---|---|---|
| `*.logic-function.mjs` | ~1.2 MB | ~9.5 KB |
| `*.logic-function.mjs.map` | ~3.1 MB | ~22 KB |
The official scaffolding CLI for building apps on top of Twenty CRM. Sets up a ready-to-run project with twenty-sdk.
Quick start
npx create-twenty-app@latest my-twenty-app
cd my-twenty-app
yarn twenty dev
The scaffolder will:
- Create a new project with TypeScript, linting, tests, and a preconfigured
twentyCLI - Optionally start a local Twenty server (Docker)
- Open the browser for OAuth authentication
Options
| Flag | Description |
|---|---|
--example <name> |
Initialize from an example |
--name <name> |
Set the app name (skips the prompt) |
--display-name <displayName> |
Set the display name (skips the prompt) |
--description <description> |
Set the description (skips the prompt) |
--skip-local-instance |
Skip the local server setup prompt |
By default (no flags), a minimal app is generated with core files and an integration test. Use --example to start from a richer example:
npx create-twenty-app@latest my-twenty-app --example hello-world
Examples are sourced from twentyhq/twenty/packages/twenty-apps/examples.
Documentation
Full documentation is available at docs.twenty.com/developers/extend/apps:
- Getting Started — step-by-step setup, project structure, server management, CI
- Building Apps — entity definitions, API clients, testing
- Publishing — deploy, npm publish, marketplace
Troubleshooting
- Server not starting: check Docker is running (
docker info), then tryyarn twenty server logs. - Auth not working: make sure you are logged in to Twenty in the browser, then run
yarn twenty remote add. - Types not generated: ensure
yarn twenty devis running — it auto-generates the typed client.