> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-vortex-format.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Utiliser Drizzle ORM avec ClickHouse Managed Postgres

> Connectez une application TypeScript à ClickHouse Managed Postgres avec Drizzle ORM et node-postgres, exécutez des migrations avec drizzle-kit et lancez des requêtes via une connexion TLS vérifiée

export const BetaBadge = ({link, galaxyTrack, galaxyEvent}) => {
  if (link) {
    return <a href={link} target="_blank" rel="noopener noreferrer" className="betaBadge" onClick={galaxyTrack && galaxyEvent ? galaxyOnClick(galaxyEvent) : undefined}>
                <span>Beta</span>
            </a>;
  }
  return <a href="https://clickhouse.com/docs/reference/settings/beta-and-experimental-features#beta-features" className="betaBadge">
            <span>Fonctionnalité en bêta</span>
        </a>;
};

<BetaBadge link="https://clickhouse.com/cloud/postgres" galaxyTrack={true} galaxyEvent="docs.managed-postgres.guides-drizzle-beta" />

[Drizzle ORM](https://orm.drizzle.team/) est un ORM TypeScript doté d'un query builder à la syntaxe proche du SQL, et `drizzle-kit` est la CLI qui l'accompagne pour générer et exécuter des migrations. Dans ce guide, vous définissez une table `todos` en TypeScript, vous la créez au moyen d'une migration `drizzle-kit`, puis vous servez des requêtes de création, de lecture, de mise à jour et de suppression depuis un petit serveur HTTP Node.js. Toutes les connexions utilisent TLS avec une vérification complète des certificats.

<h2 id="prerequisites">
  Prérequis
</h2>

* [Node.js](https://nodejs.org/) 20 ou version ultérieure
* Un compte ClickHouse Cloud
* [`psql`](https://www.postgresql.org/download/), pour créer la base de données. Vous pouvez également exécuter le statement `CREATE DATABASE` dans la [console SQL](/fr/integrations/connectors/sql-clients/sql-console).

<h2 id="create-service">
  Créer un service ClickHouse Managed Postgres
</h2>

Dans la console ClickHouse Cloud, cliquez sur **New service** et sélectionnez **Postgres**. L'instance est prête en quelques minutes. Pour une présentation pas à pas, consultez le [guide de démarrage rapide](/fr/products/managed-postgres/quickstart).

<h2 id="connection-details">
  Obtenir vos informations de connexion
</h2>

Cliquez sur **Connect** dans la barre latérale gauche de votre service. La fenêtre modale affiche votre nom d'utilisateur, votre mot de passe, le serveur et le port, ainsi qu'un bouton bascule **Directly** / **via PgBouncer**.

Ce guide utilise deux chaînes de connexion :

* **Directe (port `5432`)** pour `drizzle-kit`. Les migrations exécutent du DDL, peuvent durer longtemps et dépendre de l'état de session, par exemple `SET lock_timeout` ; elles doivent donc communiquer directement avec Postgres.
* **PgBouncer (port `6432`)** pour l'application. Le [PgBouncer](/fr/products/managed-postgres/connection#pgbouncer) intégré fonctionne en mode de pool de connexions par transaction et permet à de nombreuses instances de l'application, y compris des fonctions serverless, de se partager un petit nombre de connexions Postgres.

<Tip>
  Si vous exécutez un seul serveur Node.js de longue durée, `node-postgres` gère déjà son propre pool de connexions ; vous pouvez donc aussi faire pointer l'application vers la connexion directe. Utilisez la connexion PgBouncer lorsque vous répartissez la charge sur de nombreux processus ou que vous déployez sur des plateformes serverless.
</Tip>

Une fois **Directly** sélectionné, activez **Use SSL**. L'URL de connexion de l'onglet **url** se termine alors par `sslmode=verify-full&sslrootcert=<service-name>-ca-certificate.pem`, et le port est `5432`. Sélectionnez **via PgBouncer** pour afficher les informations de connexion via le pool : le port passe à `6432`, et l'URL inclut toujours `sslmode=verify-full`.

Dans la fenêtre modale, cliquez sur **Download CA certificate**. Vous pouvez également le télécharger depuis **Settings → CA Certificate**. Ce certificat est propre à votre instance, ce qui permet au driver de vérifier qu'il communique bien avec votre serveur.

<h2 id="project-setup">
  Configurer le projet
</h2>

Créez un projet et installez Drizzle ORM, le driver [`node-postgres`](https://node-postgres.com/) (`pg`) ainsi que `drizzle-kit` :

```bash theme={null}
mkdir drizzle-managed-postgres && cd drizzle-managed-postgres
npm init -y
npm pkg set type=module
npm install drizzle-orm pg dotenv
npm install -D drizzle-kit tsx @types/pg
```

<Tip>
  **Vous ajoutez Drizzle à une application existante ?**

  Ignorez les commandes `mkdir`, `npm init` et `npm pkg set type=module`. Dans votre projet, exécutez `npm install drizzle-orm pg dotenv` et `npm install -D drizzle-kit tsx @types/pg`, puis passez directement à la section [Configurer la connexion](#configure-connection).
</Tip>

<h2 id="configure-connection">
  Configurer la connexion
</h2>

Déplacez le certificat CA que vous avez téléchargé dans le répertoire du projet et renommez-le en `ca-certificate.pem`.

Créez une base de données pour l'application. Remplacez `<PASSWORD>` et l'hôte par les valeurs indiquées dans la fenêtre modale **Connect** :

```bash theme={null}
psql "postgresql://postgres:<PASSWORD>@your-instance.pg.clickhouse.cloud:5432/postgres?sslmode=verify-full&sslrootcert=ca-certificate.pem" -c "CREATE DATABASE guide_drizzle;"
```

```text theme={null}
CREATE DATABASE
```

Ajoutez les deux chaînes de connexion à un fichier `.env` à la racine du projet, ou à votre fichier `.env` existant. Elles ne diffèrent que par le port et pointent toutes deux vers la base de données `guide_drizzle` :

```bash title=".env" theme={null}
# Runtime queries go through PgBouncer (port 6432)
DATABASE_URL="postgresql://postgres:<PASSWORD>@your-instance.pg.clickhouse.cloud:6432/guide_drizzle?sslmode=verify-full&sslrootcert=ca-certificate.pem"
# drizzle-kit migrations connect directly to Postgres (port 5432)
DIRECT_DATABASE_URL="postgresql://postgres:<PASSWORD>@your-instance.pg.clickhouse.cloud:5432/guide_drizzle?sslmode=verify-full&sslrootcert=ca-certificate.pem"
```

`node-postgres` lit `sslmode=verify-full` et `sslrootcert` depuis l’URL. Il charge le fichier de l'autorité de certification (CA) et vérifie à la fois la chaîne de certificats et le nom d’hôte : vous n'avez donc besoin d'aucun code TLS supplémentaire. Le path `sslrootcert` est résolu par rapport au répertoire depuis lequel vous exécutez les commandes. Ne versionnez pas le fichier `.env` : excluez-le du contrôle de version.

<Note>
  Si le fichier de la CA est manquant ou incorrect, la connexion échoue avec l'erreur `unable to verify the first certificate`. Si le nom d’hôte ne correspond pas au certificat, elle échoue avec l'erreur `ERR_TLS_CERT_ALTNAME_INVALID`. Si votre mot de passe contient des caractères spéciaux tels que `@`, `/` ou `#`, encodez-les au format URL.
</Note>

<h2 id="schema">
  Définir le schéma
</h2>

Créez le fichier `src/db/schema.ts` :

```ts title="src/db/schema.ts" theme={null}
import { boolean, integer, pgTable, text, timestamp } from "drizzle-orm/pg-core";

export const todos = pgTable("todos", {
  id: integer().primaryKey().generatedAlwaysAsIdentity(),
  title: text().notNull(),
  done: boolean().notNull().default(false),
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
});
```

Créez `drizzle.config.ts` à la racine du projet. Ce fichier indique à `drizzle-kit` où trouver le schéma et quelle connexion directe utiliser :

```ts title="drizzle.config.ts" theme={null}
import "dotenv/config";
import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql",
  schema: "./src/db/schema.ts",
  out: "./drizzle",
  dbCredentials: {
    // Migrations use the direct connection (port 5432)
    url: process.env.DIRECT_DATABASE_URL!,
  },
});
```

<h2 id="migrations">
  Exécuter les migrations
</h2>

Générez une migration SQL à partir du schéma :

```bash theme={null}
npx drizzle-kit generate --name init
```

```text theme={null}
1 tables
todos 4 columns 0 indexes 0 fks

[✓] Your SQL migration file ➜ drizzle/0000_init.sql 🚀
```

Le fichier `drizzle/0000_init.sql` généré contient le statement `CREATE TABLE`. Relisez-le, puis commitez le dossier `drizzle` avec votre code. Appliquez-le ensuite :

```bash theme={null}
npx drizzle-kit migrate
```

```text theme={null}
Using 'pg' driver for database querying
[✓] migrations applied successfully!
```

`drizzle-kit migrate` enregistre les migrations appliquées dans la table `drizzle.__drizzle_migrations` et n'exécute que les nouvelles lors des appels suivants. Chaque fois que vous modifiez `schema.ts`, exécutez `generate`, puis à nouveau `migrate`.

<Tip>
  `drizzle-kit migrate` se termine avec le statut `1`, sans aucun message d'erreur, lorsqu'il ne parvient pas à se connecter, par exemple si le path `sslrootcert` ou le mot de passe est incorrect. Dans ce cas, testez d'abord `DIRECT_DATABASE_URL` avec `psql`.
</Tip>

`drizzle-kit push` applique les modifications de schéma sans passer par des fichiers de migration. C'est pratique pour le prototypage, mais en production, `generate` et `migrate` vous offrent des fichiers SQL que vous pouvez relire, ainsi qu'un historique.

<h2 id="query">
  Interroger la base de données
</h2>

Créez `src/db/index.ts`. Ce fichier instancie le client Drizzle sur un pool `node-postgres` qui passe par la connexion PgBouncer :

```ts title="src/db/index.ts" theme={null}
import "dotenv/config";
import { drizzle } from "drizzle-orm/node-postgres";

// The app uses the PgBouncer connection (port 6432)
export const db = drizzle(process.env.DATABASE_URL!);
```

Créez `src/server.ts`, un petit serveur HTTP qui exécute une requête Drizzle par route. Dans une application existante, vous pouvez à la place appeler ces mêmes requêtes `db` depuis vos propres handlers de route :

```ts title="src/server.ts" theme={null}
import { createServer } from "node:http";
import { desc, eq, not } from "drizzle-orm";
import { db } from "./db";
import { todos } from "./db/schema";

const server = createServer(async (req, res) => {
  const url = new URL(req.url ?? "/", "http://localhost");
  const id = Number(url.pathname.split("/")[2]);
  let body: unknown;

  try {
    if (req.method === "GET" && url.pathname === "/todos") {
      // Read
      body = await db.select().from(todos).orderBy(desc(todos.id));
    } else if (req.method === "POST" && url.pathname === "/todos") {
      // Create
      const title = url.searchParams.get("title") ?? "Untitled";
      [body] = await db.insert(todos).values({ title }).returning();
    } else if (req.method === "PATCH" && id) {
      // Update: toggle the done flag
      [body] = await db
        .update(todos)
        .set({ done: not(todos.done) })
        .where(eq(todos.id, id))
        .returning();
    } else if (req.method === "DELETE" && id) {
      // Delete
      [body] = await db.delete(todos).where(eq(todos.id, id)).returning();
    } else {
      res.writeHead(404).end();
      return;
    }
    res.writeHead(200, { "Content-Type": "application/json" });
    res.end(JSON.stringify(body, null, 2) + "\n");
  } catch (err) {
    console.error(err);
    res.writeHead(500).end("Database error\n");
  }
});

server.listen(3101, () => console.log("Listening on http://localhost:3101/todos"));
```

<Note>
  Aucun paramètre de driver n'est nécessaire pour PgBouncer. Par défaut, les requêtes de Drizzle utilisent des statements non nommés, et le PgBouncer intégré prend également en charge les prepared statements nommés, comme ceux créés avec la méthode `.prepare` de Drizzle, en mode pool de connexions par transaction. Les fonctionnalités propres à la session, comme `LISTEN` et les verrous consultatifs de session, ne fonctionnent pas via PgBouncer. Consultez la [FAQ](/fr/products/managed-postgres/faq#prepared-statement-errors).
</Note>

<h2 id="verify">
  Exécuter et vérifier
</h2>

Démarrez le serveur :

```bash theme={null}
npx tsx src/server.ts
```

```text theme={null}
Listening on http://localhost:3101/todos
```

Dans un second terminal, créez deux tâches, marquez la première comme terminée et supprimez la seconde :

```bash theme={null}
curl -X POST "http://localhost:3101/todos?title=Try%20Drizzle%20ORM"
curl -X POST "http://localhost:3101/todos?title=Write%20a%20migration"
curl -X PATCH http://localhost:3101/todos/1
curl -X DELETE http://localhost:3101/todos/2
```

La requête `PATCH` renvoie la ligne mise à jour :

```json theme={null}
{
  "id": 1,
  "title": "Try Drizzle ORM",
  "done": true,
  "createdAt": "2026-09-30T16:45:14.610Z"
}
```

Ouvrez `http://localhost:3101/todos` dans votre navigateur pour afficher la liste des tâches restantes. La réponse se présente comme suit :

```json theme={null}
[
  {
    "id": 1,
    "title": "Try Drizzle ORM",
    "done": true,
    "createdAt": "2026-09-30T16:45:14.610Z"
  }
]
```

Pour afficher les données dans la console, ouvrez **console SQL** dans la barre latérale gauche de votre service, développez `guide_drizzle` puis `public`, et cliquez sur la table `todos`. Le schéma `drizzle` héberge la table d'historique des migrations. La table `todos` contient la ligne restante :

| id | title | done | created\_at |
| - | - | - | - |
| 1 | Try Drizzle ORM | true | 2026-09-30 16:45:14.610099+00 |

<h2 id="next-steps">
  Étapes suivantes
</h2>

* [Connexion](/fr/products/managed-postgres/connection) : chaînes de connexion, PgBouncer et TLS
* [Paramètres](/fr/products/managed-postgres/settings) : paramètres de Postgres et de PgBouncer, tels que `max_connections`
* [Répliques en lecture](/fr/products/managed-postgres/read-replicas) : répartissez la charge de lecture avec [`withReplicas`](https://orm.drizzle.team/docs/read-replicas) de Drizzle
* [Sécurité](/fr/products/managed-postgres/security) : listes d'accès IP et réseau privé
