agenda vs cron vs later vs node-schedule
Node.js Task Scheduling Libraries
agendacronlaternode-scheduleSimilar Packages:

Node.js Task Scheduling Libraries

Task scheduling libraries in Node.js provide developers with the ability to execute code at specific intervals or times, facilitating automation and background processing in applications. These libraries help manage recurring tasks, delayed executions, and one-time jobs, enhancing the efficiency and performance of applications by offloading tasks that do not need to run in real-time. Each library offers unique features, syntax, and capabilities, making them suitable for different use cases in web development.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
agenda09,649295 kB2a month agoMIT
cron08,916161 kB254 months agoMIT
later02,418-9810 years agoMIT
node-schedule09,22135 kB1713 years agoMIT

Feature Comparison: agenda vs cron vs later vs node-schedule

Scheduling Syntax

  • agenda:

    Agenda uses a fluent API for defining jobs, allowing for easy configuration and management of job schedules. It supports a variety of scheduling options, including recurring jobs and delayed executions, making it intuitive for developers familiar with MongoDB.

  • cron:

    Cron employs a simple and familiar cron syntax (e.g., '0 * * * *') for scheduling tasks, which is widely recognized in the Unix/Linux community. This makes it easy for developers to quickly set up and understand job schedules.

  • later:

    Later provides a more flexible syntax that allows for complex scheduling scenarios, including intervals and specific dates. It supports human-readable expressions, making it easier to define intricate schedules without deep technical knowledge.

  • node-schedule:

    Node-Schedule allows scheduling using both cron syntax and JavaScript Date objects, providing flexibility in how tasks are defined. This dual approach caters to developers who prefer either method for scheduling.

Persistence and Reliability

  • agenda:

    Agenda excels in job persistence, storing job details in MongoDB, which ensures that jobs are not lost even if the application crashes. It also supports job retries and concurrency, enhancing reliability in task execution.

  • cron:

    Cron does not provide built-in job persistence; if the application crashes, scheduled jobs may be lost. It's best suited for lightweight tasks that do not require persistence or reliability.

  • later:

    Later does not inherently support job persistence, focusing instead on in-memory scheduling. This makes it less reliable for long-running applications unless combined with additional persistence mechanisms.

  • node-schedule:

    Node-Schedule also lacks built-in persistence, relying on in-memory scheduling. It is suitable for short-lived tasks but may require additional handling for reliability in long-running applications.

Complexity and Learning Curve

  • agenda:

    Agenda has a moderate learning curve due to its integration with MongoDB and the need to understand job management concepts. However, its API is well-documented and intuitive for developers familiar with database interactions.

  • cron:

    Cron is very easy to learn, especially for those familiar with Unix/Linux systems. Its straightforward syntax allows developers to quickly implement basic scheduling without much overhead.

  • later:

    Later has a slightly steeper learning curve due to its flexible syntax and advanced scheduling capabilities. Developers may need to invest time in understanding its features to fully leverage its potential.

  • node-schedule:

    Node-Schedule is relatively easy to learn, especially for those familiar with JavaScript. Its dual scheduling methods provide flexibility, but understanding the nuances of each method may take some time.

Use Cases

  • agenda:

    Agenda is ideal for applications that require complex job management, such as background processing, email notifications, and data synchronization tasks that need to be persistent and reliable.

  • cron:

    Cron is best suited for simple, recurring tasks like cleaning up temporary files, sending periodic reports, or executing maintenance scripts that do not require persistence.

  • later:

    Later is perfect for applications that need advanced scheduling capabilities, such as event-driven architectures or applications that require precise timing for tasks based on user interactions.

  • node-schedule:

    Node-Schedule is versatile for various use cases, including scheduled API calls, automated data processing, and any task that can benefit from either cron-like scheduling or JavaScript Date-based scheduling.

Community and Support

  • agenda:

    Agenda has a strong community and good documentation, making it easier for developers to find support and examples. Its integration with MongoDB also means that many developers are familiar with its usage.

  • cron:

    Cron is widely used and has a large community, providing ample resources and examples for developers. Its simplicity contributes to its popularity and ease of adoption.

  • later:

    Later has a smaller community compared to others, but it is well-documented. Developers may find fewer resources, but the library's flexibility compensates for this.

  • node-schedule:

    Node-Schedule has a decent community and is well-documented, making it accessible for developers. Its versatility ensures that it is used in various projects, leading to a growing number of shared resources.

How to Choose: agenda vs cron vs later vs node-schedule

  • agenda:

    Choose Agenda if you need a robust job scheduling library that integrates seamlessly with MongoDB and supports job persistence, retries, and concurrency. It's ideal for applications that require complex job management and monitoring.

  • cron:

    Select Cron if you prefer a simple syntax for scheduling tasks using cron-like expressions. It's lightweight and straightforward, making it suitable for basic scheduling needs without additional overhead.

  • later:

    Opt for Later if you need a flexible scheduling library that supports complex scheduling scenarios, including intervals, specific dates, and recurring patterns. It's great for applications that require advanced scheduling capabilities without a heavy dependency.

  • node-schedule:

    Use Node-Schedule if you want a versatile library that allows you to schedule jobs using cron syntax or JavaScript Date objects. It's suitable for applications that need a straightforward solution for scheduling tasks without the need for a database.

README for agenda

Agenda

Agenda

A light-weight job scheduling library for Node.js

NPM Version NPM Downloads

Migrating from v5? See the Migration Guide for all breaking changes.

Agenda 6.x

Agenda 6.x is a complete TypeScript rewrite with a focus on modularity and flexibility:

  • Pluggable storage backends - Choose from MongoDB, PostgreSQL, Redis, or implement your own. Each backend is a separate package - install only what you need.

  • Pluggable notification channels - Move beyond polling with real-time job notifications via Redis, PostgreSQL LISTEN/NOTIFY, or other pub/sub systems. Jobs get processed immediately when saved, not on the next poll cycle.

  • Modern stack - ESM-only, Node.js 18+, full TypeScript with strict typing.

See the 6.x Roadmap for details and progress.

Features

  • Minimal overhead job scheduling
  • Pluggable storage backends (MongoDB, PostgreSQL, Redis)
  • TypeScript support with full typing
  • Scheduling via cron or human-readable syntax
  • Configurable concurrency and locking
  • Real-time job notifications (optional)
  • Sandboxed worker execution via fork mode
  • TypeScript decorators for class-based job definitions

Installation

Install the core package and your preferred backend:

# For MongoDB
npm install agenda @agendajs/mongo-backend

# For PostgreSQL
npm install agenda @agendajs/postgres-backend

# For Redis
npm install agenda @agendajs/redis-backend

Requirements:

  • Node.js 18+
  • Database of your choice (MongoDB 4+, PostgreSQL, or Redis)

Quick Start

import { Agenda } from 'agenda';
import { MongoBackend } from '@agendajs/mongo-backend';

const agenda = new Agenda({
  backend: new MongoBackend({ address: 'mongodb://localhost/agenda' })
});

// Define a job
agenda.define('send email', async (job) => {
  const { to, subject } = job.attrs.data;
  await sendEmail(to, subject);
});

// Start processing
await agenda.start();

// Schedule jobs
await agenda.every('1 hour', 'send email', { to: 'user@example.com', subject: 'Hello' });
await agenda.schedule('in 5 minutes', 'send email', { to: 'admin@example.com', subject: 'Report' });
await agenda.now('send email', { to: 'support@example.com', subject: 'Urgent' });

Official Backend Packages

PackageBackendNotificationsInstall
@agendajs/mongo-backendMongoDBPolling onlynpm install @agendajs/mongo-backend
@agendajs/postgres-backendPostgreSQLLISTEN/NOTIFYnpm install @agendajs/postgres-backend
@agendajs/redis-backendRedisPub/Subnpm install @agendajs/redis-backend

Backend Capabilities

BackendStorageNotificationsNotes
MongoDB (MongoBackend)Storage only. Combine with external notification channel for real-time.
PostgreSQL (PostgresBackend)Full backend. Uses LISTEN/NOTIFY for notifications.
Redis (RedisBackend)Full backend. Uses Pub/Sub for notifications.
InMemoryNotificationChannelNotifications only. For single-process/testing.

Backend Configuration

MongoDB

import { Agenda } from 'agenda';
import { MongoBackend } from '@agendajs/mongo-backend';

// Via connection string
const agenda = new Agenda({
  backend: new MongoBackend({ address: 'mongodb://localhost/agenda' })
});

// Via existing MongoDB connection
const agenda = new Agenda({
  backend: new MongoBackend({ mongo: existingDb })
});

// With options
const agenda = new Agenda({
  backend: new MongoBackend({
    mongo: db,
    collection: 'jobs'        // Collection name (default: 'agendaJobs')
  }),
  processEvery: '30 seconds', // Job polling interval
  maxConcurrency: 20,         // Max concurrent jobs
  defaultConcurrency: 5       // Default per job type
});

PostgreSQL

import { Agenda } from 'agenda';
import { PostgresBackend } from '@agendajs/postgres-backend';

const agenda = new Agenda({
  backend: new PostgresBackend({
    connectionString: 'postgresql://user:pass@localhost:5432/mydb'
  })
});

Redis

import { Agenda } from 'agenda';
import { RedisBackend } from '@agendajs/redis-backend';

const agenda = new Agenda({
  backend: new RedisBackend({
    connectionString: 'redis://localhost:6379'
  })
});

Real-Time Notifications

For faster job processing across distributed systems:

import { Agenda, InMemoryNotificationChannel } from 'agenda';
import { MongoBackend } from '@agendajs/mongo-backend';

const agenda = new Agenda({
  backend: new MongoBackend({ mongo: db }),
  notificationChannel: new InMemoryNotificationChannel()
});

Mixing Storage and Notification Backends

You can use MongoDB for storage while using a different system for real-time notifications:

import { Agenda } from 'agenda';
import { MongoBackend } from '@agendajs/mongo-backend';
import { RedisBackend } from '@agendajs/redis-backend';

// MongoDB for storage + Redis for real-time notifications
const redisBackend = new RedisBackend({ connectionString: 'redis://localhost:6379' });
const agenda = new Agenda({
  backend: new MongoBackend({ mongo: db }),
  notificationChannel: redisBackend.notificationChannel
});

This is useful when you want MongoDB's proven durability and flexible queries for job storage, but need faster real-time notifications across multiple processes.

API Overview

Defining Jobs

// Simple async handler
agenda.define('my-job', async (job) => {
  console.log('Processing:', job.attrs.data);
});

// With options
agenda.define('my-job', async (job) => { /* ... */ }, {
  concurrency: 10,
  lockLimit: 5,
  lockLifetime: 10 * 60 * 1000, // 10 minutes
  priority: 'high'
});

Defining Jobs with Decorators

For a class-based approach, use TypeScript decorators:

import { JobsController, Define, Every, registerJobs, Job } from 'agenda';

@JobsController({ namespace: 'email' })
class EmailJobs {
  @Define({ concurrency: 5 })
  async sendWelcome(job: Job<{ userId: string }>) {
    console.log('Sending welcome to:', job.attrs.data.userId);
  }

  @Every('1 hour')
  async cleanupBounced(job: Job) {
    console.log('Cleaning up bounced emails');
  }
}

registerJobs(agenda, [new EmailJobs()]);
await agenda.start();

// Schedule using namespaced name
await agenda.now('email.sendWelcome', { userId: '123' });

See Decorators Documentation for full details.

Scheduling Jobs

// Run immediately
await agenda.now('my-job', { userId: '123' });

// Run at specific time
await agenda.schedule('tomorrow at noon', 'my-job', data);
await agenda.schedule(new Date('2024-12-25'), 'my-job', data);

// Run repeatedly
await agenda.every('5 minutes', 'my-job');
await agenda.every('0 * * * *', 'my-job'); // Cron syntax

Job Control

// Cancel jobs (removes from database)
await agenda.cancel({ name: 'my-job' });

// Disable/enable jobs globally (by query)
await agenda.disable({ name: 'my-job' });  // Disable all jobs matching query
await agenda.enable({ name: 'my-job' });   // Enable all jobs matching query

// Disable/enable individual jobs
const job = await agenda.create('my-job', data);
job.disable();
await job.save();

// Progress tracking
agenda.define('long-job', async (job) => {
  for (let i = 0; i <= 100; i += 10) {
    await doWork();
    await job.touch(i); // Report progress 0-100
  }
});

Stopping / Draining

// Stop immediately - unlocks running jobs so other workers can pick them up
await agenda.stop();

// Drain - waits for running jobs to complete before stopping
await agenda.drain();

// Drain with timeout (30 seconds) - for cloud platforms with shutdown deadlines
const result = await agenda.drain(30000);
if (result.timedOut) {
    console.log(`${result.running} jobs still running after timeout`);
}

// Drain with AbortSignal - for external control
const controller = new AbortController();
setTimeout(() => controller.abort(), 30000);
await agenda.drain({ signal: controller.signal });

Use drain() for graceful shutdowns where you want in-progress jobs to finish their work.

Events

agenda.on('start', (job) => console.log('Job started:', job.attrs.name));
agenda.on('complete', (job) => console.log('Job completed:', job.attrs.name));
agenda.on('success', (job) => console.log('Job succeeded:', job.attrs.name));
agenda.on('fail', (err, job) => console.log('Job failed:', job.attrs.name, err));

// Job-specific events
agenda.on('start:send email', (job) => { /* ... */ });
agenda.on('fail:send email', (err, job) => { /* ... */ });

Custom Backend

For databases other than MongoDB, PostgreSQL, or Redis, implement AgendaBackend:

import { AgendaBackend, JobRepository } from 'agenda';

class SQLiteBackend implements AgendaBackend {
  readonly repository: JobRepository;
  readonly notificationChannel = undefined; // Or implement NotificationChannel

  async connect() { /* ... */ }
  async disconnect() { /* ... */ }
}

const agenda = new Agenda({
  backend: new SQLiteBackend({ path: './jobs.db' })
});

See Custom Backend Driver for details.

Documentation

Related Packages

Official Backend Packages:

Tools:

License

MIT