Every bot
Runtime
- Node.js 22 or later, and your app is ESM (
"type": "module"inpackage.json, or.mjsfiles). The packages ship no CommonJS build. - A process manager restarts the bot when it exits: PM2, systemd,
Docker
restart: unless-stoppedor your orchestrator. See Deployment. - Graceful shutdown: on
SIGTERM/SIGINTcallawait bot.stop({ drain: true, timeout: '15s' })so replies in flight are sent and recorded before the process exits (Graceful shutdown). - Pin your versions (commit the lockfile). While the packages are in beta, read the migration pages before each upgrade.
State
- A persistent store. The default
MemoryStorekeeps everything in RAM. UseSQLiteStorefor one process orRedisStorefor several (Persistent store). - Pass the store instance:
store: new SQLiteStore({ file }). A string such asstore: 'sqlite'is accepted for compatibility but still creates aMemoryStore. - Multi-step flows are
.persistent(), so a user in the middle of a flow resumes it after a restart (Flows). - On Node.js 24.19 or later, use
better-sqlite313 withSQLiteStore(why). - Volumes and backups: the WhatsApp session folder (
sessions/) and the data folder (data/) are mounted on persistent disk and backed up together (Backups).
Secrets
- Tokens, API keys and webhook secrets come from the environment (or your secret manager), never from the source tree. The framework reads no environment variable by itself: you map them to the provider options (Environment variables).
sessions/,.env,*.dband*.qr.pngare in.gitignoreand never copied into a Docker image.
Webhooks (Cloud API, Telegram webhook, Twilio…)
- Served over HTTPS, with the channel’s signature check configured
(
appSecret,webhookSecret…). Never setallowUnsignedWebhooks: truein production (Security). - The signature is checked on the raw body: do not put a JSON body parser in front of the webhook route (Webhook server).
Observability
- Logs: pass your own pino
logger(or keep the built-in one, which logs atwarn). Chat and sender ids are hashed in log lines by default (logIds: 'hash'); keep it that way outside local debugging. - Errors: listen to
bot.on('error', …)and send them to your error tracker. - Health and metrics: expose a liveness/readiness endpoint and
bot.metrics()in Prometheus format (Health checks, Operations).
Channel limits
- WhatsApp on Baileys: keep the provider’s rate limiter on and avoid unsolicited bulk sends (Rate limiting).
- Cloud API: free-form replies only within the 24-hour window; use templates outside it (WhatsApp 24h window).
- Message log growth: the persistent stores keep every message unless
you set
maxMessagesPerChat(Persistent store).
When you need more
All of these are opt-in: without the option, the bot runs exactly as before.
Which packages are published
The 36 public packages are on npm; a few pages also describe private packages that live only in the monorepo (the TikTok channel,@botmesh/manager, the
sandbox…), and each of those pages says so. The full list, with npm tags and
install commands, is in Packages and versions. Plan a
production deployment on the published ones.
Before each release of your bot
- Tests pass with
createTestBot/MockProvider(Testing). - The store files or databases are backed up before upgrading
@botmesh/sqlite-store: a newer schema version cannot be opened by an older release (Schema versions). - With replicas, every replica runs a version that understands the options
you turn on (for example
coordination.handover.flows: 'forward').