Tutorials July 2026

Fly.io Cron Jobs with Python: Setup Guide and Alternatives (2026)

Want to run scheduled Python scripts on Fly.io? Here's exactly how to do it — and when a purpose-built cron platform is the smarter choice.

L
LiteLambda Team
8 min read

Fly.io has become a favorite platform for developers who want Heroku-like simplicity with more control. Its global deployment model and developer-friendly CLI make it a great fit for web apps. But for Python cron jobs and scheduled scripts, Fly.io has meaningful limitations that make it a poor fit for most use cases.

This guide covers how Fly.io cron jobs work, what the real limitations are, and what to use instead if you just want to run a Python script on a schedule.

How Fly.io Handles Scheduled Tasks

Fly.io doesn't have a native "cron job" feature. Instead, you have a few options:

Option 1: Fly Machines with restart_policy + schedule

Fly.io supports Machine scheduling via its API and fly.toml. As of 2024, you can configure a Machine to run on a schedule using the Fly Machines API:

{
  "schedule": "daily",
  "restart": {
    "policy": "no"
  }
}

Limitation: The schedule options are coarse (hourly, daily, monthly) — no custom cron expressions. You can't say "every 15 minutes" or "Monday at 9 AM."

Option 2: Run a Persistent Worker with an Internal Scheduler

Deploy a Fly app with a Python process that uses schedule or APScheduler internally:

# app.py — runs as a persistent Fly Machine
import schedule
import time

def my_daily_job():
    print("Running daily job...")
    # your logic here

schedule.every().day.at("09:00").do(my_daily_job)

while True:
    schedule.run_pending()
    time.sleep(60)

Problem: This requires a Fly Machine to be running 24/7. At minimum scale (shared-cpu-1x, 256MB), that's ~$2.20/month. You're paying for a server that mostly does nothing.

Option 3: Dockerfile + Fly.io + Crontab Inside Container

Run a Docker container on Fly that uses the Linux crontab internally:

FROM python:3.11-slim

COPY requirements.txt .
RUN pip install -r requirements.txt
COPY script.py .
COPY crontab /etc/cron.d/myjob
RUN chmod 0644 /etc/cron.d/myjob
CMD ["cron", "-f"]
# crontab file
0 9 * * * python /app/script.py >> /var/log/cron.log 2>&1

This works, but now you're managing:
- A Dockerfile
- Crontab syntax inside the container
- Log collection (Fly's log viewer shows container stdout, not cron logs by default)
- Fly.io deployment and scale-to-zero configuration

Realistic setup time: 45 minutes to 2 hours.


The Real Cost of Running Cron Jobs on Fly.io

For a script that runs once daily:

Resource Cost
Shared CPU 1x, 256MB RAM (minimum) ~$2.20/month
1 GB persistent volume (if needed) $0.15/month
Bandwidth Negligible for most scripts
Total ~$2.35–5/month

This is for a machine that runs 24/7 to execute one 10-second script per day. You're paying for 99.99% idle time.

With scale-to-zero configured, the machine sleeps, but it takes 1–3 seconds to wake up — which means your job doesn't run at the exact scheduled time.


Fly.io Cron vs. Purpose-Built Python Cron Platforms

Feature Fly.io Cron LiteLambda
Custom cron expressions ⚠️ Limited (daily/hourly only natively) ✅ Full cron syntax
pip packages ✅ (via Dockerfile) ✅ (list them, no Dockerfile)
Execution logs per run ⚠️ Container logs only ✅ Per-execution dashboard
Failure alerts ❌ (manual setup) ✅ Email + Telegram built-in
Pay-per-execution ❌ (always-on machine)
Setup time 45 min–2 hrs 5 minutes
AI code assistant
Playwright support ✅ (container-based)
Monthly cost (1 daily script) ~$2.35+ $0–$4.99

When Fly.io Makes Sense for Cron

Fly.io is a good choice for scheduled tasks when:

  1. You already have a Fly.io app and want the cron to share its environment, database connection, or private network
  2. You need very long-running jobs (Fly supports running containers for hours or days)
  3. You want global deployment and need the job to run close to a specific geographic region

For standalone Python scripts that don't need to live inside a Fly.io private network, the setup complexity and cost aren't justified.


Tutorial: Run a Python Script on a Schedule Without Fly.io

Here's the same result with dramatically less setup using LiteLambda.

Scenario: A Python script that checks your Fly.io app's uptime via HTTP and sends a Telegram alert if it's down.

import requests
import os
from datetime import datetime

def handler(event, context):
    """
    Health check for Fly.io app — runs every 5 minutes.
    Sends Telegram alert if the app is down.
    """
    app_url = os.environ["APP_URL"]
    bot_token = os.environ["TELEGRAM_BOT_TOKEN"]
    chat_id = os.environ["TELEGRAM_CHAT_ID"]

    try:
        resp = requests.get(app_url, timeout=10)
        is_up = resp.status_code == 200
    except requests.RequestException:
        is_up = False

    if not is_up:
        message = f"⚠️ {app_url} is DOWN at {datetime.utcnow().strftime('%H:%M UTC')}"
        requests.post(
            f"https://api.telegram.org/bot{bot_token}/sendMessage",
            json={"chat_id": chat_id, "text": message}
        )

    return {
        "url": app_url,
        "status": "up" if is_up else "down",
        "checked_at": datetime.utcnow().isoformat()
    }

Deploy on LiteLambda:

  1. Create a new cron job at /crons/new/
  2. Paste the code
  3. Add package: requests
  4. Add env vars: APP_URL, TELEGRAM_BOT_TOKEN, TELEGRAM_CHAT_ID
  5. Set schedule: */5 * * * * (every 5 minutes)
  6. Save and test with Run Manually

This gives you a more reliable uptime monitor than running the same script inside your Fly app — because if Fly itself has an issue, your monitor on a separate platform will still catch it.


Migrating From Fly.io Cron to LiteLambda

1. Extract your script from the Dockerfile

If your Fly.io cron runs inside a container, pull out the Python script. The logic itself doesn't change.

2. Convert environment variables

Copy your secrets from fly secrets list and paste them into LiteLambda's Env Vars section.

3. Convert the cron expression

Fly.io uses standard cron syntax in its API. Your expression translates directly to LiteLambda.

4. Handle the entry point

Wrap your script in a handler function:

# Before (standalone script run by cron)
import requests

def main():
    # your logic

if __name__ == "__main__":
    main()

# After (LiteLambda)
import requests

def handler(event, context):
    # your logic (call main() or put logic here)
    result = main()
    return {"status": "ok", "result": result}

def main():
    # unchanged
    pass

5. Test and go live

Click Run Manually to verify the output. Activate the schedule. Decommission your Fly Machine.


Summary

Fly.io is excellent for persistent web services and apps that need global edge deployment. For scheduled Python scripts, it requires Docker knowledge, container management, and you pay for idle compute.

If your goal is just to run a Python script on a schedule:

Goal Best Platform
Simple scheduled Python script LiteLambda
Part of existing Fly.io app ecosystem Fly.io persistent worker
Complex multi-step pipeline Apache Airflow or Prefect
Enterprise AWS environment Lambda + EventBridge

Deploy your first Python cron job in 5 minutes →

Skip the infrastructure setup.

Run this exact code in our secure, isolated Docker sandbox. It takes 10 seconds to deploy.

Deploy this script in 60s →

No DevOps required.