Next.js starter your AI actually understands. Ship internal tools in days not weeks. Pre-order $199 $499 → [Get it now]

How to use Agenda scheduler in Node.js

Agenda is a lightweight job scheduling library for Node.js that stores jobs in MongoDB, providing persistence across restarts. As the creator of CoreUI with over 10 years of Node.js experience since 2014, I’ve used Agenda for email campaigns, report generation, and recurring maintenance tasks in production applications. The standard approach defines job processors, schedules jobs with cron expressions or intervals, and monitors execution with event listeners. This provides durable scheduled task execution with minimal overhead.

Install Agenda and connect it to MongoDB.

npm install agenda
const { Agenda } = require('agenda')

const agenda = new Agenda({
  db: {
    address: 'mongodb://localhost:27017/agenda',
    collection: 'jobs'
  }
})

agenda.define('send welcome email', async (job) => {
  const { userId, email } = job.attrs.data
  console.log(`Sending welcome email to ${email}`)
  await sendEmail(email, 'Welcome!', 'Welcome to our platform.')
})

;(async () => {
  await agenda.start()
  await agenda.schedule('in 5 minutes', 'send welcome email', {
    userId: '123',
    email: '[email protected]'
  })
})()

async function sendEmail(to, subject, body) {
  console.log(`Email sent to ${to}: ${subject}`)
}

agenda.define registers a job processor. agenda.start() begins processing. agenda.schedule creates a one-time job. Job data is persisted to MongoDB, surviving server restarts.

Recurring Jobs with Cron

Schedule jobs that repeat on a cron schedule.

const { Agenda } = require('agenda')

const agenda = new Agenda({
  db: { address: 'mongodb://localhost:27017/agenda' }
})

agenda.define('daily report', async (job) => {
  console.log('Generating daily report...')
  await generateReport()
})

agenda.define('cleanup old sessions', async (job) => {
  console.log('Cleaning up sessions older than 30 days...')
  await cleanupSessions()
})

;(async () => {
  await agenda.start()

  await agenda.every('0 9 * * 1-5', 'daily report')
  await agenda.every('0 2 * * *', 'cleanup old sessions')

  console.log('Scheduler started')
})()

async function generateReport() {
  await new Promise(resolve => setTimeout(resolve, 2000))
}

async function cleanupSessions() {
  await new Promise(resolve => setTimeout(resolve, 500))
}

agenda.every schedules recurring jobs. The first argument is a cron expression. 0 9 * * 1-5 runs at 9 AM on weekdays. 0 2 * * * runs at 2 AM daily. Jobs persist in MongoDB so schedules survive restarts.

Job Priorities and Concurrency

Control how many jobs run simultaneously.

const agenda = new Agenda({
  db: { address: 'mongodb://localhost:27017/agenda' },
  maxConcurrency: 20,
  defaultConcurrency: 5,
  lockLimit: 10
})

agenda.define('high priority task', { priority: 'high', concurrency: 1 }, async (job) => {
  console.log('Running high priority task')
})

agenda.define('bulk email', { priority: 'low', concurrency: 3 }, async (job) => {
  const { batch } = job.attrs.data
  console.log(`Sending bulk email batch ${batch}`)
})

priority controls job order in the queue. concurrency limits simultaneous instances of one job type. maxConcurrency caps total concurrent jobs. Tune these to prevent overloading your server.

Handling Job Failures

Monitor and retry failed jobs.

agenda.define('process payment', {
  attempts: 3,
  backoff: { type: 'fixed', delay: 60000 }
}, async (job) => {
  const { paymentId } = job.attrs.data

  if (Math.random() < 0.2) {
    throw new Error('Payment gateway timeout')
  }

  console.log(`Payment ${paymentId} processed`)
})

agenda.on('fail:process payment', (err, job) => {
  console.error(`Payment job failed: ${err.message}`)
  console.error('Job data:', job.attrs.data)
})

agenda.on('complete:process payment', (job) => {
  console.log(`Payment job completed for ${job.attrs.data.paymentId}`)
})

attempts retries failed jobs automatically. backoff adds delay between retries. Event listeners track failures and completions. Failed jobs stay in MongoDB for inspection and manual retry.

Best Practice Note

This is the same Agenda pattern we use in CoreUI backend services for scheduled maintenance and notification tasks. Always run agenda.start() on application boot and agenda.stop() on graceful shutdown to avoid orphaned locks. Use agenda.cancel() to remove obsolete jobs when changing schedules. Monitor the jobs collection in MongoDB to track execution history. For high-throughput scenarios, consider Bull with Redis instead - Agenda is excellent for moderate workloads where MongoDB is already in your stack. Define job names as constants to avoid typos across your codebase.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author

Subscribe to our newsletter
Get early information about new products, product updates and blog posts.

Answers by CoreUI Core Team