Skip to content

Deploy a Node.js API and its PostgreSQL database from your AI agent, over MCP

Your AI agent already knows how to write your Node.js API. Connected to while over MCP, it deploys it too, with its PostgreSQL database backed up every day, and you never touch a server.

By Aloïs Oddon, co-founder of Nextmap. Facts checked on November 2, 2026.

View as Markdown

Prerequisites

  • A Node.js API.
  • An AI agent that works in a terminal: Claude Code, Codex, Cursor or Gemini CLI.

Step 1: Give your agent these instructions

Open your agent in your API’s folder, and paste these instructions into it:

Instructions
Connect to while with my account (while.sh/agents), then deploy my app.

Without an account, your agent deploys your API as a trial, in one request. To keep it, open the link it gives you and create your account.

With your account, your agent adds while’s MCP server itself. If it asks you to, restart it. On the first call to while, a page opens in your browser. In Claude Code, if it doesn’t open, type /mcp, choose while, then Authenticate. On that page, choose your app, or “A new app”, then click Authorize.

Step 2: Open your API

Your agent gives you your API’s address, for example https://mon-api.while.cloud.

What your agent does

It reads the rules for an app on while, like listening on PORT and answering 200 on /health, then writes while.yaml at the root of your API:

while.yaml
apiVersion: while/v1
project: mon-api
services:
  - name: web
    port: 3000
databases:
  - name: main

The last two lines add a PostgreSQL database. Its address, password included, reaches your API in DATABASE_URL. node-postgres reads it as is1, as in this Express API tested on while:

server.js
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');

It then sends the code, which is built, tested, then deployed.

Choose the PostgreSQL version

You, to your agent: Create the database on PostgreSQL 18.

You choose the version when the database is created: PostgreSQL 17 by default, 16 or 18 with version in while.yaml:

while.yaml
databases:
  - name: main
    version: "18"

Plan the disk space

You, to your agent: Create the database with 10 GiB of disk.

You choose the disk when the database is created, with size: 1 GiB by default. Ask for it before the first deployment.

while.yaml
databases:
  - name: main
    size: 10Gi

Use Prisma with PostgreSQL

You, to your agent: Use Prisma to create and migrate the tables.

Your agent writes the schema and runs the migration when the API starts. Prisma reads the database address from DATABASE_URL:

prisma/schema.prisma
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}
package.json (excerpt)
"type": "module",
"scripts": {
  "build": "prisma generate",
  "start": "prisma migrate deploy && node server.js"
},
"dependencies": {
  "@prisma/client": "^6.1.0",
  "prisma": "^6.1.0"
}

Prisma goes in dependencies: the deployed API is installed without its devDependencies. There’s no need to add ?pgbouncer=true to the address: PgBouncer handles prepared statements.

Your agent doesn’t declare a directUrl: the database’s direct address is only given to jobs, and Prisma would stop at startup with error P1012.

Query PostgreSQL from your agent, over MCP

You, to your agent: How many visits today?

Your agent reads your database in SQL through while’s MCP server, with your permissions on the data, and it can’t write to it. Every query is recorded in while’s activity log, with its values replaced by $1, $2…

Export a table to CSV

You, to your agent: Export the visites table to CSV.

Your agent writes the table to a CSV file, with the same permissions it has to read it.

Find slow queries

You, to your agent: Which queries are slowing down the database?

Your agent reads your database’s most frequent and slowest queries, as recorded by pg_stat_statements.

Change the database size

You, to your agent: Move the database to size M.

Your agent changes compute in while.yaml. Before the change, it sees how much more it costs per month. The database then restarts, in about fifteen seconds.

Size (compute)CPUMemoryConcurrent clientsPrice, excl. VAT
S, by default0.1 vCPU256 MB, up to 1 GB200€5 per month
M0.5 vCPU1 GB400€17 per month
L1 vCPU4 GB600€65 per month
XL2 vCPU8 GB800€150 per month
while.yaml
databases:
  - name: main
    compute: M

Add a standby instance

You, to your agent: Add a standby instance to the database.

With instances: 2, a second instance is kept up to date continuously, on its own disk, and takes over if the first one goes down. With the Enterprise plan, a production database has two instances by default.

Back up before a change

You, to your agent: Take a backup before the migration.

Your agent starts a backup, immediately followed by a test: a throwaway database is created from it, and its tables are read back. Every database is also backed up every day, and its write-ahead log is archived continuously.

Go back to a backup or a precise time

You, to your agent: Restore the database to yesterday at 6 pm.

Your database goes back to a backup or to a precise moment, within their retention period: 14 days. In production, your agent gives you a link: the database only goes back once the restore is approved, by you or by an administrator depending on your permissions. A safety backup is taken first, then the restored database replaces the old one.

Understand a failed deployment

You, to your agent: Why did the deployment fail?

Your agent receives the error and the last lines of the build log. Your tests run during the build: if they fail, your API keeps its previous version.

For example, connect ECONNREFUSED 127.0.0.1:5432: your tests are looking for a database, which isn’t connected during the build. Your agent writes them so they pass without it, or turns them off:

while.yaml
services:
  - name: web
    port: 3000
    build:
      skip_tests: true

Configure the session behind PgBouncer

DATABASE_URL goes through PgBouncer in transaction mode: each transaction can use a different connection. A SET outside a transaction only lasts for its query. To configure the session, use SET LOCAL inside a transaction:

server.js
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();
}

Anything that needs the whole session, like pg_restore or a migration that runs SET commands, runs in a scheduled job, which your agent can also start on demand. The job receives the database’s direct address in DB_MAIN_DIRECT_URL.

In the docs: PostgreSQL databases, Web service, Valkey cache (Redis), Scheduled jobs and Versions and rollback.

Next steps

Sources

  1. node-postgres, connecting with a connection string (connectionString), accessed November 1, 2026

Questions

How much does a Node.js API with its database cost on while?

With the Free plan, you only pay for resources, excl. VAT: €5 per month for an S database, plus €0.25 per GiB of disk, and for the API, €17 per vCPU and €8.50 per GiB of memory, per month, based on what it uses. An API that uses at most 0.25 vCPU and 0.5 GiB of memory pays at most €8.50 per month, and €13.75 with an S database and its 1 GiB disk.

Where is my API hosted?

In France, by Nextmap, a French company.

Does my API go to sleep when nobody calls it?

No, in production it stays awake. With sleep: 30m in while.yaml, it goes to sleep after 30 minutes without a request, and the first request wakes it up in a few seconds.

Can I put my API on my own domain?

Yes. Your agent declares the domain, you add the two DNS records it gives you, and the HTTPS certificate is issued on the first visit.

Where do I put my API’s keys and passwords?

Never in the code. The key for an external API is entered in while and added to each call: neither your API nor your agent sees it. Other secrets go into while’s vault.

Can I run background processing?

Yes. Ask your agent for a worker, for processing that runs nonstop, or a scheduled job, for work at a set time.

I’m on Heroku or Render: how do I move over?

Your agent takes over the code, copies the database from a Heroku or Render export (pg_dump), restored by a job, and carries over your environment variables.

Can I use Express, Fastify or NestJS?

Yes, any Node.js server that starts with a script in its package.json: start, or start:prod for NestJS. Express and NestJS have already been deployed to production on while.

Can I open my database in pgAdmin or with psql?

No, the database doesn’t open from your computer: your agent reads it and exports it for you.

Do I need to set SSL in the database address?

No, the DATABASE_URL address works as is, without sslmode.

Do I need to write a Dockerfile?

No. Without a Dockerfile in your repository, while generates one for your API.

Connect your agent, it takes care of the rest

To paste into your agent

Read while.sh/agents, then deploy my app with while.

Copy the instructions

No account needed to try: your app is live right away. To keep it, sign in.

A project for your company? Talk to the team: hello@while.sh