Retour au blog
Comparatif Technique · 11 min de lecture

PgBouncer vs Supavisor vs PgCat : quel pooler Postgres en 2026

Affane Daylami · Fondateur· 24 août 2026

PgBouncer, Supavisor et PgCat mutualisent tous les trois des connexions Postgres, mais ils ne visent pas le même problème. PgBouncer reste le standard historique : léger, en C, intégré nativement à l'écosystème Kubernetes via CloudNativePG. Supavisor a été construit par Supabase pour un besoin précis, faire tenir des milliers de bases tenant derrière un seul service au lieu d'un process par base. PgCat, écrit en Rust, ajoute au pooling classique du sharding et de l'équilibrage de charge entre réplicas. Chez Aurabase, le trafic data-plane passe par PgBouncer en mode transaction. C'est ce que montre directement le code du dépôt : chart Helm, ressource CNPG Pooler et docker-compose local convergent tous vers le même choix.

Cet article compare l'architecture des trois poolers : langage, modes de pooling, modèle mono ou multi-tenant, fonctions au-delà du pooling pur. Tembo et PkgPulse ont publié des comparatifs chiffrés de ces trois outils, mais nous n'avons reproduit aucune de leurs mesures nous-mêmes. Notre position éditoriale sur les benchmarks, détaillée dans notre méthodologie de benchmark, est de ne jamais republier un chiffre qu'on n'a pas vérifié soi-même. Ce que vous trouverez ici à la place : l'architecture réelle de chaque outil, et la façon dont Aurabase route concrètement son trafic Postgres, vérifiée section par section dans le code source.

L'essentiel
  • PgBouncer (C) reste le pooler le plus éprouvé et le mieux intégré à Kubernetes : CloudNativePG s'appuie directement dessus pour sa ressource Pooler.
  • Supavisor (Elixir, projet Supabase) cible un problème différent : servir des milliers de bases tenant depuis un même service, plutôt qu'un pooler par base.
  • PgCat (Rust) ajoute au pooling brut du sharding applicatif, de l'équilibrage de charge entre réplicas et du failover automatique.
  • Le dépôt Aurabase montre PgBouncer utilisé à deux niveaux : un déploiement partagé pour la flotte mutualisée, et une ressource Pooler gérée par CloudNativePG par tenant dédié. Les deux tournent en mode transaction.
  • PostgREST et le pool d'administration d'aura-db restent volontairement en connexion directe sur Postgres, sans passer par le pooler : le transaction pooling casserait leur rechargement de schéma et leurs verrous de session.
#
Panorama

Trois poolers, trois philosophies

PgBouncer minimise, Supavisor mutualise à l'échelle du multi-tenant, PgCat ajoute des fonctions réseau au pooling brut. Aucun des trois n'est un remplacement direct des deux autres, même s'ils sont souvent comparés terme à terme sur les mêmes pages.

LangageCElixir (BEAM)Rust
Modes de poolingSession, transaction, statementSession, transactionSession, transaction, statement
Modèle de tenanceUn cluster cible par instance, pensé mono-tenantMulti-tenant natif : un service pour de nombreuses basesUn cluster cible, sharding par clé de partition
Au-delà du poolingAucune fonction annexe, volontairement minimalAPI HTTP d’admin, enregistrement dynamique des tenantsSharding, équilibrage de charge et failover entre réplicas
Intégration Kubernetes nativeOui : ressource Pooler de CloudNativePGNon documentée nativement à ce jourNon documentée nativement à ce jour
OrigineLe standard historique du pooling PostgresConstruit par Supabase pour son propre cloud multi-tenantNé chez Instacart, maintenu aujourd’hui par PostgresML

Colonnes, dans l'ordre : PgBouncer, Supavisor, PgCat. Caractéristiques d'architecture d'après les dépôts officiels de chaque projet, à confirmer sur la version que vous déployez, l'écosystème évoluant vite sur ce point.

#
PgBouncer

Le standard historique, léger et intégré à Kubernetes

PgBouncer ne fait qu'une chose : mutualiser des connexions Postgres, sans fonction annexe. Ce périmètre volontairement étroit explique en grande partie sa longévité et son adoption comme brique de base dans la plupart des stacks Postgres en production.

Trois modes de pooling sont disponibles. Le mode session ouvre une connexion serveur par connexion client, le plus permissif. Le mode transaction réutilise une connexion serveur entre plusieurs clients, libérée à chaque fin de transaction. Le mode statement va plus loin encore, et reste rarement utilisé en production. C'est le mode transaction qui apporte le vrai gain de mutualisation, mais il impose des règles strictes. Tout état de session (variables SET, verrous consultatifs, LISTEN/NOTIFY) ne survit pas au-delà d'une transaction. Nous détaillons ces règles et leurs pièges dans notre article dédié sur le mode transaction pooling de PgBouncer.

Historiquement mono-processus, une instance PgBouncer exploite un seul cœur CPU par défaut. Faire tourner plusieurs instances derrière le même port (via SO_REUSEPORT) est une évolution plus récente du projet, pas une caractéristique de conception initiale. Côté authentification, PgBouncer supporte un auth_query configurable, une fonction SQL exécutée à chaque connexion pour résoudre dynamiquement le mot de passe d'un rôle. Ce mécanisme évite de dépendre d'un fichier statique listant chaque utilisateur à l'avance. C'est exactement ce mécanisme qu'Aurabase utilise pour ses rôles par-projet (section 05).

Astuce
PgBouncer est le pooler que CloudNativePG déploie nativement derrière sa ressource Pooler. Sur un cluster Postgres géré par l'opérateur CloudNativePG, activer un pooler managé revient, en pratique, à activer PgBouncer sans le configurer à la main.
#
Supavisor

Le pooler multi-tenant cloud-native de Supabase

Supavisor répond à un problème que PgBouncer n'a jamais été conçu pour résoudre à cette échelle. Il s'agit de servir un très grand nombre de bases tenant distinctes depuis un service unique, plutôt qu'une instance de pooler par base. Écrit en Elixir et exécuté sur la machine virtuelle Erlang (BEAM), le projet est développé et maintenu par Supabase, en open source, sur son propre dépôt GitHub.

Le modèle multi-tenant natif est la vraie différence structurelle. Là où une flotte PgBouncer classique demande un process (ou un ensemble de connexions dédiées) par base cible, Supavisor fonctionne différemment. Il enregistre dynamiquement des tenants via une interface d'administration HTTP, et route chaque connexion entrante vers la bonne base sans redémarrer le service. Supabase a migré ses propres projets Cloud de PgBouncer vers Supavisor pour cette raison précise. Un cluster de pooling classique, un par base, ne passe pas à l'échelle d'un cloud multi-tenant qui héberge des centaines de milliers de projets.

Ce choix architectural a un revers documenté. La parité de fonctionnalités avec PgBouncer sur des cas avancés a mis du temps à se stabiliser après le lancement du projet. Deux exemples : certains comportements de LISTEN/NOTIFY, et la gestion fine des prepared statements en mode transaction. À vérifier sur votre version avant migration si votre application dépend de ces comportements précis.

#
PgCat

L'outsider Rust : sharding et load-balancing natifs

PgCat se positionne explicitement comme une alternative à PgBouncer, écrite en Rust. Il ajoute au pooling classique des fonctions réseau que ni PgBouncer ni Supavisor n'embarquent nativement. Trois en particulier : sharding applicatif par clé de partition, équilibrage de charge entre réplicas de lecture, et bascule automatique loin d'un réplica en échec. Le projet est né chez Instacart avant d'être repris et maintenu aujourd'hui par PostgresML.

Concrètement, PgCat peut jouer le rôle qu'occuperaient normalement deux couches distinctes : un pooler de connexions et un proxy applicatif de routage entre plusieurs instances Postgres. Une équipe qui shardait déjà ses données à la main peut simplifier son code avec PgCat. Même chose pour une logique de répartition des lectures entre réplicas développée en interne : une couche réseau dédiée la remplace directement.

Le compromis inverse existe aussi : PgCat est un projet plus jeune, avec un écosystème de documentation et de retours d'expérience en production nettement plus restreint que PgBouncer. Adopter ses fonctions de sharding et de failover, c'est aussi accepter de dépendre de la maturité de ce composant précis, pas seulement de sa capacité de pooling.

#
Vérifié dans le code

Ce que montre le code Aurabase : PgBouncer partout, sauf où le transaction pooling casse tout

Le dépôt Aurabase déploie PgBouncer à deux niveaux distincts, tous deux en mode transaction. Pour la flotte mutualisée, le chart Helm définit un déploiement PgBouncer dédié devant le data-plane partagé (deploy/helm/aurabase/templates/infra/pgbouncer.yaml, image edoburu/pgbouncer). Pour un tenant sur instance dédiée, le provisioner génère une ressource Pooler gérée nativement par CloudNativePG (deploy/cnpg/tenant-pooler.yaml, rendue par k8s_tenant.rs). Aucun des deux ne fait appel à Supavisor ni à PgCat. Le code ne documente pas de comparatif explicite ayant précédé ce choix. Il montre en revanche une intégration profonde et déjà opérationnelle avec l'écosystème CloudNativePG, cohérente avec le fait que PgBouncer en est la brique de pooling native.

transaction
MODE DE POOLING
Flotte partagée et pooler par tenant dédié
1000
MAX CLIENT CONN
Plafond clients simultanés, défaut chart Helm
80
DEFAULT POOL SIZE
Connexions serveur par (base, rôle), défaut chart Helm

Tout ne passe pourtant pas par le pooler, et c'est un choix délibéré documenté dans le code lui-même. PostgREST reste connecté en direct sur Postgres, jamais via PgBouncer. Le commentaire du chart Helm est explicite sur la raison : le transaction pooling casserait son rechargement de schéma, qui dépend d'un LISTEN sur le canal pgrst. Ce mécanisme est incompatible avec des connexions serveur recyclées entre clients. Le pool d'administration d'aura-db (schéma, DDL, verrous consultatifs de session) reste lui aussi en connexion directe, pour la même raison de fond. Un SET search_path non transaction-scoped et des verrous de session ne survivent pas à un pooler en mode transaction.

docker-compose.yml (extrait réel, commenté)
YAML
# Data-plane aura-db : via PgBouncer, tout est transaction-scoped (SET LOCAL)
DATABASE_URL: postgresql://aura_authenticator:...@pgbouncer:5432/aura_db_master
# Pool admin (DDL, introspection) : DIRECT sur Postgres, jamais PgBouncer
# SET search_path non-LOCAL + verrous de session cassent le transaction pooling
ADMIN_DATABASE_URL: postgresql://aura:...@postgres:5432/aura_db_master

L'authentification suit le pattern auth_query décrit en section 02 : AUTH_QUERY: SELECT * FROM pgbouncer.user_lookup($1), sans fichier userlist.txt statique. C'est ce qui permet aux rôles créés dynamiquement par projet (project_<uuid>_authenticator) de s'authentifier via PgBouncer sans redéployer le pooler à chaque nouveau projet.

Une leçon opérationnelle trouvée en écrivant cet article
Le commentaire du healthcheck PgBouncer dans docker-compose.yml documente un bug réel, déjà corrigé. Un pg_isready exécuté contre PgBouncer valide seulement la poignée de main du proxy, jamais la connexion réelle au backend Postgres qu'il relaie. PgBouncer répond « accepting connections » même backend arrêté, en mettant les requêtes en file d'attente. Résultat observé lors d'un test destructif : le service restait healthy pendant 5 cycles consécutifs alors que Postgres était injoignable. Le correctif remplace le check par une vraie requête psql de bout en bout à travers le pooler, jusqu'au backend. Résultat après correction, dans le même test rejoué : unhealthy détecté en 7 cycles, environ 35 secondes.

Un dernier détail, mineur mais révélateur : le chart Helm épingle edoburu/pgbouncer:v1.24.1-p1 par défaut, tandis que le docker-compose local utilise v1.25.2-p0. Ce n'est pas un choix architectural, juste un léger défaut de synchronisation de versions entre deux environnements, le genre de détail qu'une revue de code attrape plus vite qu'un article de blog. Nous le documentons tel quel plutôt que de le maquiller. Pour le détail du cloisonnement par schéma que ce pooler dessert, voir notre article sur l'isolation RLS multi-tenant.

#
Décision

Comment choisir entre les trois

Choisissez PgBouncer si…
  • Cluster Postgres géré par CloudNativePG ou Kubernetes en général
  • Vous voulez le pooler le plus éprouvé et le mieux documenté
  • Une base cible par instance de pooler vous convient
Choisissez Supavisor si…
  • Des centaines ou milliers de bases tenant derrière un même service
  • Besoin d’enregistrer des tenants dynamiquement via une API, sans redéploiement
  • Déjà dans l’écosystème Supabase ou disposé à en dépendre
Choisissez PgCat si…
  • Sharding applicatif déjà en place ou prévu au niveau du pooler
  • Équilibrage de charge et failover réplica sans couche applicative séparée
  • À l’aise avec un projet plus jeune, moins documenté que PgBouncer

Quel que soit le pooler retenu, il ne remplace pas le dimensionnement de Postgres lui-même. La taille du pool et le max_connections du serveur doivent être pensés ensemble, pas l'un après l'autre. Un pool généreux devant un max_connections trop bas se contente de déplacer la saturation d'un étage à l'autre. Notre guide sur le tuning de max_connections détaille la formule de dimensionnement à appliquer avant de fixer la taille de votre pool.

#
Questions fréquentes

Ce qu'on nous demande le plus souvent

PgBouncer et Pgpool-II, quelle différence ?+
Pgpool-II va au-delà du pooling de connexions : répartition de charge entre réplicas, cache de requêtes en mémoire, réplication applicative. PgBouncer, lui, ne fait qu'une chose : mutualiser les connexions. C'est en partie ce qui explique pourquoi il reste souvent choisi comme brique de base, complétée par d'autres outils si besoin, plutôt que remplacé par une plateforme plus large.
Peut-on utiliser PgBouncer avec Supabase ?+
Historiquement oui : Supabase s'appuyait sur PgBouncer avant de développer Supavisor. Les deux restent présentés dans leur documentation officielle selon le contexte de connexion : IPv4 direct, pooler transaction, pooler session. Ce point précis évolue vite, à vérifier au moment de configurer un projet.
PgCat gère-t-il les prepared statements en mode transaction ?+
Depuis sa version 1.21, PgBouncer suit et reprépare à la volée les prepared statements protocolaires en mode transaction, un comportement documenté dans le chart Helm d'Aurabase lui-même. PgCat revendique un support similaire côté serveur. Nous n'avons mesuré ni l'un ni l'autre en conditions de charge réelle, donc à vérifier sur votre propre trafic avant d'en faire un critère de choix décisif.
Supavisor est-il open source ?+
Oui, le dépôt est public sur GitHub (supabase/supavisor). C'est un projet distinct du cœur Postgres de Supabase, écrit en Elixir, pensé dès le départ pour le multi-tenant plutôt qu'adapté après coup.
#
En résumé

Il n'y a pas de pooler universel, seulement un bon fit pour votre tenance

PgBouncer, Supavisor et PgCat résolvent trois variantes du même problème, pas trois versions du même outil. PgBouncer reste le choix le plus sûr quand votre plateforme s'appuie déjà sur Kubernetes et CloudNativePG, ou quand vous voulez simplement le pooler le plus documenté. Supavisor devient pertinent au-delà d'un certain nombre de bases tenant à servir depuis un même service. PgCat vaut le détour si le sharding et le failover réplica vous manquent au niveau réseau, à condition d'accepter la maturité d'un projet plus jeune.

Le code Aurabase montre un choix cohérent, pas neutre : PgBouncer en mode transaction, à deux niveaux, flotte partagée et pooler CNPG par tenant dédié. Deux exceptions documentées subsistent, pour PostgREST et pour l'administration du schéma. Si vous voulez voir ce cloisonnement par projet à l'œuvre plutôt que sur le papier, notre page Performances documente la méthodologie de mesure associée.

ARCHITECTURE POSTGRES · POOLING

Un pooler géré, sans le configurer à la main.

PgBouncer en mode transaction, ressource CNPG par tenant dédié, rôles par-projet authentifiés dynamiquement. Créez un projet gratuit pour voir la topologie réelle.

Créer un projet gratuit Documentation Database
Aucune carte bancaire requise · 500 MB gratuits · 50 000 MAU