# Summary
- Introduces a new, flexible folder structure for Twenty SDK
applications using file suffix-based entity detection
- Adds defineApp, defineFunction, defineObject, and defineRole helper
functions with built-in validation
- Refactors manifest loading to use jiti runtime evaluation for
TypeScript config files
- Separates validation logic into dedicated module with comprehensive
error reporting
# New Application Folder Structure
Applications now use a convention-over-configuration approach where
entities are detected by their file suffix, allowing flexible
organization within the src/app/ folder.
# Required Structure
my-app/
├── package.json
├── yarn.lock
└── src/
├── app/
│ └── application.config.ts # Required - main application configuration
└── utils/ # Optional - handler implementations & utilities
# Entity Detection by File Suffix
- *.object.ts - Custom object definitions
- *.function.ts - Serverless function definitions
- *.role.ts - Role definitions
# Supported Folder Organizations
## Traditional (by type):
src/app/
├── application.config.ts
├── objects/
│ └── postCard.object.ts
├── functions/
│ └── createPostCard.function.ts
└── roles/
└── admin.role.ts
## Feature-based:
src/app/
├── application.config.ts
└── post-card/
├── postCard.object.ts
├── createPostCard.function.ts
└── postCardAdmin.role.ts
## Flat:
src/app/
├── application.config.ts
├── postCard.object.ts
├── createPostCard.function.ts
└── admin.role.ts
# New Helper Functions
## defineApp(config)
import { defineApp } from 'twenty-sdk';
export default defineApp({
universalIdentifier: '4ec0391d-...',
displayName: 'My App',
description: 'App description',
icon: 'IconWorld',
});
## defineObject(config)
import { defineObject, FieldType } from 'twenty-sdk';
export default defineObject({
universalIdentifier: '54b589ca-...',
nameSingular: 'postCard',
namePlural: 'postCards',
labelSingular: 'Post Card',
labelPlural: 'Post Cards',
icon: 'IconMail',
fields: [
{
universalIdentifier: '58a0a314-...',
type: FieldType.TEXT,
name: 'content',
label: 'Content',
},
],
});
## defineFunction(config)
import { defineFunction } from 'twenty-sdk';
import { myHandler } from '../utils/my-handler';
export default defineFunction({
universalIdentifier: 'e56d363b-...',
name: 'My Function',
handler: myHandler,
triggers: [
{
universalIdentifier: 'c9f84c8d-...',
type: 'route',
path: '/my-route',
httpMethod: 'POST',
},
],
});
## defineRole(config)
import { defineRole, PermissionFlag } from 'twenty-sdk';
export default defineRole({
universalIdentifier: 'b648f87b-...',
label: 'App User',
objectPermissions: [
{
objectNameSingular: 'postCard',
canReadObjectRecords: true,
},
],
permissionFlags: [PermissionFlag.UPLOAD_FILE],
});
# Test plan
- Verify npx twenty app sync works with new folder structure
- Verify npx twenty app dev works with new folder structure
- Verify validation errors display correctly for invalid configs
- Verify all three folder organization styles work (traditional,
feature-based, flat)
- Run existing E2E tests to ensure backward compatibility
A CLI and SDK to develop, build, and publish applications that extend Twenty CRM.
- Type‑safe client and workspace entity typings
- Built‑in CLI for auth, generate, dev sync, one‑off sync, and uninstall
- Works great with the scaffolder: create-twenty-app
Prerequisites
- Node.js 24+ (recommended) and Yarn 4
- A Twenty workspace and an API key. Generate one at https://app.twenty.com/settings/api-webhooks
Installation
npm install twenty-sdk
# or
yarn add twenty-sdk
Usage
Usage: twenty [options] [command]
CLI for Twenty application development
Options:
--workspace <name> Use a specific workspace configuration (default: "default")
-V, --version output the version number
-h, --help display help for command
Commands:
auth Authentication commands
app Application development commands
help [command] display help for command
Global Options
--workspace <name>: Use a specific workspace configuration profile. Defaults todefault. See Configuration for details.
Commands
Auth
Authenticate the CLI against your Twenty workspace.
-
twenty auth login— Authenticate with Twenty.- Options:
--api-key <key>: API key for authentication.--api-url <url>: Twenty API URL (defaults to your current profile's value orhttp://localhost:3000).
- Behavior: Prompts for any missing values, persists them to the active workspace profile, and validates the credentials.
- Options:
-
twenty auth logout— Remove authentication credentials for the active workspace profile. -
twenty auth status— Print the current authentication status (API URL, masked API key, validity).
Examples:
# Login interactively (recommended)
twenty auth login
# Provide values in flags
twenty auth login --api-key $TWENTY_API_KEY --api-url https://api.twenty.com
# Login interactively for a specific workspace profile
twenty auth login --workspace my-custom-workspace
# Check status
twenty auth status
# Logout current profile
twenty auth logout
App
Application development commands.
-
twenty app sync [appPath]— One-time sync of the application to your Twenty workspace. -
Behavior: Compute your application's manifest and send it to your workspace to sync your application
-
twenty app dev [appPath]— Watch and sync local application changes.- Options:
-d, --debounce <ms>: Debounce delay in milliseconds (default:1000).
- Behavior: Performs an initial sync, then watches the directory for changes and re-syncs after debounced edits. Press Ctrl+C to stop.
- Options:
-
twenty app uninstall [appPath]— Uninstall the application from the current workspace.- Note:
twenty app deleteexists as a hidden alias for backward compatibility.
- Note:
-
twenty app add [entityType]— Add a new entity to your application.- Arguments:
entityType: one offunctionorobject. If omitted, an interactive prompt is shown.
- Options:
--path <path>: The path where the entity file should be created (relative to the current directory).
- Behavior:
object: prompts for singular/plural names and labels, then creates a new object definition file.function: prompts for a name and scaffolds a serverless function file.
- Arguments:
-
twenty app generate [appPath]— Generate the typed Twenty client for your application. -
twenty app logs [appPath]— Stream application function logs.- Options:
-u, --functionUniversalIdentifier <id>: Only show logs for a specific function universal ID.-n, --functionName <name>: Only show logs for a specific function name.
- Options:
Examples:
# Start dev mode with default debounce
twenty app dev
# Start dev mode with custom workspace profile
twenty app dev --workspace my-custom-workspace
# Dev mode with custom debounce
twenty app dev --debounce 1500
# One-time sync of the current directory
twenty app sync
# Add a new object interactively
twenty app add
# Generate client types
twenty app generate
# Watch all function logs
twenty app logs
# Watch logs for a specific function by name
twenty app logs -n my-function
Configuration
The CLI stores configuration per user in a JSON file:
- Location:
~/.twenty/config.json - Structure: Profiles keyed by workspace name. The active profile is selected with
--workspace <name>.
Example configuration file:
{
"profiles": {
"default": {
"apiUrl": "http://localhost:3000",
"apiKey": "<your-api-key>"
},
"prod": {
"apiUrl": "https://api.twenty.com",
"apiKey": "<your-api-key>"
}
}
}
Notes:
- If a profile is missing,
apiUrldefaults tohttp://localhost:3000until set. twenty auth loginwrites theapiUrlandapiKeyfor the default profile.twenty auth login --workspace custom-workspacewrites theapiUrlandapiKeyfor a customcustom-workspaceprofile.
Troubleshooting
- Auth errors: run
twenty auth loginagain and ensure the API key has the required permissions. - Typings out of date: run
twenty app generateto refresh the client and types. - Not seeing changes in dev: make sure dev mode is running (
twenty app dev).