Creating a Cron Job

I don’t create cron jobs very often. I do it rarely enough that I have to go figure it out each time. Tonight I needed to create a cron job on my home server. Rather than look it up again, I told Claude to do it for me. Tasks like this are exactly the kind of thing that many devs will happily offload to AI.

Whether we actually create cron jobs by hand or not, we will still need them. I think it’s worth remembering how they work. Allowing AI to think for you feels like a win. One less thing you need to understand. But over time that attitude is going to destroy your skills.

When you use AI to perform a task, ask yourself, am I avoiding manual effort here? Or am I avoiding thinking effort? If it’s the former, great. If it’s the latter, be careful. You don’t want to lose your ability to think through problems and understand how things work.

So tonight, when I needed a cron job, I avoided the manual effort. But, I was also skipping the part where I go and search and remind myself how cron jobs work. And that part is important. With that in mind. Here’s a quick refresher on cron jobs, a reminder for my future self.

The Task at Hand

I wanted to create a demo of a project. This would involve allowing users to freely register and create content in the app. Each night at midnight I want to clear down the data, so the demo starts clean each day.

For the purposes of this demo, cleaning down the data just means deleting some files. Running the command to do that at midnight is exactly what cron is made for.

What is cron?

A cron job is a scheduled task on a Linux/Unix server — “run this command at this time, every day/week/hour/etc.”

Cron is a background process (daemon) that’s always running on the server. It wakes up every minute, checks if any scheduled tasks are due, and runs them.

Crontab is the file where the schedule is defined — one line per job. Each line has two parts: when to run, and what to run.

0 23 * * *   cd ~/myapp && bash reset-demo.sh
─────────── ──────────────────────────────────
WHEN                    WHAT

The five numbers/stars define the schedule:

0 23 * * *
│ │  │ │ └── day of week  (* = any)
│ │  │ └──── month        (* = any)
│ │  └─────  day of month (* = any)
│ └────────  hour         (23 = 11pm UTC)
└──────────  minute       (0 = on the hour)

So 0 23 * * * means: at 23:00, every day, regardless of month or day of week.

Minutes and hours are in 24-hour format, and the time is in UTC by default. You can specify a different timezone if needed.

The day of the week is specified as 0-7 (0 or 7 = Sunday, 1 = Monday, …, 6 = Saturday). The day of the month is 1-31. The month is 1-12.

If you want the command to run only on weekdays you’d write 0 23 * * 1-5, or Monday and Friday only: 0 23 * * 1,5.

That - and , notation also works for days of the month, and months of the year.

For example:

0 9 1,15 * *        # 9am on the 1st and 15th of every month
0 9 * 6-8 *         # 9am every day during June, July, August
0 9 * * 1-5         # 9am every weekday
*/15 * * * *        # every 15 minutes
0 */6 * * *         # every 6 hours

It’s been a standard part of Unix since the 1970s — the same mechanism is used for things like log rotation, backups, and system maintenance tasks on essentially every Linux/Unix server in the world.

Where is cron?

It’s stored on the server at /var/spool/cron/crontabs/richard — one file per user.

You don’t edit it directly though. The crontab command is the interface:

  • crontab -l — list your current jobs
  • crontab -e — edit in a text editor
  • crontab -r — delete all your jobs (careful)

The cron daemon itself is a system process — you can see it running with:

$ ps aux | grep cron

How do I create a cron job?

If you want to create a one-off cron job and you can ssh into the server, you can just run crontab -e and add a line to the file.

$ crontab -e

Select an editor.  To change later, run 'select-editor'.
  1. /bin/nano        <---- easiest
  2. /usr/bin/vim.basic
  3. /usr/bin/vim.tiny
  4. /bin/ed

Choose 1-4 [1]: 1

You can then add a line to the file. For example, to run a script at midnight every day:

0 0 * * * /home/richard/reset-demo.sh

For my demo I had a .sh script that copied the project’s files to the server then spun up the project using docker compose. To avoid manually logging on to the server to configure a cron job I added the following to that script.

ssh "$SERVER" "(crontab -l 2>/dev/null | grep -v 'reset-demo.sh'; echo '0 23 * * * cd ~/myapp && bash reset-demo.sh >> ~/myapp/reset-demo.log 2>&1') | crontab -"

Breaking it down — three commands piped together, all running on the server via SSH:

  1. crontab -l 2>/dev/null — print the existing crontab (suppress errors if it’s empty)
  2. grep -v 'reset-demo.sh' — strip out any existing reset-demo line (prevents duplicates on re-deploy)
  3. echo '0 23 * * * cd ~/myapp && bash reset-demo.sh ...' — append the new line

The whole output is piped into crontab - which writes it as the new crontab, replacing the old one.

comments powered by Disqus