Cron Jobs

Scheduling Cron Jobs in Node.js

By: August Flanagan|Last Updated: Mar 17, 2023

As the most popular programming language in the world ¹, it's no surprise that Javascript is also a popular language for writing cron jobs.

In this guide you’ll learn how to run any Node.js script as a cron job. We also explore other ways to add cron-like functionality to Node.js apps while avoiding some of the pitfalls of traditional cron jobs.

What is a cron job?

Traditionally, cron jobs are user-defined scripts/commands that are executed on a repeating schedule by the Unix cron scheduler. Now used by many background task systems, the term broadly means a piece of code running in the background at a scheduled time.

What the * * * * * ?!?

One of the strangest parts of a cron job is the scheduling syntax, e.g.  */3 2 * * 0-3.

Reminiscent of regular expressions, it is very hard to remember. See our guide on cron schedule syntax or use crontab.guru to translate a cron expression to english.

Run a Nodejs script as a cron job

Any Node script can be executed from the command line as:

node /path/to/script.js

Thus, the first step to running your Node scipt as a cron job is to manually execute your script from the command line of your server, and to verify that it does what you expect.

Note: Even if your script executes as expected, it's still possible for it to fail when executed by cron. We'll cover this in detail below.

Once you've successfully tested your script, it's time to configure it to be run by the cron scheduler.

There are five different ways to schedule cron jobs, but we will cover the two most common options.

  • Scheduling a cron job when you have root or sudo privileges

    With administrator-level access to a linux instance, a best practice is to create an application-specific crontab file in the server's cron.d directory, usually located at /etc/cron.d/. This directory is scanned every minute by cron, and all you need to do is copy a crontab file into place. Below is an example single line crontab file.

    # Run the daily_analytics.js script once a day.
    0 0 * * *  node /etc/scripts/daily_analytics.js
    
  • Scheduling a cron job without root privileges

    Cron jobs can also be scheduled in a user crontab file. These user crontabs can only run commands as the user they are assigned to.

    To edit your user crontab, use the crontab -e command:

    $ crontab -e
    

    From the text editor, add your new cron entry:

    # m h dom mon dow   command
    0 0 * * * node /path/to/script.js
    

Common Mistakes

With your script written, tested and scheduled you are almost done. You would think that a script that works for you will also work when run as a cron job, but there are a few key differences between your shell and the cron execution environment and these differences can often cause headaches when scheduling jobs:

  1. Incorrect file permissions or ownership

    The cron daemon will be executing your script as a specific user, and your Node.js must be executable by that user. You can check the file permissions of your script with:

    ls -l /path/to/script.js
    
  2. Not using absolute paths

    The current working directory used by Cron depends on several factors, but it's usually the job owner's home directory. Avoid any confusion here by exclusively using fully-qualified paths when you add the job to the crontab file. Similarly, if your script is invoking any other commands, it should use a fully qualified path or set its own working directory before doing any invocations.

  3. Missing environment variables

    Even though cron runs your cron jobs using a real user account, it does not trigger an interactive session, so any environment variables you may be loading in .bash_profile or .bashrc will not be available. If your script expects certain environment variables, you can either set them within the crontab file itself, or have each line of your crontab source your .bash_profile before invoking your script.

    0 0 * * * source ~/.bash_profile ; node /etc/scripts/daily_analytics.js
    

This is by no means a comprehensive list of possible errors. If you're still stuck, our troubleshooting guide for cron jobs that will walk you step-by-step through the reasons that cause most cron job failures.

Run cron jobs with Node-Cron

One of the interesting language features of Node.js is the event loop, and it happens to makes it easy to implement a cron-like scheduler in Node.

This has the benefit of making it easy write "cron jobs" from within your Node.js application, which means the code can be colocated and version controlled. And, of course, it means not having to SSH onto a server in order to update a crontab file, or otherwise figure out how to deploy crontab updates.

Node-Cron is one popular library for running cron jobs directly from within your Node.js application, and it uses the ever-present cron syntax like so:

var cron = require('node-cron');

cron.schedule('1,2,4,5 * * * *', () => {
  console.log('running every minute 1, 2, 4 and 5');
});

It is very popular to use Node-Cron with Express, and Digital Ocean has written an excellent tutorial on getting started.

Run cron jobs with Vercel

Vercel has become one of the most popular platforms for deploying modern Javascript applications, and in early 2023 they announced built-in support for cron jobs.

With Vercel's take on "cron jobs" you provide a cron schedule syntax and the path to an API endpoint, and Vercel will handle calling this endpoint on your defined schedule.

# vercel.json
{
  "crons": [
    {
      "path": "/api/cron",
      "schedule": "0 5 * * *"
    }
  ]
}

This is a great light-weight alernative to traditional cron jobs, but it comes with a few limitations. Specifically, long-running jobs are difficult scale if they need to be executed with in the HTTP request lifecycle.

If you are not using Vercel, but would like to use the same cloud scheduler concept, there are a number of alternatives, including Cron-Job.org or Google's Cloud Scheduler.

Monitor Node.js cron jobs

Because cron jobs are "background jobs", it's important to monitor them, otherwise you will eventually discover a job has been failing silently for far too long. Depending on the job, this can have major impacts on operations and performance.

Cronitor has a Node SDK that makes it incredible easy to monitor the execution of your Node.js cron jobs.

Monitoring Node.js Cron Jobs

const cronitor = require('cronitor')('<cronitor api key here>');

let importantAsyncWorker = cronitor.wrap('important-worker', async function() {
    // do some async work
});

// cronitor will track the start and end time and state (promise resolved or rejected).
await importantAsyncWorker();

Monitoring Node-Cron Jobs

const cronitor = require('cronitor')('cronitor_api_key');
const nodeCron = require('node-cron');

cronitor.wraps(nodeCron);

// the first parameter is now the key that Cronitor will use
// to send telemetry events when the jobs runs, completes or fails
cronitor.schedule('SendWelcomeEmail', '*/5 * * * *', function() {
    console.log('Sending welcome email to new sign ups every five minutes.');
});
Previous
PHP Cron Jobs