Skip to content
All Articles
Data Engineering··11 min read

How to Schedule a Python Script to Run Automatically

A beginner's guide to scheduling a Python script to run automatically: cron on Mac and Linux, Task Scheduler on Windows, and the schedule library, plus the gotchas that break automations.

PythonAutomationCronData EngineeringTutorial

You wrote a Python script. It works. Now you find yourself opening a terminal every morning to run it by hand, and on the mornings you forget, nothing happens. That gets old fast.

The fix is scheduling. A scheduler is basically an alarm clock for your code. You tell it "run this script every day at 6am," and it does, whether or not you remember. In this guide you will learn how to schedule a Python script to run automatically, on any operating system, using the three approaches that actually matter. No prior DevOps knowledge needed.

If you built the pipeline from my beginner ETL guide, this is the piece that turns it from a script you babysit into something that runs on its own.

A schedule every day at 6am Scheduler cron / Task Scheduler your_script.py runs, then exits repeats on the next scheduled time
A scheduler launches a fresh copy of your script at each scheduled time. The script runs to the end and exits, and the scheduler brings it back on the next tick.

What "scheduling" actually means

A scheduler is just a program whose whole job is to run other programs at set times. cron and Windows Task Scheduler are schedulers built into your operating system. They sit quietly in the background and wake up to launch your script when the clock matches.

Here is the one mental shift that clears up most confusion. Your script does not need to be running for a scheduler to run it. The scheduler starts a brand new copy at the scheduled time, that copy runs to the end and exits, and tomorrow the scheduler starts another fresh copy. So a scheduled script should do its job once and finish, not loop forever waiting for the clock. The clock is the scheduler's job, not your script's.

Option 1: cron (Mac and Linux)

cron is the scheduler built into every Mac and Linux system. You hand it a schedule and a command, and it runs that command on that schedule, in the background, indefinitely.

You edit your schedule with one command:

crontab -e

That opens your personal list of scheduled jobs, called your crontab. Each line is one job. The format looks cryptic the first time, but it is only five time fields followed by the command to run.

* * * * * minute (0-59) hour (0-23) day of month (1-31) month (1-12) day of week (0-6, Sunday is 0)
Five fields, left to right: minute, hour, day of month, month, day of week. An asterisk means "every."

So to run a script every day at 6:00am:

crontab
# minute hour day month weekday   command
0 6 * * *   /home/you/venv/bin/python /home/you/pipeline.py >> /home/you/pipeline.log 2>&1

Let me unpack that command, because the details are exactly where people get stuck:

  • 0 6 * * * is minute 0 of hour 6, on every day, month and weekday. That is 6
    daily.
  • /home/you/venv/bin/python is the full path to the Python inside your virtual environment, not just python. cron knows nothing about your venv, so you point straight at it.
  • /home/you/pipeline.py is the full path to your script.
  • >> /home/you/pipeline.log 2>&1 sends everything the script prints, including errors, into a log file so you can actually see what happened.

A handful of schedules you will reach for constantly:

ScheduleCron lineMeaning
Every day at 6am0 6 * * *minute 0, hour 6, any day
Every hour0 * * * *at the top of every hour
Every 15 minutes*/15 * * * *the */15 means "every 15"
Every Monday at 9am0 9 * * 1weekday 1 is Monday
Midnight on the 1st0 0 1 * *day of month 1

If cron syntax makes your eyes cross, crontab.guru turns any schedule into plain English as you type it. I still keep it open.

Option 2: Task Scheduler (Windows)

Windows has no cron, but it has Task Scheduler, which does the same job with a wizard instead of a text file. The short version:

  1. Press the Windows key, type Task Scheduler, and open it.
  2. Click Create Basic Task and give it a name like "Daily pipeline."
  3. Choose a trigger. Pick Daily and set your time.
  4. For the action, choose Start a program.
  5. In Program/script, put the full path to your venv's Python, for example C:\Users\you\venv\Scripts\python.exe.
  6. In Add arguments, put the full path to your script, C:\Users\you\pipeline.py.
  7. Finish.

The task now runs on the schedule you picked. Tick "run whether the user is logged on or not" on the last screen if it should run even when you are signed out.

Option 3: the schedule library (inside Python)

Sometimes you want the schedule to live in your code rather than in the operating system. Maybe you are on a host where you cannot touch cron, or you just want everything in one place. The schedule library is the friendliest way to do that.

pip install schedule
scheduler.py
import schedule
import time
 
def job():
    print("Running the pipeline...")
    # your real work goes here, e.g. run_pipeline()
 
# say what to run and when, almost in plain English
schedule.every().day.at("06:00").do(job)
schedule.every(15).minutes.do(job)
 
# keep the program alive so it can trigger jobs on time
while True:
    schedule.run_pending()
    time.sleep(1)

There is a catch, and it matters. This only works while the program is running. That while True loop is the program staying awake to watch the clock. If the process stops, the schedule stops with it. So schedule shines when it lives inside something already running long-term, and it is a poor fit for "run once a day then exit," where cron or Task Scheduler are the honest answer.

So which one should you use?

If you...Use
are on Mac or Linux and want "run and exit"cron
are on WindowsTask Scheduler
want the schedule inside a long-running Python appthe schedule library
need restarts, parallelism or persistenceAPScheduler, or an orchestrator

For most beginners scheduling a data script, cron on a Linux server or Task Scheduler on a Windows machine is the entire answer. Start there and add complexity only when something forces you to.

The 5 gotchas that silently break scheduled scripts

This is the part I wish someone had handed me on day one. A script that runs perfectly by hand can fail the instant a scheduler runs it, and it tends to fail quietly. Here is why, roughly in order of how often it bites people.

  1. Relative paths. Your script opens data.csv and it works from your project folder, but the scheduler runs from somewhere else entirely, so the file is not found. Use absolute paths, or build them from the script's own location.
  2. The wrong Python. cron and Task Scheduler default to the system Python, which does not have the packages you pip installed. Point them at your virtual environment's Python instead.
  3. No logging. When a scheduled run fails, there is no terminal watching to show you the error. Redirect output to a log file (>> file.log 2>&1 in cron) or add Python's logging, so failures leave a trace you can read later.
  4. The script waits for input. Any input() call, or a library that pops a prompt, will hang forever because nobody is there to answer. An automated script has to run start to finish with zero interaction.
  5. Timezone surprises. The server's clock may not be your clock. A job set for "6am" can fire at 6am UTC, which might be the middle of your night. Check the machine's timezone before you trust the time.

Get these five right and most scheduling pain simply disappears.

When to graduate from a scheduler

cron and Task Scheduler are great for a handful of independent jobs. You outgrow them when jobs start depending on each other (run the report only after the load finishes), when you need automatic retries and alerts on failure, or when you are juggling dozens of them and cron turns into a wall of cryptic lines nobody dares touch.

That is when teams move to an orchestrator like Dagster, Airflow or Prefect, which add dependencies, retries, and a dashboard that shows what ran and what broke. I compared the three in Dagster vs Airflow vs Prefect. On a distributor pipeline I built for an FMCG client, jobs kicked off automatically when files landed on a server, not on a fixed clock, which is the kind of thing an orchestrator makes easy and cron cannot really do. You do not need any of that on day one. You just need to recognise the day cron stops being enough.

Frequently asked questions

How do I run a Python script automatically every day?

On Mac or Linux, add a cron job with crontab -e and a line like 0 6 * * * /path/to/venv/bin/python /path/to/script.py. On Windows, use Task Scheduler's Create Basic Task wizard with a Daily trigger. Both launch a fresh copy of your script at the set time.

How do I schedule a Python script on Windows?

Open Task Scheduler, choose Create Basic Task, set a Daily or other trigger, then for the action pick "Start a program" and point it at your virtual environment's python.exe, with your script's full path as the argument. Tick "run whether user is logged on or not" if it should run in the background.

cron or the schedule library, which is better?

cron is better for "run once and exit" jobs, because the operating system handles it and nothing of yours has to stay running. The schedule library is better when the schedule lives inside an app that is already running long-term. If you need persistence across restarts or parallel jobs, use APScheduler instead.

Why does my scheduled Python script fail when it runs fine manually?

Almost always one of three things: it uses relative paths that break from the scheduler's working directory, it runs with the system Python that lacks your installed packages, or it errors silently with no log to explain why. Use absolute paths, point at your venv's Python, and write output to a log file.

The takeaway

Scheduling is the small step that turns a script into a system. You do not need a fancy tool for it. cron on Mac and Linux, Task Scheduler on Windows, or the schedule library inside a running app will each take a job off your plate for good. The tool matters less than the habits: full paths, the right Python, and logs you can actually read when something breaks.

Set it up once, and the thing you used to run by hand just happens on its own. That is a genuinely good feeling.

If you are wiring up real data pipelines and trying to work out where a cron line ends and a proper orchestrator begins, that is the kind of work I do. Or tell me what you are automating and I will point you the right way.

MH

Mirza Hammad Tariq

AWS Data Engineer with 5+ years building production-grade ETL pipelines, cloud data warehouses, and scalable data architectures in Python, SQL, Dagster, and AWS.

Work With Me
The proof

Related case studies

Data EngineeringDelivered

Dynamic, Fully-Automated ETL Pipeline on AWS

100% API automation processing millions of records daily

Built a dynamic ETL pipeline on AWS for a sales-engagement SaaS platform, using Glue, Redshift, Apache Hudi and Athena to automate extraction of milli…

−40%automation
PythonPySparkAWSAWS Glue
View Case Study
Data EngineeringDelivered

Automated Distributor ETL for Unilever

Hands-off SFTP-to-analytics for daily sales & stock data

An automated ELT pipeline that detects distributor files landing on SFTP, validates and homologates them, and lands analytics-ready data in S3 for rea…

ZeroManual intervention
DagsterdbtPostgreSQLAWS S3
View Case Study
Keep reading

Continue reading

Data Engineering

How to Build Your First ETL Pipeline in Python

New to data engineering? Build your first ETL pipeline in Python: pull data from an API, clean it with pandas, and load it into a database, the right way.

ETLPythonData EngineeringPandas
Data Engineering

Dagster vs Airflow vs Prefect for ETL in 2026

Dagster vs Airflow vs Prefect for ETL in 2026, compared by the one question they disagree on: what a pipeline is actually made of. Field notes from a 50M-records/day build.

DagsterAirflowPrefectETL
Data Engineering

RabbitMQ Data Pipelines: Scale ETL without adding compute

How to scale a data pipeline with RabbitMQ: work queues, a horizontal worker pool, durability and backpressure. The pattern that took one pipeline past 2M records a day.

RabbitMQMessage QueueData EngineeringDistributed Systems
Taking on new projects · Outside IR35

Have a data pipeline or warehouse problem worth solving?

From messy source data to analytics-ready warehouses that cut cost. Let's scope it. I reply within one business day.