---
title: Objets
description: Déclarez de nouveaux types d’enregistrements — des tables personnalisées avec leurs propres champs — à l’aide de defineObject.
icon: table
---

Les **objets** personnalisés sont de nouveaux types d’enregistrements que votre application ajoute à un espace de travail — carte postale, facture, abonnement, tout ce qui est spécifique à votre domaine. Chaque objet déclare son schéma (champs, relations, valeurs par défaut) et un identifiant universel stable qui survit aux synchronisations et aux déploiements.

```ts src/objects/post-card.object.ts
import { defineObject, FieldType } from 'twenty-sdk/define';

enum PostCardStatus {
  DRAFT = 'DRAFT',
  SENT = 'SENT',
  DELIVERED = 'DELIVERED',
  RETURNED = 'RETURNED',
}

export default defineObject({
  universalIdentifier: '54b589ca-eeed-4950-a176-358418b85c05',
  nameSingular: 'postCard',
  namePlural: 'postCards',
  labelSingular: 'Post Card',
  labelPlural: 'Post Cards',
  description: 'A post card object',
  icon: 'IconMail',
  fields: [
    {
      universalIdentifier: '58a0a314-d7ea-4865-9850-7fb84e72f30b',
      name: 'content',
      type: FieldType.TEXT,
      label: 'Content',
      description: "Postcard's content",
      icon: 'IconAbc',
    },
    {
      universalIdentifier: 'c6aa31f3-da76-4ac6-889f-475e226009ac',
      name: 'recipientName',
      type: FieldType.FULL_NAME,
      label: 'Recipient name',
      icon: 'IconUser',
    },
    {
      universalIdentifier: '95045777-a0ad-49ec-98f9-22f9fc0c8266',
      name: 'recipientAddress',
      type: FieldType.ADDRESS,
      label: 'Recipient address',
      icon: 'IconHome',
    },
    {
      universalIdentifier: '87b675b8-dd8c-4448-b4ca-20e5a2234a1e',
      name: 'status',
      type: FieldType.SELECT,
      label: 'Status',
      icon: 'IconSend',
      defaultValue: `'${PostCardStatus.DRAFT}'`,
      options: [
        { value: PostCardStatus.DRAFT, label: 'Draft', position: 0, color: 'gray' },
        { value: PostCardStatus.SENT, label: 'Sent', position: 1, color: 'orange' },
        { value: PostCardStatus.DELIVERED, label: 'Delivered', position: 2, color: 'green' },
        { value: PostCardStatus.RETURNED, label: 'Returned', position: 3, color: 'orange' },
      ],
    },
    {
      universalIdentifier: 'e06abe72-5b44-4e7f-93be-afc185a3c433',
      name: 'deliveredAt',
      type: FieldType.DATE_TIME,
      label: 'Delivered at',
      icon: 'IconCheck',
      isNullable: true,
      defaultValue: null,
    },
  ],
});
```

## Points clés

* Le `universalIdentifier` doit être unique et stable entre les déploiements.
* Chaque champ nécessite un `name`, un `type`, un `label` et son propre `universalIdentifier` stable.
* Le tableau `fields` est facultatif — vous pouvez définir des objets sans champs personnalisés.
* `openRecordIn` définit où les enregistrements de cet objet s’ouvrent lorsqu’on clique dessus : `ObjectOpenRecordIn.USER_CHOICE` (la valeur par défaut, qui suit la préférence de chaque membre de l’espace de travail dans Settings → Experience), `ObjectOpenRecordIn.SIDE_PANEL` ou `ObjectOpenRecordIn.RECORD_PAGE`. Épinglez-le sur `RECORD_PAGE` pour les enregistrements qui ont besoin d’une page complète pour être utilisables, comme les flux de travail et les tableaux de bord, ou sur `SIDE_PANEL` pour les enregistrements qui n’ont de sens qu’en tant que panneau rapide, comme les événements de calendrier.
* Les champs en ligne définis ici n’ont **pas** besoin d’un `objectUniversalIdentifier` — il est hérité de l’objet parent. Utilisez [`defineField()`](/l/fr/developers/extend/apps/data/extending-objects) pour ajouter des champs aux objets que vous ne possédez pas.
* Vous pouvez générer de nouveaux objets avec `yarn twenty dev:add object`, qui vous guide à travers le nommage, les champs et les relations. Voir [Architecture → Scaffolding entities](/l/fr/developers/extend/apps/getting-started/scaffolding).

<Note>
**Les champs de base sont ajoutés automatiquement.** Lorsque vous définissez un objet personnalisé, Twenty crée pour vous des champs standard comme `id`, `name`, `createdAt`, `updatedAt`, `createdBy`, `updatedBy` et `deletedAt`. Vous n’avez pas besoin de les déclarer dans votre tableau `fields` — uniquement vos champs personnalisés. Vous pouvez remplacer un champ par défaut en en déclarant un avec le même nom, mais c’est rarement une bonne idée.
</Note>

## Types de champ

L’ensemble complet des valeurs de `FieldType`, exportées depuis `twenty-sdk/define` :

| Catégorie                 | Types                                                                                                                              |
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| Texte                     | `TEXT`, `RICH_TEXT`, `ARRAY` (de chaînes), `RAW_JSON`                                                                              |
| Numérique                 | `NUMBER` (`universalSettings.dataType` : `'float'` / `'int'` / `'bigint'`), `NUMERIC` (précision arbitraire), `RATING`, `POSITION` |
| Dates                     | `DATE`, `DATE_TIME`                                                                                                                |
| Choix                     | `BOOLEAN`, `SELECT`, `MULTI_SELECT`                                                                                                |
| Composés                  | `FULL_NAME`, `ADDRESS`, `EMAILS`, `PHONES`, `LINKS`, `CURRENCY`, `ACTOR`, `FILES`                                                  |
| Identifiants et relations | `UUID`, `RELATION`, `MORPH_RELATION` (voir [Relations](/l/fr/developers/extend/apps/data/relations))                                    |
| Système                   | `TS_VECTOR` (vecteur de recherche en texte intégral, géré par le serveur)                                                          |

Les types composés stockent plusieurs sous-champs (par exemple `FULL_NAME` = prénom + nom de famille ; `CURRENCY` = `amountMicros` + `currencyCode`). `SELECT` et `MULTI_SELECT` nécessitent un tableau `options` comme dans l’exemple ci-dessus.

## Valeurs par défaut

Les valeurs par défaut de type chaîne littérale doivent être entourées de guillemets simples **à l’intérieur** de la chaîne — `defaultValue: "'Draft'"`, et non `defaultValue: "Draft"`. C’est pourquoi le champ `status` ci-dessus utilise `` `'${PostCardStatus.DRAFT}'` ``.

Les chaînes sans guillemets sont réservées aux valeurs par défaut calculées, évaluées lors de la création d’un enregistrement :

* `'uuid'` — génère un UUID (pour les champs `UUID`)
* `'now'` — l’horodatage actuel (pour les champs `DATE_TIME`)

La même convention s’applique aux sous-champs de type chaîne des valeurs par défaut composites (par exemple `{ source: "'MANUAL'" }` sur un champ `ACTOR`) ainsi qu’aux valeurs `SELECT`/`MULTI_SELECT`. Une valeur par défaut littérale de type chaîne laissée sans guillemets génère un avertissement lors de la compilation de votre application.

## Nullabilité

`isNullable` détermine si un champ accepte `NULL`. Sa valeur par défaut est `true` — omettez-le pour les champs facultatifs. Définissez `isNullable: false` pour rendre un champ obligatoire au niveau de la base de données.

Les modifications de `isNullable` sont appliquées à chaque synchronisation, y compris celles qui mettent à jour un champ existant — vous pouvez donc modifier la nullabilité d’un champ en éditant le manifeste puis en relançant la synchronisation.

<Note>
**Rendre un champ existant non nullable nécessite une valeur par défaut.** Lorsque vous modifiez un champ avec `isNullable: false`, vous devez également fournir une `defaultValue` non nulle. La valeur par défaut remplit rétroactivement toutes les lignes `NULL` existantes avant que la contrainte `NOT NULL` ne soit appliquée ; sans cela, la synchronisation échoue avec `Default value cannot be null for non-nullable fields`. Les champs de relation et les champs `TS_VECTOR` sont toujours nullables, donc `isNullable` n’a aucun effet sur eux.
</Note>

```ts
{
  universalIdentifier: 'b1a7c0de-1234-4f00-9abc-000000000000',
  name: 'reference',
  type: FieldType.TEXT,
  label: 'Reference',
  isNullable: false,
  defaultValue: "'N/A'",
}
```

## Et après

* **Connectez cet objet aux autres** — voir [Relations](/l/fr/developers/extend/apps/data/relations) pour le modèle de relation bidirectionnelle.
* **Ajoutez des champs aux objets d’autres applications** — voir [Extending Objects](/l/fr/developers/extend/apps/data/extending-objects) pour `defineField()`.
* **Afficher cet objet dans l’interface utilisateur** — voir [Éléments du menu de navigation](/l/fr/developers/extend/apps/layout/navigation-menu-items) pour ajouter une entrée dans la barre latérale ; voir [Vues](/l/fr/developers/extend/apps/layout/views) pour ajouter des configurations de liste personnalisées.
