src/objects/post-card.object.ts
Key points
- The
universalIdentifiermust be unique and stable across deployments. - Each field requires a
name,type,label, and its own stableuniversalIdentifier. - The
fieldsarray is optional — you can define objects without custom fields. openRecordInsets where records of this object open when clicked:ObjectOpenRecordIn.USER_CHOICE(the default, following each workspace member’s own preference from Settings → Experience),ObjectOpenRecordIn.SIDE_PANEL, orObjectOpenRecordIn.RECORD_PAGE. Pin it toRECORD_PAGEfor records that need a full page to be usable, the way workflows and dashboards do, or toSIDE_PANELfor records that only make sense as a quick panel, the way calendar events do.writabilitycontrols who may write records of the object at all, before role permissions apply:MetadataWritability.OPEN(the default — workspace roles decide),MetadataWritability.APPLICATION(only your app’s own logic functions can create, update, or delete records; use this for configuration-like objects whose records grant behavior, so workspace members with broad record access cannot edit them through the API), orMetadataWritability.SYSTEM(reserved for platform-managed data). Reads are unaffected — this is enforced server-side, unlikeisUIEditable, which only hides UI affordances. It also exists per field, where it can only be stricter than the object’s level.colorsets the accent color of the object in the UI. Omit it and Twenty picks one for the object.imageIdentifierFieldMetadataUniversalIdentifiernames the field whose value is shown as the record avatar. Omit it to let Twenty pick the default.isLabelSyncedWithName, on an object or on a field, keeps the API name in sync with the label when the label is edited in Settings. It defaults tofalse, so a renamed label leaves the name untouched.- Inline fields defined here do not need an
objectUniversalIdentifier— it’s inherited from the parent object. UsedefineField()to add fields to objects you don’t own. - You can scaffold new objects with
yarn twenty dev:add object, which guides you through naming, fields, and relationships. See Architecture → Scaffolding entities.
Base fields are added automatically. When you define a custom object, Twenty creates standard fields like
id, name, createdAt, updatedAt, createdBy, updatedBy, and deletedAt for you. You don’t need to declare them in your fields array — only your custom fields. You can override a default field by declaring one with the same name, but this is rarely a good idea.Field types
The full set ofFieldType values, exported from twenty-sdk/define:
Composite types store multiple sub-fields (e.g.
FULL_NAME = first + last name; CURRENCY = amountMicros + currencyCode). SELECT and MULTI_SELECT require an options array as in the example above.
Default values
Literal string defaults must be wrapped in single quotes inside the string —defaultValue: "'Draft'", not defaultValue: "Draft". That’s why the status field above uses `'${PostCardStatus.DRAFT}'`.
Unquoted strings are reserved for computed defaults, evaluated when a record is created:
'uuid'— generates a UUID (forUUIDfields)'now'— the current timestamp (forDATE_TIMEfields)
{ source: "'MANUAL'" } on an ACTOR field) and to SELECT/MULTI_SELECT values. A literal string default left unquoted raises a warning when your app is built.
Nullability
isNullable controls whether a field accepts NULL. It defaults to true — omit it for optional fields. Set isNullable: false to make a field required at the database level.
Changes to isNullable are applied on every sync, including syncs that update an existing field — so you can flip a field’s nullability by editing the manifest and re-syncing.
Making an existing field non-nullable requires a default value. When you change a field to
isNullable: false, you must also provide a non-null defaultValue. The default backfills any existing NULL rows before the NOT NULL constraint is applied; without it the sync fails with Default value cannot be null for non-nullable fields. Relation fields and TS_VECTOR fields are always nullable, so isNullable has no effect on them.What’s next
- Connect this object to others — see Relations for the bidirectional relation pattern.
- Add fields to objects from other apps — see Extending Objects for
defineField(). - Display this object in the UI — see Navigation Menu Items to add a sidebar entry; see Views to add custom list configurations.