## Summary - Adds a `color` column to `ObjectMetadataEntity` with full GraphQL support so object icon colors are persisted at the metadata level - Adds a `type` column to `NavigationMenuItemEntity` (enum: `OBJECT`, `VIEW`, `FOLDER`, `LINK`, `RECORD`) replacing field-based type inference - Updates frontend to read object colors from `objectMetadata.color` (falling back to standard defaults) in the sidebar nav, record index header, and record show breadcrumb - Simplifies `NavigationMenuItemIcon` color resolution via `getEffectiveNavigationMenuItemColor` util ## Color rules | Item type | Color source | Editable in sidebar? | |-----------|-------------|---------------------| | **Object** | `objectMetadata.color` | Yes — persisted to `objectMetadata.color` on Save | | **Folder** | `navigationMenuItem.color` | Yes | | **Link** | Fixed default (`DEFAULT_NAVIGATION_MENU_ITEM_COLOR_LINK`) | No | | **View** | `objectMetadata.color` (from the parent object) | No | | **Record** | None | No | - **Object** items represent the whole object (e.g. "Companies") and point to the INDEX view. Changing their color updates `objectMetadata.color` via `useSaveObjectMetadataColorsFromDraft`. - **View** items represent specific non-INDEX views. Their color comes from the parent object's metadata (read-only). - Only **folders** store their color on `navigationMenuItem.color` — enforced by `hasNavigationMenuItemOwnColor` util. - `getEffectiveNavigationMenuItemColor` returns `objectColor` for both OBJECT and VIEW items, folder's own color for folders, and the fixed default for links. ## NavigationMenuItemType enum - Shared enum created in `twenty-shared` with values: `OBJECT`, `VIEW`, `FOLDER`, `LINK`, `RECORD` - Registered as a GraphQL enum on the backend - Replaces string literals across entity, DTOs, input, converters, and frontend hooks - Migration backfills existing rows: INDEX views → `OBJECT`, non-INDEX views → `VIEW`, based on join with the view table ## Design decisions - **OBJECT vs VIEW distinction**: Items pointing to INDEX views are typed as `OBJECT` (represent the whole object, color editable). Items pointing to non-INDEX views are typed as `VIEW` (specific view, color read-only from parent object). - **Dual color storage**: `navigationMenuItem.color` is preserved for folders only. Objects use `objectMetadata.color` as their source of truth. - **Type discriminator**: The `type` column replaces field-based inference (checking `viewId`, `link`, `targetRecordId` presence) with an explicit enum, simplifying `isNavigationMenuItemLink` / `isNavigationMenuItemFolder` to simple `item.type ===` checks. - **No settings page color picker**: Object color editing is done from the sidebar edit panel, not the data model settings page. ## Test plan - [ ] Verify objects display their default standard colors in the sidebar - [ ] Verify object color editing works in the sidebar edit panel (persists to objectMetadata.color) - [ ] Verify folder color editing works in the sidebar edit panel - [ ] Verify views, links, and records do NOT show a color picker in the sidebar edit panel - [ ] Run `npx nx typecheck twenty-front` and `npx nx typecheck twenty-server` - [ ] Verify the database migrations add `color` to `objectMetadata` and `type` to `navigationMenuItem` Made with [Cursor](https://cursor.com)
Create Twenty App is the official scaffolding CLI for building apps on top of Twenty CRM. It sets up a ready‑to‑run project that works seamlessly with the twenty-sdk.
- Zero‑config project bootstrap
- Preconfigured scripts for auth, dev mode (watch & sync), uninstall, and function management
- Strong TypeScript support and typed client generation
Documentation
See Twenty application documentation https://docs.twenty.com/developers/extend/capabilities/apps
Prerequisites
- Node.js 24+ (recommended) and Yarn 4
- A Twenty workspace and an API key (create one at https://app.twenty.com/settings/api-webhooks)
Quick start
npx create-twenty-app@latest my-twenty-app
cd my-twenty-app
# Get help and list all available commands
yarn twenty help
# Authenticate using your API key (you'll be prompted)
yarn twenty auth:login
# Add a new entity to your application (guided)
yarn twenty entity:add
# Start dev mode: watches, builds, and syncs local changes to your workspace
# (also auto-generates typed CoreApiClient — MetadataApiClient ships pre-built with the SDK — both available via `twenty-sdk/clients`)
yarn twenty app:dev
# Watch your application's function logs
yarn twenty function:logs
# Execute a function with a JSON payload
yarn twenty function:execute -n my-function -p '{"key": "value"}'
# Execute the pre-install function
yarn twenty function:execute --preInstall
# Execute the post-install function
yarn twenty function:execute --postInstall
# Build the app for distribution
yarn twenty app:build
# Publish the app to npm or directly to a Twenty server
yarn twenty app:publish
# Uninstall the application from the current workspace
yarn twenty app:uninstall
Scaffolding modes
Control which example files are included when creating a new app:
| Flag | Behavior |
|---|---|
-e, --exhaustive |
(default) Creates all example files |
-m, --minimal |
Creates only core files (application-config.ts and default-role.ts) |
# Default: all examples included
npx create-twenty-app@latest my-app
# Minimal: only core files
npx create-twenty-app@latest my-app -m
What gets scaffolded
Core files (always created):
application-config.ts— Application metadata configurationroles/default-role.ts— Default role for logic functionslogic-functions/pre-install.ts— Pre-install logic function (runs before app installation)logic-functions/post-install.ts— Post-install logic function (runs after app installation)- TypeScript configuration, Oxlint, package.json, .gitignore
- A prewired
twentyscript that delegates to thetwentyCLI from twenty-sdk
Example files (controlled by scaffolding mode):
objects/example-object.ts— Example custom object with a text fieldfields/example-field.ts— Example standalone field extending the example objectlogic-functions/hello-world.ts— Example logic function with HTTP triggerfront-components/hello-world.tsx— Example front componentviews/example-view.ts— Example saved view for the example objectnavigation-menu-items/example-navigation-menu-item.ts— Example sidebar navigation linkskills/example-skill.ts— Example AI agent skill definition__tests__/app-install.integration-test.ts— Integration test that builds, installs, and verifies the app (includesvitest.config.ts,tsconfig.spec.json, and a setup file)
Next steps
- Run
yarn twenty helpto see all available commands. - Use
yarn twenty auth:loginto authenticate with your Twenty workspace. - Explore the generated project and add your first entity with
yarn twenty entity:add(logic functions, front components, objects, roles, views, navigation menu items, skills). - Use
yarn twenty app:devwhile you iterate — it watches, builds, and syncs changes to your workspace in real time. CoreApiClient(for workspace data via/graphql) is auto-generated byyarn twenty app:dev.MetadataApiClient(for workspace configuration and file uploads via/metadata) ships pre-built with the SDK. Both are available viaimport { CoreApiClient, MetadataApiClient } from 'twenty-sdk/clients'.
Build and publish your application
Once your app is ready, build and publish it using the CLI:
# Build the app (output goes to .twenty/output/)
yarn twenty app:build
# Build and create a tarball (.tgz) for distribution
yarn twenty app:build --tarball
# Publish to npm (requires npm login)
yarn twenty app:publish
# Publish with a dist-tag (e.g. beta, next)
yarn twenty app:publish --tag beta
# Publish directly to a Twenty server (builds, uploads, and installs in one step)
yarn twenty app:publish --server https://app.twenty.com
Publish to the Twenty marketplace
You can also contribute your application to the curated marketplace:
git clone https://github.com/twentyhq/twenty.git
cd twenty
git checkout -b feature/my-awesome-app
- Copy your app folder into
twenty/packages/twenty-apps. - Commit your changes and open a pull request on https://github.com/twentyhq/twenty
Our team reviews contributions for quality, security, and reusability before merging.
Troubleshooting
- Auth prompts not appearing: run
yarn twenty auth:loginagain and verify the API key permissions. - Types not generated: ensure
yarn twenty app:devis running — it auto‑generates the typed client.