---
title: Targeting System Metadata
description: Resolve the deterministic universal identifiers of the metadata Twenty provisions automatically on every object, so your app can reference it without hardcoding.
icon: "gears"
---

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()`](/developers/extend/apps/data/extending-objects):

`id`, `createdAt`, `updatedAt`, `deletedAt`, `createdBy`, `updatedBy`, `position`, `searchVector`

So how do you reference `createdAt` as a column in a [view](/developers/extend/apps/layout/views)?

### 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:

```
Dev sync failed: viewField: INVALID_VIEW_DATA: Field metadata not found
```

### The solution

<Note>
  `getFieldUniversalIdentifier` is available from `twenty-sdk` 2.21 onward.
</Note>

Use `getFieldUniversalIdentifier` to resolve the exact same value the server uses. It takes the three inputs and returns the field's universal identifier:

```ts
import { getFieldUniversalIdentifier } from 'twenty-sdk/define';

const createdAtFieldId = getFieldUniversalIdentifier({
  applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
  objectUniversalIdentifier: MY_OBJECT_UNIVERSAL_IDENTIFIER,
  name: 'createdAt',
});
```

- `applicationUniversalIdentifier` is your app's identifier, the one you pass to [`defineApplication()`](/developers/extend/apps/config/application).
- `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`:

```ts src/views/example-view.ts
import {
  defineView,
  getFieldUniversalIdentifier,
} from 'twenty-sdk/define';

const APPLICATION_UNIVERSAL_IDENTIFIER =
  '0b04e15c-27b2-4741-9046-b32e07469072';
const MY_OBJECT_UNIVERSAL_IDENTIFIER =
  'c782b61c-70fd-4c88-9cd6-4e61ab8d7591';

export default defineView({
  universalIdentifier: '70f10d44-144a-4da8-8c6f-3ec2422138c0',
  name: 'All records',
  objectUniversalIdentifier: MY_OBJECT_UNIVERSAL_IDENTIFIER,
  icon: 'IconList',
  position: 0,
  fields: [
    {
      universalIdentifier: '75a90bc4-d901-4df4-85e0-af29db5e0104',
      fieldMetadataUniversalIdentifier: getFieldUniversalIdentifier({
        applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
        objectUniversalIdentifier: MY_OBJECT_UNIVERSAL_IDENTIFIER,
        name: 'createdAt',
      }),
      position: 0,
      isVisible: true,
      size: 200,
    },
  ],
});
```

The same resolved id works anywhere a `fieldMetadataUniversalIdentifier` is expected: view fields, filters, sorts, groups, and page-layout widgets.

<Note>
  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.
</Note>

### System relation fields

<Note>
  `getSystemRelationFieldUniversalIdentifier` is available from `twenty-sdk`
  2.23 onward and requires a Twenty server on 2.23 or later.
</Note>

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:

```ts
import {
  getSystemRelationFieldUniversalIdentifier,
  STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS,
} from 'twenty-sdk/define';

// rocket.attachments — the relation field hosted on your custom object
const rocketAttachmentsFieldId = getSystemRelationFieldUniversalIdentifier({
  applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
  objectUniversalIdentifier: ROCKET_OBJECT_UNIVERSAL_IDENTIFIER,
  relationTargetObjectUniversalIdentifier:
    STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.attachment.universalIdentifier,
});
```

- `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:

```ts
// attachment.targetRocket — the reverse morph field on Attachment
const attachmentTargetRocketFieldId =
  getSystemRelationFieldUniversalIdentifier({
    applicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
    objectUniversalIdentifier:
      STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.attachment.universalIdentifier,
    relationTargetObjectUniversalIdentifier: ROCKET_OBJECT_UNIVERSAL_IDENTIFIER,
  });
```

As with scalar system fields, the resolved id works anywhere a `fieldMetadataUniversalIdentifier` is expected.

## System views

<Note>
  `getSystemViewUniversalIdentifier` and `getSystemViewFieldUniversalIdentifier`
  are available from `twenty-sdk` 2.26 onward and require a Twenty server on
  2.26 or later.
</Note>

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:

```ts
import { getSystemViewUniversalIdentifier, ViewKey } from 'twenty-sdk/define';

const rocketIndexViewId = getSystemViewUniversalIdentifier({
  objectMetadataApplicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
  objectUniversalIdentifier: ROCKET_OBJECT_UNIVERSAL_IDENTIFIER,
  viewKey: ViewKey.INDEX,
});
```

- `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`](/developers/extend/apps/layout/navigation-menu-items) 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:

```ts
import { getSystemViewFieldUniversalIdentifier } from 'twenty-sdk/define';

const rocketNameColumnId = getSystemViewFieldUniversalIdentifier({
  fieldMetadataApplicationUniversalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
  viewUniversalIdentifier: rocketIndexViewId,
  fieldMetadataUniversalIdentifier: ROCKET_NAME_FIELD_UNIVERSAL_IDENTIFIER,
});
```

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.

<Warning>
  System views and their columns are **server-owned**: resolve their identifiers
  to reference them, never to declare them. `key` on
  [`defineView()`](/developers/extend/apps/layout/views) 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.
</Warning>

## 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.

```ts
import { STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS } from 'twenty-sdk/define';

// STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.company.fields.createdAt.universalIdentifier
// STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.fields.updatedAt.universalIdentifier
// STANDARD_OBJECT_UNIVERSAL_IDENTIFIERS.person.views.allPeople.universalIdentifier
```

Reach for the helpers above when the object is one **your app** defines with [`defineObject()`](/developers/extend/apps/data/objects), where no such constant exists.

<Note>
  `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()`.
</Note>
