Skip to main content
Every object in Twenty comes with system metadata you never declare yourself, such as a set of fields and a main list view with its columns. The server creates all of it when the object is provisioned, and the set grows as Twenty does. Because you don’t declare it, there’s no universalIdentifier constant for you to import. Instead, the server derives each identifier deterministically, and twenty-sdk exposes the same derivation so your manifest can resolve the exact value the server uses.

System fields

The scalar fields present on every object, none of which you declare with defineField(): id, createdAt, updatedAt, deletedAt, createdBy, updatedBy, position, searchVector So how do you reference createdAt as a column in a view?

The problem

Since Twenty 2.19, a system field’s universal identifier is derived deterministically by the server from three inputs: the application universal identifier, the object universal identifier, and the field name. Inventing an id and hardcoding it won’t work: it matches nothing on the server, and the sync rejects the dangling reference:

The solution

getFieldUniversalIdentifier is available from twenty-sdk 2.21 onward.
Use getFieldUniversalIdentifier to resolve the exact same value the server uses. It takes the three inputs and returns the field’s universal identifier:
  • applicationUniversalIdentifier is your app’s identifier, the one you pass to defineApplication().
  • objectUniversalIdentifier is the identifier of the object the field belongs to.
  • name is the system field name, one of the values listed above.

Example: a createdAt column in a view

The typical case is adding a createdAt column to a view of one of your custom objects. Resolve the field id and reference it as any other fieldMetadataUniversalIdentifier:
src/views/example-view.ts
The same resolved id works anywhere a fieldMetadataUniversalIdentifier is expected: view fields, filters, sorts, groups, and page-layout widgets.
Resolve the id, don’t hardcode it. Because the server derives the value from the application id, the object id and the field name, calling getFieldUniversalIdentifier keeps your reference correct even if those inputs change, and avoids drift if the derivation ever evolves.

System relation fields

getSystemRelationFieldUniversalIdentifier is available from twenty-sdk 2.23 onward and requires a Twenty server on 2.23 or later.
Besides the scalar system fields above, the server also provisions four system relation fields on every object: timelineActivities, attachments, noteTargets and taskTargets, each pointing at the matching standard relation object. These fields are not resolved with getFieldUniversalIdentifier: their identifier is derived name-free, from the object hosting the field and the object the field points to. That way renaming an object never changes the identifiers of its relation fields. Use getSystemRelationFieldUniversalIdentifier to resolve them:
  • objectUniversalIdentifier is the object hosting the field.
  • relationTargetObjectUniversalIdentifier is the object the field points to.
The direction is encoded by the argument order. To resolve the reverse side (e.g. attachment.targetRocket, the morph field the server creates on the standard relation object), swap the two:
As with scalar system fields, the resolved id works anywhere a fieldMetadataUniversalIdentifier is expected.

System views

getSystemViewUniversalIdentifier and getSystemViewFieldUniversalIdentifier are available from twenty-sdk 2.26 onward and require a Twenty server on 2.26 or later.
The server also provisions a system view on every object: the main list view (All {objectLabelPlural}, keyed on ViewKey.INDEX), with one column per displayable field. Like system relation fields, their identifiers are derived name-free, so renaming an object or a field never changes them. Use getSystemViewUniversalIdentifier to resolve the view:
  • objectMetadataApplicationUniversalIdentifier is the application owning the object, which is what the view is namespaced by.
  • objectUniversalIdentifier is the object the view lists.
  • viewKey is the system view key, ViewKey.INDEX today.
The resolved id works anywhere a viewUniversalIdentifier is expected, such as a NavigationMenuItemType.VIEW sidebar entry. To simply open an object’s main list, prefer NavigationMenuItemType.OBJECT with targetObjectUniversalIdentifier: it needs no derivation. getSystemViewFieldUniversalIdentifier resolves a single column on a system view, from the view and the field it displays:
Note the first argument: a column is namespaced by the application owning the field it displays, not the one owning the view. A field your app adds to a standard object gets its column derived under your application, on a view owned by Twenty.
System views and their columns are server-owned: resolve their identifiers to reference them, never to declare them. key on defineView() is deprecated and ignored, so a manifest view can never claim the INDEX key, and the server already provisions a column for every field you add, so declaring your own defineViewField() for that same field on a system view conflicts with it.

Standard Twenty objects

For a standard Twenty object (Person, Company, Opportunity, …), you don’t need to derive anything: the identifiers are pre-computed constants you can import directly, for both fields and views.
Reach for the helpers above when the object is one your app defines with defineObject(), where no such constant exists.
name is a default field, not a system field. It keeps its own hardcoded universal identifier and is not resolved through getFieldUniversalIdentifier. On objects you define, reference the name field by the identifier you gave it in defineObject().