crontool
Paste a schedule, read it in English, see the next runs.

Cron and Python Virtualenv

Cron doesn't know about an activated virtualenv — it uses the system Python and misses your installed packages. The reliable fix is to call the venv's python interpreter by its absolute path instead of activating anything.

Call the venv python directly

No activation needed — just use the interpreter inside the venv:

* * * * * /home/you/venv/bin/python /home/you/app.py >> /var/log/app.log 2>&1

That interpreter already sees the venv's packages, so imports work.

Or activate inside the command

* * * * * /bin/bash -c 'source /home/you/venv/bin/activate && python /home/you/app.py'. Wrapping in bash is required because cron's default shell won't run source the same way.

Why activation isn't enough

Activating a venv just prepends its bin to PATH in your shell. Cron starts a fresh minimal shell without that PATH, so it falls back to system Python and raises ModuleNotFoundError.

FAQ

How do I run a Python venv script from cron?

Call the venv's interpreter by absolute path: /home/you/venv/bin/python /home/you/app.py. It already sees the venv packages, no activation required.

Why does cron use the wrong Python?

Cron starts a minimal shell without your activated venv on PATH, so it uses system Python and misses installed packages, causing ModuleNotFoundError.

Can I activate a virtualenv in cron?

Yes: wrap it in bash — /bin/bash -c 'source venv/bin/activate && python app.py'. But calling venv/bin/python directly is simpler and more reliable.