RBRunbook
Dev Tools

How to Schedule a Python Script: Cron vs Task Scheduler vs launchd

Every OS has a different way to run a script automatically. Here's the correct syntax for each, plus the mistakes that make scheduled jobs silently fail.

DifficultyIntermediate
Time15–25 min
PlatformWindows / macOS / Linux
CategoryDev Tools

A script that runs perfectly when you type python script.py in your terminal often fails silently when scheduled — not because the schedule is wrong, but because scheduled jobs don't inherit your shell's environment (PATH, virtual environments, working directory). Each platform's method is below, plus the fix for that specific problem.

01Linux/macOS: cron

Open your crontab:

crontab -e

Add a line for, say, running a script every day at 6:30 AM:

30 6 * * * /usr/bin/python3 /home/user/scripts/backup.py >> /home/user/scripts/backup.log 2>&1

Two details that matter: use the full path to both the Python interpreter and the script (find it with which python3), and redirect output to a log file — otherwise, when the job fails, you'll have no idea why.

02Windows: Task Scheduler

  1. Open Task Scheduler → Create Task (not "Basic Task" — it hides useful options).
  2. General tab: check "Run whether user is logged on or not" if it needs to work while you're logged out.
  3. Triggers tab: New → set your schedule.
  4. Actions tab: New → Program/script: the full path to python.exe (find it with where python in Command Prompt). Add arguments: the full path to your script, in quotes.
  5. Set "Start in" to your script's folder — this fixes relative file paths inside the script that otherwise break.

03macOS: launchd

Cron technically still works on macOS but Apple's own scheduler, launchd, is more reliable for tasks that need to survive sleep/wake cycles. Create a plist file:

nano ~/Library/LaunchAgents/com.user.backup.plist
<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>com.user.backup</string>
  <key>ProgramArguments</key>
  <array>
    <string>/usr/bin/python3</string>
    <string>/Users/you/scripts/backup.py</string>
  </array>
  <key>StartCalendarInterval</key>
  <dict>
    <key>Hour</key><integer>6</integer>
    <key>Minute</key><integer>30</integer>
  </dict>
</dict>
</plist>

Load it:

launchctl load ~/Library/LaunchAgents/com.user.backup.plist

04The virtual environment trap

If your script depends on packages installed in a virtual environment, calling the system Python directly will fail with ModuleNotFoundError even though it works in your terminal. Point the scheduler at the interpreter inside the venv instead:

/home/user/myproject/venv/bin/python3 /home/user/myproject/backup.py

This one line fixes the single most common reason scheduled Python jobs work manually but fail when automated.

Always test this way first Before trusting any schedule, temporarily set it to run two minutes from now and check the log file or Task Scheduler's history tab. It's much faster to catch a broken path this way than to find out tomorrow that nothing ran.
JM
Written by Jordan Malik Senior Editor, Systems & Networking — guide tested on a live Windows / macOS / Linux setup before publishing
Last verified: July 2026