Crontab Environment Variables

How environment variables work in crontab. Setting PATH, SHELL, MAILTO, CRON_TZ, and passing variables to cron job commands.

ZERO UPLOAD · ALL LOCAL
  1. Type or paste a 5-field cron expression into the input (e.g. */15 * * * *).
  2. Use the preset buttons to load a common schedule instantly.
  3. Edit individual fields (MIN, HR, DOM, MON, DOW) — the expression updates live.
  4. Read the SCHEDULE panel for a plain-English description of the pattern.
  5. Choose a timezone and clock format, then read NEXT 5 RUNS for upcoming execution times.

What to look for

  • /usr/bin:/bin
PRESETS

MIN
HR
DOM
MON
DOW
SCHEDULE

NEXT 5 RUNS

    Crontab Environment Variables: PATH, SHELL, MAILTO, CRON_TZ

    Cron jobs run in a stripped environment. The cron daemon does not read .bashrc, .bash_profile, or any login script; it starts each job with a minimal set of variables defined by the system.1 This stripped environment is the root cause of the most common cron failure: a command that works in a terminal because your PATH includes /usr/local/bin silently fails in cron because that directory is not on the cron PATH.

    Four variables cover the majority of cron environment needs: SHELL (which interpreter runs your command), PATH (where to find executables), MAILTO (where output goes), and CRON_TZ (which timezone to use for schedule evaluation). All four are set at the top of the crontab file, above the job lines they apply to.

    SHELL, PATH, and MAILTO

    SHELL=/bin/bash changes the command interpreter from the default /bin/sh. This matters when your command uses bash-specific syntax like arrays, [[ ]], or process substitution.2 Choosing the wrong shell is one of the most common reasons a cron job fails silently, because the command parses without error but produces no output when the shell rejects the syntax.

    Setting PATH and MAILTO

    PATH=/usr/local/bin:/usr/bin:/bin:/home/user/.local/bin extends the default minimal path so that executables installed by package managers or language-specific toolchains are visible to cron jobs. [email protected] routes job output to an email address; set MAILTO="" to suppress output entirely when you redirect to a log file. Setting both variables at the top of every crontab is a low-cost habit that prevents the two most common classes of silent cron failure: command not found and lost output.

    Keep the assignment block at the very top of the file rather than next to each job, because the variables only influence lines that appear below them and a job above the block silently runs without them. A single preamble also makes the environment auditable at a glance, which is useful when the same file is edited by several people over time. Treat the block as part of the job definition, not an optional comment, since removing it can reintroduce the exact failures it was added to prevent.

    Passing variables to cron job commands

    Variables set in the crontab file are available to all job lines below them. DB_HOST=prod.example.com above a job line makes $DB_HOST visible inside the command. Yet unlike shell scripts, the crontab file does not support command substitution ($(...)) in variable assignments: values must be literal strings. For complex environment setup, source a dedicated env file in the command itself: bash -c 'source /etc/myapp/env && python3 /opt/myapp/run.py'. The distinction between crontab variable assignments and shell script variable assignments is subtle but important, because assuming command substitution works is how jobs end up with literal $(...) strings in their environment instead of resolved values.

    Keeping secrets out of the crontab

    Avoid placing API tokens or database passwords directly in the crontab, even though variable assignments would technically work. Prefer a restricted file, a secrets manager, or a service account with limited permissions, then source only what the command needs. This keeps the schedule readable and prevents credentials from spreading through backups and terminal history. A crontab file is often world-readable on the system and routinely backed up in plain text, which makes it one of the worst places to store sensitive values that rotate frequently.

    CRON_TZ and HOME

    CRON_TZ=America/Chicago sets the timezone used to evaluate the schedule for all subsequent job lines. It does not affect the system clock. HOME=/home/user overrides the home directory (~) that cron uses when expanding paths. Setting HOME is rarely necessary but matters for commands that write to ~/.config or read ~/.ssh because cron may default to the root home directory depending on the daemon configuration.3

    Both CRON_TZ and HOME are especially useful when a single server hosts jobs for users in different timezones or with different home directory structures. By grouping all timezone-dependent jobs under a single CRON_TZ assignment and all path-dependent jobs under a HOME assignment, you avoid scattering timezone and path overrides throughout every individual job line.

    Sourcing a .env file in a cron job command

    When your application uses a .env file for configuration, sourcing it inside the cron command is the cleanest way to pass environment variables without duplicating them in the crontab. The crontab file does not support command substitution in variable assignments, so the source must happen in the command itself: bash -c 'set -a; source /opt/myapp/.env; set +a; exec /opt/myapp/run.py'.

    The set -a flag tells bash to export every variable it reads from the .env file, making each key-value pair available to the command that follows. After sourcing, set +a stops automatic export. For Python applications using a virtual environment, combine both steps: bash -c 'set -a; source /opt/myapp/.env; set +a; /opt/myapp/venv/bin/python3 /opt/myapp/run.py >> /var/log/myapp.log 2>&1'.

    Debugging missing environment variables in cron jobs

    In the cron job command, print the environment to a log file as the first operation: env >> /tmp/cron-env-debug.log 2>&1. Comparing this output against your terminal's env output reveals every missing variable immediately. This side-by-side comparison is the fastest way to identify which variables your command needs that cron is not providing, because the diff between the two logs shows exactly which keys are present in one but absent in the other.

    Sharing variables between a systemd service and cron

    For applications managed by systemd, environment variables set in the systemd service unit are not automatically visible to cron jobs because cron is a separate service with its own environment. The reliable way to share variables between a systemd service and its associated cron jobs is to write them to a shared file during service startup and then source that file in the cron command. This decouples the two environments without requiring duplicate variable declarations in both the systemd unit and the crontab. Keep the shared file readable only by the service account when it contains secrets. That limits exposure while preserving the convenience of one source of truth, and while you sort out the environment, you can still prove your cron job fires as planned instead of guessing whether the timing or the environment is the real problem.

    When to use this

    Set SHELL, PATH, and MAILTO in every new crontab to prevent silent failures. Set CRON_TZ when your server runs in UTC but your schedule should follow a local timezone. Pass application-specific variables as crontab variables rather than hardcoding them in the command string.

    Examples

    Crontab preamble for a Python application

    A full preamble covering the four essential variables, placed at the top of the crontab file.

    Passing a database URL to a cron job

    Set the variable above the job line; it is available as $DATABASE_URL inside the command.

    Sources
    1. 1.

      The Open Group, "crontab — schedule periodic background work," opengroup.org, 2018. https://pubs.opengroup.org/onlinepubs/9699919799/utilities/crontab.html

    2. 2.

      Linux man7, "crontab(5) — Linux manual page," man7.org, accessed June 2026. https://www.man7.org/linux/man-pages/man5/crontab.5.html

    3. 3.

      Linux man7, "cron(8) — Linux manual page," man7.org, accessed June 2026. https://www.man7.org/linux/man-pages/man8/cron.8.html

    FAQ