I was searching for a WhatsApp message scheduler (without using WhatsApp Business API), but couldn’t find anything suitable—so I decided to build one myself.
🔧 What I Wanted to Build
- Create, edit, and delete scheduled messages
- Set a "Send After (in days)" timer
- Reschedule the timer with one click
It seemed like a simple project, but turned out to be pretty tricky. Here's how I tackled it.
❌ Why Not node-schedule
or setInterval
?
Basic solutions like node-schedule
or setInterval
don’t offer the reliability I wanted. So I turned to bullmq
, which uses Redis for job management.
I'm using:
-
Prisma
+SQLite
for tracking messages & schedules -
whatsapp-web.js
as an unofficial WhatsApp client - Backend:
Bun
+Hono
🗂️ Backend Structure
- Backend repo: bun-hono-backend-optimized
- Frontend repo: bun-hono-frontend-nextjs
Backend Breakdown
📦 Dependencies
{
"dependencies": {
"bullmq": "^5.45.0",
"hono": "^4.7.5",
"prisma": "^6.5.0",
"ioredis": "^5.6.0",
"whatsapp-web.js": "^1.27.0",
"qrcode-terminal": "^0.12.0",
"@prisma/client": "^6.5.0"
}
}
🧠 Prisma Schema
I have three models: AdminProfile
, People
, and Message
. Here's the Message Model.
model Message {
id String @id @default(cuid())
content String
sendTo People @relation(fields: [sendToPhone], references: [phone])
sendToPhone String
sendAfter Float @default(0)
createdAt DateTime @default(now())
}
🔐 Basic Auth
Used Hono
's built-in basic-auth with minimal setup:
new Hono().use(
basicAuth({
username: Bun.env.USERNAME || "user",
password: Bun.env.PASSWORD || "pass",
})
);
📨 Message Queue with BullMQ
import { Queue } from "bullmq";
export const messageQueue = new Queue("messageQueue", {
connection: {
url: process.env.REDIS_REST_URL,
maxRetriesPerRequest: null,
},
});
🗓 Scheduling Messages
This runs after every create/edit/delete operation.
await messageQueue.add(
jobId,
{ content: message.content, sendToPhone: message.sendToPhone },
{ jobId, delay: sendAfterMs }
);
Also added a reminder message if messages aren't rescheduled in time 👇
messageQueue.add("message-reschedule", {
content: "You have 3.5 hours left to reschedule messages or I think you are dead",
sendToPhone: "8801884510919",
}, { delay: timeLeft - 3.5 * 3600 * 1000 });
📲 WhatsApp Client (wweb.js
)
import { Client, LocalAuth } from "whatsapp-web.js";
const client = new Client({ authStrategy: new LocalAuth() });
const sendMessage = async (phone: string, message: string) => {
client.sendMessage(`${phone}@c.us`, message);
};
👷 Worker: Auto Sync with Schedule
const worker = new Worker(
"messageQueue",
async (job) => {
await sendMessage(job.data.sendToPhone, job.data.content);
},
{ connection: redisConfig, concurrency: 1 }
);
🖼️ Frontend (Minimal but Functional)
The frontend is just a simple interface built using:
Next.js
Shadcn UI
- Server Actions to talk to the backend
✨ TL;DR
I built a WhatsApp scheduler using:
- Bun + Hono for the backend
- BullMQ for reliable message queuing
- Prisma + SQLite for storing schedules
- wweb.js for sending WhatsApp messages
- Next.js frontend (barebones, but it works)
💬 Final Words
Still a work in progress, but it’s functional and fun to build.
Would love to hear thoughts, improvements, or just a “cool project” 😄