The standard @whiskeysockets/baileys tutorial assumes one thing: You are building a bot for yourself.
You run the script, a QR code prints in your terminal, you pull out your phone, scan it, and the bot runs forever. But what happens when you want to build a B2B SaaS platform (like a CRM or a multi-school EdTech platform) where 100 different clients need to connect their own WhatsApp numbers?
You cannot SSH into your server 100 times to scan 100 terminal QR codes. You need a multi-tenant architecture.
1. The Core Limitation of makeWASocket
A single makeWASocket call represents a single WhatsApp Web session. It cannot multiplex different accounts. If you have 50 clients, you need 50 distinct sockets running in Node.js.
Furthermore, the default useMultiFileAuthState writes cryptographic keys to the local file system (e.g., ./auth_info). In a scalable SaaS environment where your Node.js servers are ephemeral containers (like Docker on AWS ECS or Kubernetes), local files will be destroyed when the container restarts, disconnecting all 50 clients instantly.
2. Moving Auth State to the Database
To scale, the authentication state must be decoupled from the file system.
You must write a custom AuthState adapter that reads and writes the Baileys cryptographic keys to a central database like PostgreSQL or Redis.
When a container boots up, it queries the database: "Which clients are assigned to me?" It fetches their cryptographic keys, and instantiates 10 makeWASocket connections in a for loop, passing the database-backed auth state to each.
// Conceptual Multi-Tenant Boot
const clients = await db.getClientsAssignedToNode(process.env.NODE_ID);
for (const client of clients) {
const authState = await usePostgresAuthState(client.id, db);
const sock = makeWASocket({
auth: authState.state,
// ... configuration
});
sock.ev.on('creds.update', authState.saveCreds);
// Store active sockets in a Map for routing outgoing messages
activeSockets.set(client.id, sock);
}
3. Dynamic QR Code Provisioning
When a new user signs up on your web dashboard and clicks "Connect WhatsApp", your system must:
- Send an HTTP request to your Node.js cluster:
POST /api/provision-socket - The Node.js cluster instantiates a temporary
makeWASocketin memory. - The cluster captures the
connection.updateevent and extracts the rawqrstring. - The cluster streams that
qrstring back to your web frontend via WebSockets or Server-Sent Events (SSE). - The frontend renders the QR code using a library like
qrcode.react. - When the user scans it, the Node.js socket fires
connection: 'open', saves the final keys to Postgres, and moves the socket into the permanentactiveSocketspool.
4. Horizontal Scaling Limits
A single Node.js process can comfortably maintain hundreds of idle WebSocket connections, but if all 500 clients receive high message volume simultaneously, the single thread will block, and latency will spike.
At this scale, you introduce a Message Broker (Redis/RabbitMQ).
- The Node.js WhatsApp Gateways do absolutely no processing. They just push raw JSON payloads into a Redis queue.
- A separate fleet of auto-scaling worker nodes pulls from the queue, processes the business logic, and pushes the reply back into an "Outgoing" queue.
Summary
Scaling WhatsApp bots requires abandoning the local file system and the terminal. By backing your authentication state with a central database and building dynamic QR provisioning streams, you can transform a single-user script into a massive, multi-tenant CRM engine.