packages/twenty-docs/developers/extend/apps/layout/views.mdx
A view is a saved configuration for how records of an object are displayed: which fields appear, their order, whether they're visible, and any filters or groups applied. Use defineView() to ship pre-configured views with your app — typically a default index view for each custom object you create.
import { defineView, ViewKey } from 'twenty-sdk/define';
import { EXAMPLE_OBJECT_UNIVERSAL_IDENTIFIER } from '../objects/example-object';
import { NAME_FIELD_UNIVERSAL_IDENTIFIER } from '../objects/example-object';
export default defineView({
universalIdentifier: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890',
name: 'All example items',
objectUniversalIdentifier: EXAMPLE_OBJECT_UNIVERSAL_IDENTIFIER,
icon: 'IconList',
key: ViewKey.INDEX,
position: 0,
fields: [
{
universalIdentifier: 'f926bdb7-6af7-4683-9a09-adbca56c29f0',
fieldMetadataUniversalIdentifier: NAME_FIELD_UNIVERSAL_IDENTIFIER,
position: 0,
isVisible: true,
size: 200,
},
],
});
objectUniversalIdentifier specifies which object this view applies to. It can be a custom object you defined or a standard Twenty object.key determines the view type — ViewKey.INDEX is the main list view for the object.fields controls which columns appear and in what order. Each field references a fieldMetadataUniversalIdentifier.filters, filterGroups, groups, and fieldGroups for advanced configurations.position controls ordering when multiple views exist for the same object.A view can ship with pre-applied filters. Each filter has three coordinates: the field being filtered, the operand (how to compare), and the value (what to compare against). All three must line up — using an operand that doesn't apply to a field type will be rejected at sync time.
import { ViewFilterOperand } from 'twenty-shared/types';
filters: [
{
universalIdentifier: '...',
fieldMetadataUniversalIdentifier: STATUS_FIELD_UNIVERSAL_IDENTIFIER,
operand: ViewFilterOperand.IS,
value: ['ACTIVE'],
},
],
| Field type | Supported operands |
|---|---|
TEXT, EMAILS, FULL_NAME, ADDRESS, LINKS, PHONES, RAW_JSON, FILES, ACTOR, ARRAY | CONTAINS, DOES_NOT_CONTAIN, IS_EMPTY, IS_NOT_EMPTY |
ACTOR.source, ACTOR.workspaceMemberId | IS, IS_NOT, IS_EMPTY, IS_NOT_EMPTY |
SELECT | IS, IS_NOT, IS_EMPTY, IS_NOT_EMPTY |
MULTI_SELECT | CONTAINS, DOES_NOT_CONTAIN, IS_EMPTY, IS_NOT_EMPTY |
RELATION | IS, IS_NOT, IS_EMPTY, IS_NOT_EMPTY |
NUMBER | IS, IS_NOT, GREATER_THAN_OR_EQUAL, LESS_THAN_OR_EQUAL, IS_EMPTY, IS_NOT_EMPTY |
RATING | IS, GREATER_THAN_OR_EQUAL, LESS_THAN_OR_EQUAL, IS_EMPTY, IS_NOT_EMPTY |
CURRENCY, CURRENCY.amountMicros | GREATER_THAN_OR_EQUAL, LESS_THAN_OR_EQUAL, IS, IS_NOT, IS_EMPTY, IS_NOT_EMPTY |
CURRENCY.currencyCode | IS, IS_NOT, IS_EMPTY, IS_NOT_EMPTY |
DATE, DATE_TIME | IS, IS_RELATIVE, IS_IN_PAST, IS_IN_FUTURE, IS_TODAY, IS_BEFORE, IS_AFTER, IS_EMPTY, IS_NOT_EMPTY |
BOOLEAN | IS |
UUID | IS |
TS_VECTOR | VECTOR_SEARCH |
Field types with similar names can use entirely different operands —
SELECTandMULTI_SELECTbeing a common case.
The value field is always a JSON-serializable value, but its expected shape depends on the operand:
| Operand family | Value shape | Example |
|---|---|---|
IS, IS_NOT on SELECT | array of option keys (strings) | ['ACTIVE', 'PENDING'] |
CONTAINS, DOES_NOT_CONTAIN on MULTI_SELECT | array of option keys (strings) | ['TAG_A'] |
IS, IS_NOT on RELATION | array of record IDs (uuids) | ['c5a1...'] |
CONTAINS, DOES_NOT_CONTAIN on text-like fields | string | 'acme' |
IS, IS_NOT on NUMBER | string (the value) | '5' |
IS on RATING / UUID | string (the value) | '5' |
GREATER_THAN_OR_EQUAL, LESS_THAN_OR_EQUAL | string (the bound) | '10' |
IS, IS_BEFORE, IS_AFTER on DATE / DATE_TIME | ISO 8601 string | '2025-01-01T00:00:00Z' |
IS_EMPTY, IS_NOT_EMPTY | empty string | '' |
IS on BOOLEAN | 'true' or 'false' | 'true' |
A view by itself isn't reachable from the sidebar. To make it appear there, pair it with a navigation menu item of type VIEW that points at the view's universalIdentifier. That's the canonical pattern: every custom object typically ships a default view + a sidebar entry that opens it.