
How to Replace Baileys with whatsmeow-node
If you're using Baileys and running into maintenance issues, fork instability, or want a more reliable upstream, whatsmeow-node is a drop-in alternative with a similar API surface. This guide maps the key concepts and shows you how to migrate.
Why Migrate?
- Stable upstream — whatsmeow is maintained by the Mautrix team and used in production by thousands of Matrix bridges 24/7. When WhatsApp changes their protocol, fixes land fast.
- No fork roulette — Baileys has gone through multiple forks (adiwajshing → WhiskeySockets → others). whatsmeow-node wraps one stable Go library.
- Lower memory — ~10-20 MB vs ~50 MB typical for Baileys.
- Typed API — 100+ typed async methods with TypeScript-first design.
See the full Comparison with Alternatives for details.
Step 1: Install
# Remove Baileys
npm uninstall @whiskeysockets/baileys
# Install whatsmeow-node
npm install @whatsmeow-node/whatsmeow-node
Step 2: Update Client Initialization
Baileys
import makeWASocket, { useMultiFileAuthState } from "@whiskeysockets/baileys";
const { state, saveCreds } = await useMultiFileAuthState("auth_info");
const sock = makeWASocket({ auth: state });
sock.ev.on("creds.update", saveCreds);
whatsmeow-node
import { createClient } from "@whatsmeow-node/whatsmeow-node";
const client = createClient({ store: "session.db" });
const { jid } = await client.init();
await client.connect();
Session persistence is automatic — no saveCreds callback needed. The store option accepts a file path (SQLite) or a PostgreSQL connection string.
You'll need to re-pair (scan QR code) after switching. Baileys auth state is not compatible with whatsmeow sessions.
Step 3: Update Event Listeners
Messages
Baileys:
sock.ev.on("messages.upsert", ({ messages }) => {
for (const msg of messages) {
if (msg.key.fromMe) continue;
const text = msg.message?.conversation
?? msg.message?.extendedTextMessage?.text;
console.log(`${msg.pushName}: ${text}`);
}
});
whatsmeow-node:
client.on("message", ({ info, message }) => {
if (info.isFromMe) return;
const text =
(message.conversation as string) ??
(message.extendedTextMessage as { text?: string } | undefined)?.text;
console.log(`${info.pushName}: ${text}`);
});
Key differences:
- Single message per event (not batched)
- Message metadata is in
info, protobuf content is inmessage info.isFromMereplacesmsg.key.fromMeinfo.chatreplacesmsg.key.remoteJidinfo.senderreplacesmsg.key.participant(in groups)
Connection
Baileys:
sock.ev.on("connection.update", ({ connection, lastDisconnect }) => {
if (connection === "open") console.log("Connected!");
if (connection === "close") { /* handle reconnection */ }
});
whatsmeow-node:
client.on("connected", ({ jid }) => console.log(`Connected as ${jid}`));
client.on("disconnected", () => console.log("Disconnected"));
client.on("logged_out", ({ reason }) => console.error(`Logged out: ${reason}`));
You don't need manual reconnection logic — whatsmeow handles it automatically.
Step 4: Update Message Sending
Text message
Baileys:
await sock.sendMessage(jid, { text: "Hello!" });
whatsmeow-node:
await client.sendMessage(jid, { conversation: "Hello!" });
Reply with quote
Baileys:
await sock.sendMessage(jid, { text: "Reply!" }, { quoted: msg });
whatsmeow-node:
await client.sendRawMessage(jid, {
extendedTextMessage: {
text: "Reply!",
contextInfo: {
stanzaId: info.id,
participant: info.sender,
quotedMessage: { conversation: originalText },
},
},
});
Media
Baileys:
await sock.sendMessage(jid, {
image: { url: "/path/to/photo.jpg" },
caption: "Check this out",
});
whatsmeow-node:
const media = await client.uploadMedia("/path/to/photo.jpg", "image");
await client.sendRawMessage(jid, {
imageMessage: {
URL: media.URL,
directPath: media.directPath,
mediaKey: media.mediaKey,
fileEncSHA256: media.fileEncSHA256,
fileSHA256: media.fileSHA256,
fileLength: String(media.fileLength),
mimetype: "image/jpeg",
caption: "Check this out",
},
});
Media upload and sending are separate steps in whatsmeow-node. This gives you more control (e.g., upload once, send to multiple chats).
Reactions
Baileys:
await sock.sendMessage(jid, { react: { text: "👍", key: msg.key } });
whatsmeow-node:
await client.sendReaction(jid, senderJid, messageId, "👍");
Step 5: Update Group Operations
| Baileys | whatsmeow-node |
|---|---|
sock.groupCreate(name, members) | client.createGroup(name, members) |
sock.groupMetadata(jid) | client.getGroupInfo(jid) |
sock.groupFetchAllParticipating() | client.getJoinedGroups() |
sock.groupUpdateSubject(jid, name) | client.setGroupName(jid, name) |
sock.groupUpdateDescription(jid, desc) | client.setGroupDescription(jid, desc) |
sock.groupSettingUpdate(jid, "announcement") | client.setGroupAnnounce(jid, true) |
sock.groupParticipantsUpdate(jid, [jid], "add") | client.updateGroupParticipants(jid, [jid], "add") |
sock.groupInviteCode(jid) | client.getGroupInviteLink(jid) |
sock.groupLeave(jid) | client.leaveGroup(jid) |
API Quick Reference
| Baileys | whatsmeow-node |
|---|---|
makeWASocket() | createClient() |
sock.sendMessage(jid, content) | client.sendMessage(jid, content) |
sock.readMessages([key]) | client.markRead([id], chat, sender) |
sock.sendPresenceUpdate("available") | client.sendPresence("available") |
sock.presenceSubscribe(jid) | client.subscribePresence(jid) |
sock.profilePictureUrl(jid) | client.getProfilePicture(jid) |
sock.updateBlockStatus(jid, "block") | client.updateBlocklist(jid, "block") |
sock.logout() | client.logout() |
Migration Checklist
- Install
@whatsmeow-node/whatsmeow-node, remove@whiskeysockets/baileys - Replace
makeWASocket→createClient - Remove
useMultiFileAuthState— session is handled automatically - Update event listeners (
ev.on→client.on, different event names) - Update
sendMessagecalls (text→conversation) - Update media sending (separate upload + send steps)
- Update group operations (method names differ slightly)
- Remove manual reconnection logic — whatsmeow auto-reconnects
- Re-pair via QR code (new session required)
- Test all message types end-to-end
Common Pitfalls
Baileys auth state cannot be migrated. You must pair a new session by scanning the QR code. Your WhatsApp chat history and contacts are unaffected — only the device link is new.
text vs conversationBaileys uses { text: "..." } for messages. whatsmeow-node uses { conversation: "..." } — matching the WhatsApp protobuf field name.
Upload response fields use exact protobuf casing: URL, fileSHA256, fileEncSHA256 — not camelCase. Using wrong casing silently fails.





