DevTools•Jun 2026•3 min read

Daemon Processes vs System Timers

Long-running daemons versus scheduled system timers (systemd timers, cron) for keeping work happening on a Linux box. One holds state and reacts; the other wakes, runs, and dies. Pick by lifecycle, not by habit.

The short answer

System Timers over Daemon Processes for most cases. For periodic and event-adjacent work, system timers win on operational sanity: no leaked memory, no zombie state, restart semantics handled by the supervisor,.

  • Pick Daemon Processes if the work is continuous, stateful, or sub-second latency-sensitive — a socket listener, a queue consumer, a connection pool, a hot in-memory cache. Things that must already be running when the request arrives
  • Pick System Timers if the work is periodic, batch, or idempotent — backups, syncs, cleanups, report generation, cert renewal. Anything you'd otherwise tempt fate by keeping alive 24/7 to do for 8 seconds an hour
  • Also consider: Don't write a daemon to fake a timer (a while-true-sleep loop is a memory leak with extra steps), and don't fire a timer so often it's a daemon in denial. If your timer interval is under ~10 seconds, you wanted a daemon.

— Nice Pick, opinionated tool recommendations

What they actually are

A daemon is a process that stays resident — it boots, holds memory and file handles, and lives until something kills it. Think nginx, postgres, a queue worker. A system timer is a scheduler that wakes a unit on a calendar or monotonic interval, runs it to completion, and reaps it: cron, or its grown-up successor, systemd timers. The distinction isn't 'background vs foreground' — both run unattended. It's lifecycle. The daemon owns time continuously; the timer borrows it in slices. That single fact decides almost everything downstream: how you handle crashes, where state lives, how you observe the thing, and how badly a bug hurts you at 3am. People pick daemons by reflex because 'always running' feels robust. Always running is also always leaking, always accumulating, and always one OOM-kill from silent death. Resident is a cost, not a feature.

Reliability and failure modes

A daemon's failure mode is the nasty one: it doesn't crash, it degrades. Memory creeps, a connection goes stale, a counter wraps, and it keeps reporting healthy while quietly doing nothing useful. You find out from the downstream, not the daemon. Timers fail loud and clean — the unit runs, exits non-zero, and that's a discrete, alertable event with a start and an end. systemd gives you OnFailure=, Restart policy, RandomizedDelaySec to dodge thundering herds, and Persistent=true to catch runs missed while the box was off. Cron, by contrast, swallows output unless you wire up MAILTO and silently runs in a stripped PATH that doesn't match your shell — the classic 'works by hand, dies in cron' trap. Daemons need their own watchdog, health probe, and restart supervisor reinvented per service. Timers inherit all of that from the init system for free. Fewer moving parts you wrote yourself means fewer parts that betray you.

Observability and operations

With systemd timers you get this for nothing: systemctl list-timers shows last-run and next-run at a glance, journalctl -u yourjob gives you per-invocation logs with exit codes, and each run is bounded so 'is it stuck?' has an actual answer. A daemon's logs are a continuous stream you have to slice by time and correlate by hand, and 'stuck' looks identical to 'idle.' Resource accounting is cleaner too — a timer unit's CPU and memory are attributed to a transient scope that vanishes when it exits, so a runaway run can't poison the next one. Daemons share one long-lived cgroup where yesterday's leak is today's baseline. Deploys are also less violent: restarting a timer is a no-op, while restarting a daemon means draining in-flight work and praying your shutdown handler is correct. Operationally, timers are boring. Boring is the highest compliment infrastructure can earn.

When the daemon is the right call

None of this means daemons are wrong — it means they're specialized. If work must be in-memory and warm before the request lands, a timer can't help you: process startup, connection setup, and cache warming cost too much to pay per invocation. Socket servers, queue consumers with long-poll, websocket hubs, anything holding a stateful protocol connection, anything needing sub-second reaction — that's daemon territory, full stop. The mistake is using a daemon for episodic work because spinning up feels expensive, then babysitting a long-lived process to do a 5-second job hourly. If you do need a daemon, at least run it under systemd as a Type=notify service with a watchdog and resource limits, so you're not hand-rolling supervision the init system already ships. The honest test: does the work need to be alive between runs? If no, you wanted a timer and were too sentimental to admit it.

Quick Comparison

FactorDaemon ProcessesSystem Timers
Resource footprint when idleResident — holds RAM, handles, and connections 24/7 even when doing nothingZero between runs — process exists only while working
Failure visibilitySilent degradation; looks healthy while leaking or stalledDiscrete non-zero exits, alertable per run via OnFailure=
Observability out of the boxContinuous log stream; 'stuck' indistinguishable from 'idle'list-timers + per-invocation journald logs with exit codes
Latency / warm stateAlready-warm memory, pooled connections, sub-second reactionPays startup and connection cost on every invocation
Supervision you must build yourselfHealth probe, restart policy, watchdog reinvented per serviceRestart, missed-run catchup, jitter inherited from systemd

The Verdict

Use Daemon Processes if: The work is continuous, stateful, or sub-second latency-sensitive — a socket listener, a queue consumer, a connection pool, a hot in-memory cache. Things that must already be running when the request arrives.

Use System Timers if: The work is periodic, batch, or idempotent — backups, syncs, cleanups, report generation, cert renewal. Anything you'd otherwise tempt fate by keeping alive 24/7 to do for 8 seconds an hour.

Consider: Don't write a daemon to fake a timer (a while-true-sleep loop is a memory leak with extra steps), and don't fire a timer so often it's a daemon in denial. If your timer interval is under ~10 seconds, you wanted a daemon.

Daemon Processes vs System Timers: FAQ

Is Daemon Processes or System Timers better?

System Timers is the Nice Pick. For periodic and event-adjacent work, system timers win on operational sanity: no leaked memory, no zombie state, restart semantics handled by the supervisor, and logs you can actually find. Reach for a daemon only when the work is genuinely continuous or latency-sensitive.

When should you use Daemon Processes?

The work is continuous, stateful, or sub-second latency-sensitive — a socket listener, a queue consumer, a connection pool, a hot in-memory cache. Things that must already be running when the request arrives.

When should you use System Timers?

The work is periodic, batch, or idempotent — backups, syncs, cleanups, report generation, cert renewal. Anything you'd otherwise tempt fate by keeping alive 24/7 to do for 8 seconds an hour.

What's the main difference between Daemon Processes and System Timers?

Long-running daemons versus scheduled system timers (systemd timers, cron) for keeping work happening on a Linux box. One holds state and reacts; the other wakes, runs, and dies. Pick by lifecycle, not by habit.

How do Daemon Processes and System Timers compare on resource footprint when idle?

Daemon Processes: Resident — holds RAM, handles, and connections 24/7 even when doing nothing. System Timers: Zero between runs — process exists only while working. System Timers wins here.

Are there alternatives to consider beyond Daemon Processes and System Timers?

Don't write a daemon to fake a timer (a while-true-sleep loop is a memory leak with extra steps), and don't fire a timer so often it's a daemon in denial. If your timer interval is under ~10 seconds, you wanted a daemon.

🧊
The Bottom Line
System Timers wins

For periodic and event-adjacent work, system timers win on operational sanity: no leaked memory, no zombie state, restart semantics handled by the supervisor, and logs you can actually find. Reach for a daemon only when the work is genuinely continuous or latency-sensitive.

Related Comparisons

Disagree? nice@nicepick.dev