FlowKit

Le node Postgres dans n8n : des requêtes SQL directes dans vos workflows

Publié le 28 juillet 2026 · 8 min de lecture

Beaucoup de workflows n8n finissent par toucher une base de données : enregistrer un lead, vérifier qu'un webhook n'a pas déjà été traité, agréger des ventes pour un rapport hebdomadaire. Les nodes applicatifs (CRM, tableurs, API REST) couvrent une partie de ces besoins, mais dès que la logique devient relationnelle — jointures, agrégations, écritures conditionnelles — rien ne remplace du SQL exécuté directement sur la base. C'est exactement le rôle du node Postgres : un client SQL complet au cœur du workflow, avec des opérations prêtes à l'emploi pour les cas simples et une opération Execute Query pour tout le reste.

Opérations intégrées ou Execute Query : deux façons d'interroger la base

Le node Postgres propose deux niveaux d'abstraction. Le premier, ce sont les opérations intégrées : Insert, Update, Insert or Update (upsert), Select et Delete. Vous choisissez une table, n8n en lit le schéma et vous mappez les colonnes sur les champs des items entrants — automatiquement si les noms correspondent, manuellement sinon. Aucun SQL à écrire, pas de faute de frappe possible dans un nom de colonne : pour écrire un lead dans une table leads ou lire les lignes correspondant à un filtre simple, c'est le chemin le plus court et le plus sûr.

Le second niveau, c'est l'opération Execute Query : un champ de texte libre dans lequel vous écrivez la requête SQL de votre choix — SELECT avec jointures, GROUP BY, INSERT … ON CONFLICT, CTE, appel de fonction. C'est indispensable dès que le besoin dépasse le CRUD ligne à ligne, car les opérations intégrées ne savent ni agréger, ni joindre, ni poser de clause conditionnelle complexe.

La règle pratique : commencez par les opérations intégrées, et basculez sur Execute Query uniquement quand la requête l'exige. Un workflow où chaque node Postgres contient du SQL brut pour de simples insertions est plus fragile (schéma dupliqué dans le texte des requêtes) qu'un workflow qui réserve le SQL libre aux endroits où il apporte réellement quelque chose.

Paramètres de requête : $1 et $2 plutôt que des expressions concaténées

Le réflexe naturel avec Execute Query est d'insérer des expressions n8n directement dans la requête :

SELECT * FROM commandes WHERE email = '{{ $json.email }}'

C'est précisément ce qu'il ne faut pas faire. La valeur est concaténée telle quelle dans le texte SQL : un simple O'Brien casse la requête, et une valeur construite par un tiers malveillant — un champ de formulaire, un payload de webhook — peut en détourner complètement la logique. L'étude de référence de Halfond, Viegas et Orso, « A Classification of SQL Injection Attacks and Countermeasures » (IEEE International Symposium on Secure Software Engineering, 2006 — voir sur Google Scholar), a établi la taxonomie de ces attaques par injection SQL et identifie les requêtes paramétrées comme contre-mesure de premier rang : la requête et les données empruntent des canaux séparés, le serveur ne peut donc jamais interpréter une valeur comme du code.

Le node Postgres implémente exactement ce mécanisme via l'option Query Parameters. Vous écrivez des marqueurs $1, $2… dans la requête, et vous fournissez les valeurs à part, dans le champ Query Parameters (séparées par des virgules, expressions autorisées) :

SELECT id, montant, statut
FROM commandes
WHERE email = $1 AND statut = $2

avec {{ $json.email }}, {{ $json.statut }} comme Query Parameters. Même résultat fonctionnel, mais l'apostrophe de O'Brien est traitée comme un caractère ordinaire et une tentative d'injection reste une chaîne inerte. À réserver aux valeurs uniquement : les noms de tables ou de colonnes ne peuvent pas être paramétrés en Postgres — si vous devez rendre un nom de table dynamique, validez-le contre une liste blanche dans un node Code en amont plutôt que d'y injecter une expression.

Se connecter : Docker local, Supabase ou serveur managé

Les credentials Postgres de n8n demandent les classiques : hôte, port (5432 par défaut), base, utilisateur, mot de passe, et le mode SSL.

Postgres local en Docker. Si n8n et Postgres tournent dans le même docker-compose, l'hôte n'est pas localhost (qui désigne le conteneur n8n lui-même) mais le nom du servicepostgres, par exemple. C'est l'erreur de connexion la plus fréquente en self-hosted. SSL peut rester désactivé sur un réseau Docker interne. Et si cette base porte vos données de production, notre guide sur la sauvegarde et la restauration PostgreSQL en self-hosted est le complément indispensable.

Supabase. Chaque projet Supabase est une base Postgres complète, accessible en SQL direct. Utilisez de préférence le connection pooler (hôte et port affichés dans les paramètres de connexion du projet, utilisateur de la forme postgres.<ref-projet>) plutôt que la connexion directe, souvent inaccessible depuis un serveur sans IPv6. Activez SSL. La mise en place détaillée, credentials compris, est couverte dans notre guide de connexion n8n–Supabase.

Serveur managé (RDS, Cloud SQL, Scaleway, OVH…) : mêmes paramètres, avec SSL activé systématiquement et, côté hébergeur, l'IP de votre instance n8n autorisée dans le pare-feu ou les règles de sécurité. En cas d'erreur connection refused, c'est presque toujours ce filtrage réseau qu'il faut regarder en premier.

Cas d'usage concrets

Rapport d'agrégation. Les opérations intégrées ne savent pas faire de GROUP BY : pour un rapport, Execute Query est la seule voie.

SELECT date_trunc('week', cree_le) AS semaine,
       source, COUNT(*) AS leads, SUM(montant) AS ca
FROM leads
WHERE cree_le >= $1
GROUP BY 1, 2
ORDER BY 1 DESC

Chaque ligne du résultat devient un item n8n, prêt à alimenter un email, un Slack ou un Google Sheets.

Upsert idempotent. Un webhook rejoué ou un scénario relancé ne doit pas créer de doublon. L'opération Insert or Update le gère sur une colonne de correspondance ; en SQL libre, ON CONFLICT donne le contrôle total :

INSERT INTO clients (email, nom, maj_le)
VALUES ($1, $2, NOW())
ON CONFLICT (email) DO UPDATE
SET nom = EXCLUDED.nom, maj_le = NOW()

Relancé dix fois avec les mêmes données, ce node produit exactement le même état final — le cœur du pattern détaillé dans notre article sur l'idempotence des webhooks.

Jointure pour enrichir des items. Plutôt que de faire un Select par item puis de recoller les morceaux avec un node Merge (utile dans d'autres situations, voir notre guide du node Merge), une seule requête avec JOIN ramène les items déjà enrichis : commandes avec le nom du client, tickets avec leur historique.

Table de déduplication. Une table evenements_traites (id_evenement TEXT PRIMARY KEY) et un INSERT … ON CONFLICT DO NOTHING dont on teste le nombre de lignes affectées : si zéro ligne insérée, l'événement a déjà été vu et le workflow s'arrête là. Simple, transactionnel, sans course entre exécutions concurrentes.

Transactions et comportement par item

Comme la plupart des nodes n8n, le node Postgres s'exécute pour chaque item entrant : dix items en entrée d'un Execute Query, c'est dix exécutions de la requête, chacune avec ses propres paramètres. L'option Query Batching règle la façon dont ces requêtes partent vers la base : groupées en un seul appel (le plus rapide), exécutées indépendamment (une erreur sur un item n'arrête pas les autres — à combiner avec la gestion d'erreur du node), ou enveloppées dans une transaction qui annule l'ensemble si une seule échoue. Ce dernier mode est le bon choix quand un lot d'écritures doit être appliqué entièrement ou pas du tout — un import de facturation, par exemple. Pour une transaction multi-étapes au sein d'une même requête, un bloc SQL unique (CTE en chaîne, ou BEGIN/COMMIT explicite dans un seul Execute Query) reste l'approche la plus fiable.

Quand préférer le node Supabase ou les Data Tables

Le node Postgres n'est pas toujours le bon outil. Le node Supabase passe par l'API REST du projet et respecte les politiques Row Level Security : si vos règles d'accès vivent dans RLS, une connexion SQL directe avec l'utilisateur postgres les contourne purement et simplement — le node Supabase est alors plus sûr pour les opérations CRUD standard, et c'est aussi la brique de base des architectures RAG avec Supabase. À l'inverse, pour du SQL libre (agrégations, ON CONFLICT, jointures), le node Postgres branché sur le pooler Supabase reste sans équivalent.

Quant aux Data Tables, le stockage tabulaire intégré à n8n, elles suffisent largement pour de petits états internes : compteurs, files d'attente légères, tables de déduplication modestes — sans credentials, sans serveur, sans SQL. Notre guide des Data Tables trace la frontière : dès qu'il faut des relations, des volumes sérieux ou des requêtes riches, revenez à Postgres.

Pièges fréquents

  • Concaténer des expressions {{ }} dans le texte SQL au lieu d'utiliser les Query Parameters : requêtes cassées par une apostrophe au mieux, injection SQL au pire, dès que la valeur vient d'un formulaire ou d'un webhook.
  • Utiliser localhost comme hôte en Docker : depuis le conteneur n8n, localhost ne désigne pas votre machine mais le conteneur lui-même. Utilisez le nom du service Docker (postgres) ou l'IP du réseau interne.
  • Se connecter à Supabase en connexion directe depuis un serveur sans IPv6 : passez par le connection pooler, prévu exactement pour ce cas.
  • Oublier que le node s'exécute par item : un Execute Query alimenté par 500 items lance 500 requêtes. Agrégez en amont, ou réglez Query Batching en conséquence.
  • Faire confiance aux opérations intégrées pour un besoin d'agrégation : Select ne fait pas de GROUP BY ni de jointure — c'est un cas Execute Query, inutile de multiplier les nodes pour le contourner.
  • Utiliser le super-utilisateur postgres partout : créez un rôle dédié au workflow, limité aux tables réellement nécessaires, pour qu'une erreur de requête (ou une injection qui aurait échappé à votre vigilance) ne puisse pas toucher le reste de la base.

Pour aller plus loin

Le node Postgres est la brique d'écriture fiable par excellence dès qu'un workflow doit laisser une trace durable et requêtable. C'est exactement l'usage qu'en fait le Pack Conformité & Audit (149 €), dont le workflow d'enregistrement d'audit écrit chaque événement sensible dans Postgres/Supabase — horodatage, acteur, action — pour constituer une piste exploitable en cas de contrôle, une démarche détaillée dans notre article sur la piste d'audit RGPD avec n8n et Supabase. Et si cette base devient le socle de vos automatisations, sa sauvegarde régulière n'est plus une option.

FAQ

Questions fréquentes

Pourquoi utiliser les Query Parameters ($1, $2) plutôt que des expressions {{ }} directement dans la requête SQL ?

Parce qu'une expression insérée dans le texte de la requête est concaténée telle quelle : une apostrophe dans un nom de client suffit à casser la requête, et une valeur forgée par un tiers peut en détourner la logique (injection SQL). Avec les Query Parameters, la requête et les valeurs voyagent séparément jusqu'au serveur Postgres, qui traite les valeurs comme des données pures, jamais comme du code SQL. C'est la contre-mesure de référence identifiée par la littérature sur les injections SQL.

Comment connecter n8n à une base Supabase avec le node Postgres ?

Utilisez de préférence le connection pooler de Supabase plutôt que la connexion directe : l'hôte et le port du pooler sont affichés dans les paramètres de connexion de votre projet Supabase, avec un utilisateur de la forme postgres.<ref-projet>. La connexion directe à la base est souvent inaccessible depuis un serveur sans IPv6, ce qui explique la plupart des erreurs de connexion. Activez SSL dans les credentials n8n, comme pour tout Postgres exposé sur Internet.

Le node Postgres exécute-t-il une requête par item ou une seule requête pour tous les items ?

Par défaut, la requête d'Execute Query est exécutée pour chaque item entrant, ce qui peut multiplier les allers-retours vers la base. L'option Query Batching permet de choisir : envoyer toutes les requêtes en un seul appel, les exécuter indépendamment (une erreur n'arrête pas les autres), ou les envelopper dans une transaction qui annule tout en cas d'échec. Ce dernier mode est précieux quand un lot d'écritures doit être appliqué entièrement ou pas du tout.

Quand préférer le node Supabase ou les Data Tables au node Postgres ?

Le node Supabase passe par l'API REST du projet et respecte les politiques Row Level Security : c'est le bon choix quand vous voulez bénéficier de ces règles d'accès plutôt que de les contourner par une connexion SQL directe. Les Data Tables, elles, suffisent pour de petits stockages internes (états, compteurs, tables de déduplication simples) sans gérer ni credentials ni serveur. Le node Postgres reste incontournable dès qu'il faut du SQL libre : agrégations, jointures, upsert avec ON CONFLICT.

Bundle FlowKit Complet

269 €