cron is dead, long live launchd!

Now that I finally created my tarsnap backup script, how do I execute it regularly? Oh, I know: My Mac is just an Unix system, I'll use cron!

At least that's what I thought I'll do. After a few attempts to get cron to do the job, I learned that there's a better way on macOS: launchd.

launchd does a lot more than executing scripts cron-style. Like systemd on Linux, launchd is a replacement for a lot of old school Unix tools, like cron, inetd, init, etc.

At it's core, launchd distincts daemons and agents. Dameons are processes that always run in the background, while agents describe regular jobs that are to be executed on certain events. There are a lot of different events to choose from. For example you can trigger an agent, when a device gets mounted, when a file gets created, or when a certain time arrives.

What really helped me in learning how to write my first launchd agent was launchd.info. Unlike the Apple documentation, it contains useful snippets and concise explanations. I highly recommend that you also have a look at the launchd agents that some of your applications put into ~/Library/LaunchAgents.

Below you can see the agent that I ended up creating. You can learn how to load/unload agents and about the meaning of the different options at launchd.info.

If you're testing your script and you don't want to wait for the next hour to arrive, you can start it immediately with launchctl start eu.jan-ahrens.tarsnap.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">

P.S.: cron itself is implemented as a launchd daemon. You can find it at /System/Library/LaunchDaemons/com.vix.cron.plist.


Hi, I'm Jan Ahrens. In this blog you can read about my thoughts on various technical topics.

As you might have already guessed: My opinions are my own and don't necessarily represent those of my employer.

If you want to contact me you can use my PGP key. Its fingerprint is 3762 1152 E099 AB27 04E8 3FD1 B911 E6A2 2B4F 3B5F.

This blog is built with Jekyll. You can find its source code on GitHub.