Skip to content

Special Cron Strings (@reboot, @daily, @hourly)

DodaTech Updated 2026-06-28 6 min read

In this tutorial, you will learn about Special Cron Strings (@reboot, @daily, @hourly). We cover key concepts, practical examples, and best practices to help you master this topic.

Use special cron strings like @reboot, @daily, @hourly, @monthly, and @yearly for simpler scheduling without writing five-field expressions every time.

What You Learn

You will learn the eight special cron strings (@reboot, @yearly, @annually, @monthly, @weekly, @daily, @midnight, @hourly), their five-field equivalents, when to use each, and portability considerations.

Why It Matters

Special strings make crontabs more readable. @daily is clearer than 0 0 * * *. They reduce syntax errors and make schedule intent obvious. However, not all cron implementations support them.

Real-World Use

DodaTech uses @reboot to start monitoring agents, @daily for database backups, @hourly for cache warming, and @weekly for analytics reports. Special strings cover 80% of their scheduling needs.

Available Special Strings

# @reboot: Run once when cron daemon starts (at system boot)
@reboot /opt/scripts/startup_checks.sh
@reboot /usr/bin/python3 /opt/agents/monitor.py

# @yearly or @annually: Run once a year (0 0 1 1 *)
@yearly /opt/scripts/cert_renewal.sh
@annually /opt/scripts/yearly_audit.py

# @monthly: Run once a month (0 0 1 * *)
@monthly /opt/scripts/monthly_billing.py
@monthly /opt/scripts/log_archive.sh

# @weekly: Run once a week (0 0 * * 0)
@weekly /opt/scripts/weekly_report.sh
@weekly /opt/scripts/db_optimize.py

# @daily or @midnight: Run once a day (0 0 * * *)
@daily /opt/scripts/daily_backup.sh
@midnight /opt/scripts/log_rotation.py

# @hourly: Run once an hour (0 * * * *)
@hourly /opt/scripts/cache_warm.sh
@hourly /opt/scripts/health_ping.py

Five-Field Equivalents

special_strings = {
    '@reboot':   None,    # Runs at startup, no time equivalent
    '@yearly':   '0 0 1 1 *',
    '@annually': '0 0 1 1 *',
    '@monthly':  '0 0 1 * *',
    '@weekly':   '0 0 * * 0',
    '@daily':    '0 0 * * *',
    '@midnight': '0 0 * * *',
    '@hourly':   '0 * * * *',
}

def explain_special(special):
    if special in special_strings:
        equiv = special_strings[special]
        if equiv:
            print(f"{special:12s} = {equiv:15s} (five-field equivalent)")
        else:
            print(f"{special:12s} = runs at system boot only")
    else:
        print(f"Unknown special string: {special}")

for s in ['@daily', '@reboot', '@weekly', '@yearly']:
    explain_special(s)

Expected output:

@daily       = 0 0 * * *     (five-field equivalent)
@reboot      = runs at system boot only
@weekly      = 0 0 * * 0     (five-field equivalent)
@yearly      = 0 0 1 1 *     (five-field equivalent)

@reboot Deep Dive

# @reboot runs when the cron daemon starts.
# This typically happens at system boot, but also if cron is restarted.

# Use @reboot for:
@reboot /usr/local/bin/start_web_server.sh
@reboot /usr/bin/python3 /opt/agents/register.py
@reboot sleep 10 && /opt/scripts/delayed_startup.sh

# Caution: @reboot does NOT run on user login.
# It runs when crond starts, which is once at boot.

# To delay @reboot execution:
@reboot sleep 30 && /opt/scripts/wait_for_network.sh

# Check if @reboot jobs ran:
grep -i "reboot\|startup" /var/log/syslog | tail -5

@reboot vs systemd

# @reboot in cron is simple but limited.
# For complex startup logic, use systemd:

# /etc/systemd/system/my-startup.service
# [Unit]
# Description=My Startup Service
# After=network.target
#
# [Service]
# Type=oneshot
# ExecStart=/opt/scripts/startup.sh
# RemainAfterExit=yes
#
# [Install]
# WantedBy=multi-user.target

# Enable the service
sudo systemctl enable my-startup.service
sudo systemctl start my-startup.service

# Compare with cron @reboot:
# systemd: dependency management, logging, restart policies
# cron @reboot: simple, no dependencies, runs once

Portability Issues

import os
import subprocess

def check_cron_support():
    """Check if the current cron implementation supports special strings."""
    try:
        result = subprocess.run(
            ['crontab', '-l'],
            capture_output=True, text=True
        )
        crontab_content = result.stdout

        specials = ['@reboot', '@daily', '@hourly', '@weekly', '@monthly', '@yearly']
        supported = []

        for s in specials:
            # Test by attempting to install a temporary crontab
            test_cron = f"{s} echo test\n"
            test_result = subprocess.run(
                ['crontab', '-'],
                input=test_cron,
                capture_output=True, text=True
            )
            if test_result.returncode == 0:
                supported.append(s)

        return supported
    except Exception as e:
        return f"Error: {e}"

# Check if Docker/container cron supports special strings
# Many minimal Docker images use busybox cron which lacks @reboot
# Always test in your target environment

Mixing Special Strings with Regular Syntax

# Crontab mixing special strings and regular expressions

# Special strings for common schedules
@daily /opt/scripts/backup.sh
@hourly /opt/scripts/health.sh

# Regular expressions for precise needs
30 8 * * 1-5 /opt/scripts/business_hours.py
0 0 1 */3 * /opt/scripts/quarterly_report.sh
*/15 9-17 * * 1-5 /opt/scripts/detailed_monitor.py

# @reboot for startup tasks
@reboot /opt/scripts/init_services.sh

Common Mistakes

1. Assuming @reboot Runs on User Login

@reboot runs when crond starts, not when a user logs in. For login scripts, use .bashrc or .profile.

2. Using @reboot in Docker Containers

Many Docker base images use busybox cron which does not support @reboot. Use an ENTRYPOINT script instead.

3. Special Strings in Non-Standard Cron

Not all cron implementations (busybox, anacron, systemd timers) support special strings. Expand to five-field equivalents for portability.

4. Forgetting @reboot Runs Once

@reboot tasks run only when cron starts. If cron is already running, adding a @reboot job does not execute it until the next restart.

5. Mixing @reboot with Time Fields

@reboot is a special string, not a field. Do not add time fields after it. @reboot 0 3 * * * command is invalid.

Practice Questions

1. What is the five-field equivalent of @weekly?

0 0 * * 0 (midnight every Sunday).

2. When does @reboot execute?

When the cron daemon starts, which is typically at system boot. It does not run on user login or at a specific time.

3. What is the difference between @daily and @midnight?

None. Both expand to 0 0 * * *. @midnight is an alias for @daily.

4. Why might @reboot not work in Docker?

Docker containers often use busybox cron which lacks @reboot support. Use a startup script in the container ENTRYPOINT instead.

Challenge

Create a crontab that uses only special strings for: database backup (daily), cache warming (hourly), certificate renewal (yearly), log archiving (weekly), monitoring agent startup (at boot), and billing report (monthly). Then convert all special strings to their five-field equivalents.

FAQ

Can I use @reboot with a delay?

Yes. Add a sleep command: @reboot sleep 30 && /path/to/script.sh. This waits 30 seconds before executing.

Do all cron implementations support @yearly?

Most modern cron implementations (Vixie cron, cronie) support all standard special strings. Busybox cron and anacron may not.

What happens if multiple @reboot jobs are defined?

All @reboot jobs run sequentially when cron starts. Order is not guaranteed. Add sleep delays if ordering matters.

Can I use special strings in system crontab (/etc/crontab)?

Yes, system crontabs support special strings. But /etc/cron.d/ files and /etc/crontab use a different format with an additional user field.

Is @midnight the same as @daily?

Yes, @midnight is an alias for @daily. Both resolve to 0 0 * * *.

Mini Project: Special Strings Crontab

# /etc/cron.d/my-schedules
# Special strings make intent clear

# Startup monitoring agent
@reboot root /usr/local/bin/start-monitor.sh

# Hourly cache warming
@hourly root /usr/local/bin/warm-cache.sh

# Daily security scan
@daily root /usr/local/bin/security-scan.sh

# Weekly report generation
@weekly root /usr/local/bin/generate-report.py

# Monthly log archiving
@monthly root /usr/local/bin/archive-logs.sh

# Yearly certificate renewal reminder
@yearly root /usr/local/bin/renew-certs.sh

# Equivalent five-field version (uncomment to replace above):
# 0 * * * * root /usr/local/bin/warm-cache.sh
# 0 0 * * * root /usr/local/bin/security-scan.sh
# 0 0 * * 0 root /usr/local/bin/generate-report.py
# 0 0 1 * * root /usr/local/bin/archive-logs.sh
# 0 0 1 1 * root /usr/local/bin/renew-certs.sh

What's Next

Now that you understand special cron strings, explore crontab file management for editing and managing Cron Jobs, then learn about environment variables in cron for script configuration.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro