Mettre en ligne une API Node.js et sa base PostgreSQL depuis votre agent IA, par MCP
Votre agent IA sait déjà écrire votre API Node.js. Branché à while par MCP, il la met aussi en ligne, avec sa base PostgreSQL sauvegardée chaque jour, et vous ne touchez à aucun serveur.
Par Aloïs Oddon, cofondateur de Nextmap. Faits relevés le 2 novembre 2026.
Prérequis
- Une API Node.js.
- Un agent IA qui travaille dans un terminal : Claude Code, Codex, Cursor ou Gemini CLI.
Étape 1 : Donnez ces instructions à votre agent
Ouvrez votre agent dans le dossier de votre API, et collez-lui ces instructions :
Connecte-toi à while avec mon compte (while.sh/agents), puis mets mon appli en ligne.
Sans compte, votre agent met votre API en ligne à l’essai, en une demande. Pour la garder, ouvrez le lien qu’il vous donne et créez votre compte.
Avec votre compte, votre agent ajoute lui-même le serveur MCP de while. S’il vous le demande, relancez-le. Au premier appel à while, une page s’ouvre dans votre navigateur. Dans Claude Code, si elle ne s’ouvre pas, tapez /mcp, choisissez while, puis Authenticate. Sur cette page, choisissez votre appli, ou « Une nouvelle appli », puis cliquez sur Autoriser.
Étape 2 : Ouvrez votre API
Votre agent vous donne l’adresse de votre API, par exemple https://mon-api.while.cloud.
Ce que fait votre agent
Il lit les règles d’une appli sur while, comme écouter sur PORT et répondre 200 sur /health, puis écrit while.yaml à la racine de votre API :
apiVersion: while/v1
project: mon-api
services:
- name: web
port: 3000
databases:
- name: main
Les deux dernières lignes ajoutent une base PostgreSQL. Son adresse, mot de passe compris, arrive à votre API dans DATABASE_URL. node-postgres la lit telle quelle1, comme dans cette API Express essayée sur while :
import express from 'express';
import pg from 'pg';
const db = new pg.Pool({ connectionString: process.env.DATABASE_URL });
await db.query('CREATE TABLE IF NOT EXISTS visites (id serial PRIMARY KEY, cree_le timestamptz DEFAULT now())');
const app = express();
app.get('/health', (_req, res) => res.send('ok'));
app.get('/', async (_req, res) => {
await db.query('INSERT INTO visites DEFAULT VALUES');
const { rows } = await db.query('SELECT count(*)::int AS n FROM visites');
res.send(`visites : ${rows[0].n}`);
});
app.listen(process.env.PORT || 3000, '0.0.0.0');
Il envoie ensuite le code, qui est construit, testé, puis mis en ligne.
Choisir la version de PostgreSQL
Vous, à votre agent : Crée la base sous PostgreSQL 18.
La version se choisit à la création : PostgreSQL 17 par défaut, la 16 ou la 18 avec version dans while.yaml :
databases:
- name: main
version: "18"
Prévoir l’espace disque
Vous, à votre agent : Crée la base avec 10 Gio de disque.
Le disque se choisit à la création de la base, avec size : 1 Gio par défaut. Demandez-le avant la première mise en ligne.
databases:
- name: main
size: 10Gi
Utiliser Prisma avec PostgreSQL
Vous, à votre agent : Utilise Prisma pour créer et migrer les tables.
Votre agent écrit le schéma et fait jouer la migration au démarrage de l’API. Prisma lit l’adresse de la base dans DATABASE_URL :
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
"type": "module",
"scripts": {
"build": "prisma generate",
"start": "prisma migrate deploy && node server.js"
},
"dependencies": {
"@prisma/client": "^6.1.0",
"prisma": "^6.1.0"
}
Prisma va dans dependencies : l’API en ligne est installée sans les devDependencies. Inutile d’ajouter ?pgbouncer=true à l’adresse : PgBouncer suit les requêtes préparées.
Votre agent ne déclare pas de directUrl : l’adresse directe de la base n’est donnée qu’aux tâches, et Prisma s’arrêterait au démarrage avec l’erreur P1012.
Interroger PostgreSQL depuis votre agent, par MCP
Vous, à votre agent : Combien de visites aujourd’hui ?
Votre agent lit votre base en SQL par le serveur MCP de while, avec vos droits sur les données, sans pouvoir y écrire. Chaque requête est notée au journal de while, ses valeurs remplacées par $1, $2…
Exporter une table en CSV
Vous, à votre agent : Exporte la table visites en CSV.
Votre agent écrit la table dans un fichier CSV, avec les mêmes droits que pour la lire.
Trouver les requêtes lentes
Vous, à votre agent : Quelles requêtes ralentissent la base ?
Votre agent lit les requêtes les plus fréquentes et les plus lentes de votre base, relevées par pg_stat_statements.
Changer la taille de la base
Vous, à votre agent : Passe la base en taille M.
Votre agent change compute dans while.yaml. Avant le changement, il voit ce qu’il coûte en plus par mois. La base redémarre ensuite, en une quinzaine de secondes.
Taille (compute) | Processeur | Mémoire | Clients en même temps | Prix, hors taxes |
|---|---|---|---|---|
| S, par défaut | 0,1 vCPU | 256 Mo, jusqu’à 1 Go | 200 | 5 € par mois |
| M | 0,5 vCPU | 1 Go | 400 | 17 € par mois |
| L | 1 vCPU | 4 Go | 600 | 65 € par mois |
| XL | 2 vCPU | 8 Go | 800 | 150 € par mois |
databases:
- name: main
compute: M
Ajouter une instance de secours
Vous, à votre agent : Ajoute une instance de secours à la base.
Avec instances: 2, une seconde instance est tenue à jour en continu, sur son propre disque, et prend le relais si la première tombe. Avec l’offre Entreprise, une base de production a deux instances par défaut.
Sauvegarder avant un changement
Vous, à votre agent : Fais une sauvegarde avant la migration.
Votre agent lance une sauvegarde, aussitôt suivie d’un essai : une base jetable en naît, et ses tables sont relues. Chaque base est aussi sauvegardée tous les jours, et son journal est archivé en continu.
Revenir à une sauvegarde ou à une heure précise
Vous, à votre agent : Remets la base comme hier à 18 h.
Votre base revient à une sauvegarde ou à un instant précis, dans la limite de leur conservation : 14 jours. En production, votre agent vous donne un lien : la base ne revient qu’une fois la restauration validée, par vous ou par un administrateur selon vos droits. Une sauvegarde de sûreté part avant, puis la base restaurée prend la place de l’ancienne.
Comprendre une mise en ligne qui échoue
Vous, à votre agent : Pourquoi la mise en ligne a échoué ?
Votre agent reçoit l’erreur et les dernières lignes du journal de construction. Vos tests tournent pendant la construction : s’ils échouent, votre API garde sa version d’avant.
Par exemple, connect ECONNREFUSED 127.0.0.1:5432 : vos tests cherchent une base, qui n’est pas branchée pendant la construction. Votre agent les écrit pour qu’ils passent sans elle, ou les coupe :
services:
- name: web
port: 3000
build:
skip_tests: true
Régler la session derrière PgBouncer
DATABASE_URL passe par PgBouncer en mode transaction : chaque transaction peut prendre une autre connexion. Un SET hors transaction ne dure que sa requête. Pour régler la session, utilisez SET LOCAL dans une transaction :
const client = await db.connect();
try {
await client.query('BEGIN');
await client.query("SET LOCAL statement_timeout = '5s'");
await client.query('SELECT count(*) FROM visites');
await client.query('COMMIT');
} catch (e) {
await client.query('ROLLBACK');
throw e;
} finally {
client.release();
}
Ce qui a besoin de la session entière, comme pg_restore ou une migration qui fait des SET, tourne dans une tâche planifiée, que votre agent lance aussi à la demande. La tâche reçoit l’adresse directe de la base dans DB_MAIN_DIRECT_URL.
Dans la doc : Bases PostgreSQL, Services web, Cache Valkey (Redis), Tâches planifiées et Versions et retour arrière.
Prochaines étapes
Sources
- node-postgres, se connecter avec une adresse de connexion (connectionString), consulté le 1er novembre 2026