An open-source, self-hosted BullMQ dashboard built with TanStack Start, shadcn/ui, and Better Auth.
- Queue monitoring — view all BullMQ queues with job counts per status
- Job management — retry failed jobs, remove jobs, clean queues
- Lifecycle timeline — per-job wait/run/finish durations at a glance
- Auto-discovery — automatically discovers queues by scanning Redis keys
- Dark mode — system preference aware, persisted to localStorage
- Authentication — login protected with Better Auth (email/password)
- Real-time — auto-refresh every 3s with TanStack Query
| Layer | Tech |
|---|---|
| Framework | TanStack Start (React SSR, Node.js) |
| Routing | TanStack Router (file-based) |
| Data fetching | TanStack Query |
| UI components | shadcn/ui (New York, Zinc, Tailwind v4) |
| Auth | Better Auth |
| Database (auth only) | Prisma + SQLite |
| Queue | BullMQ + ioredis |
- Node.js 20+
- A running Redis instance with BullMQ queues
git clone https://github.com/your-org/sleek-bull-dash
cd sleek-bull-dash
npm installEdit .env.local:
# Authentication
BETTER_AUTH_SECRET=<generate with: npx @better-auth/cli secret>
BETTER_AUTH_URL=http://localhost:3001
# Database (stores user accounts and sessions)
DATABASE_URL="file:./dev.db"
# Redis connection
REDIS_URL=redis://localhost:6379
# Queue names — leave empty to auto-discover from Redis
BULLMQ_QUEUES=# Generate Prisma client
npm run db:generate
# Push auth tables to SQLite
npm run db:pushnpm run devOpen http://localhost:3001.
Public sign-up is disabled. Create users in Prisma Studio:
npm run db:studioThen create:
- one row in
User - one row in
Account
For the Account row, use:
providerId = credentialaccountId = <same value as the user id>userId = <the user id from User>password = <hashed password, not plaintext>
Generate a Better Auth-compatible password hash with:
node --input-type=module -e "import { randomBytes, scrypt as scryptCallback } from 'node:crypto'; import { promisify } from 'node:util'; const scrypt = promisify(scryptCallback); const salt = randomBytes(16).toString('hex'); const key = await scrypt('changeme123'.normalize('NFKC'), salt, 64, { N: 16384, r: 16, p: 1, maxmem: 128 * 16384 * 16 * 2 }); console.log(salt + ':' + key.toString('hex'));"Notes:
- Passwords must be at least 8 characters.
Account.passwordmust store the generated hash, not the raw password.- After creating the user, sign in at http://localhost:3001/login.
If BULLMQ_QUEUES is not set, the dashboard scans Redis for *:meta keys to auto-discover queues. Works with both bull:name and {bull:name} (Redis Cluster) key patterns.
For explicit control (recommended in production):
BULLMQ_QUEUES=payments,emails,notificationsnpm run dev # start dev server
npm run build # production build
npm run start # run production build
npm run lint # biome lint
npm run check # biome check (lint + format)
npm run db:generate # regenerate Prisma client after schema changes
npm run db:push # push schema changes to database
npm run storybook # component developmentContributions are welcome! See CONTRIBUTING.md for setup instructions, code conventions, and the pull request process.
MIT