Work Avoidance¶
Skip work when the outcome won't change.
Detect Before Execute
Check if work is needed before starting it. Avoid creating PRs for unchanged content, running builds for unchanged code, or processing already-processed items.
Overview¶
Work avoidance detects when an operation isn't needed and skips it entirely. Unlike idempotency (which makes reruns safe), work avoidance prevents the run from happening at all.
flowchart LR
subgraph trigger[Trigger]
Event[Event Received]
end
subgraph detect[Detection]
Check{Work Needed?}
end
subgraph action[Action]
Skip[Skip]
Execute[Execute]
end
Event --> Check
Check -->|No| Skip
Check -->|Yes| Execute
%% Ghostty Hardcore Theme
style Event fill:#65d9ef,color:#1b1d1e
style Check fill:#fd971e,color:#1b1d1e
style Skip fill:#5e7175,color:#f8f8f3
style Execute fill:#a7e22e,color:#1b1d1e
Work Avoidance vs Idempotency¶
Both patterns make automation safe to rerun, but they optimize for different things:
| Concern | Idempotency | Work Avoidance |
|---|---|---|
| Focus | Safe re-execution | Skipping execution |
| Question | "Can I run this again safely?" | "Should I run this at all?" |
| Resource usage | Uses resources on rerun | Saves resources |
| Implementation | Logic inside operation | Logic before operation |
Best practice: Apply work avoidance first, then ensure remaining operations are idempotent.
Techniques¶
Work avoidance uses different techniques depending on what you're checking:
| Technique | Question | Best For |
|---|---|---|
| Content Hashing | "Is the content different?" | File comparisons, config sync |
| Volatile Field Exclusion | "Did anything meaningful change?" | Version bumps, timestamps |
| Existence Checks | "Does it already exist?" | Resource creation (PRs, branches) |
| Cache-Based Skip | "Is the output already built?" | Build artifacts, dependencies |
| Queue Cleanup | "Should queued work execute?" | Mutex-locked workflows |
See Techniques Overview for detailed comparisons and when to use each.
When to Apply¶
Work avoidance is valuable when:
- Distribution workflows push files to many repositories
- Release automation bumps versions without content changes
- Scheduled jobs run regardless of whether work exists
- Monorepo builds trigger on any change but only need subset builds
- API synchronization needs to detect actual drift
- Mutex-locked workflows queue identical operations behind a lock
Anti-Patterns¶
Common mistakes that undermine work avoidance:
- Over-aggressive skipping - Checking existence, not content
- Ignoring error states - Trusting markers without validation
- Stripping too much - Destroying semantic content with broad patterns
- Stale cache keys - Missing inputs that affect output
See Anti-Patterns for details and fixes.
Quick Example¶
A file distribution workflow that skips version-only changes:
- name: Check for meaningful changes
id: check
run: |
# Strip version line before comparing
strip_version() {
sed '/^version:.*# x-release-please-version$/d' "$1"
}
SOURCE=$(strip_version "source/CONFIG.md")
TARGET=$(git show HEAD:CONFIG.md 2>/dev/null | \
sed '/^version:.*# x-release-please-version$/d' || echo "")
if [ "$SOURCE" = "$TARGET" ]; then
echo "skip=true" >> $GITHUB_OUTPUT
else
echo "skip=false" >> $GITHUB_OUTPUT
fi
- name: Distribute file
if: steps.check.outputs.skip != 'true'
run: ./distribute.sh
This applies Volatile Field Exclusion to avoid creating PRs for version-only changes.
Implementation Examples¶
- GitHub Actions: Work Avoidance - CI/CD implementation patterns
- File Distribution - Real-world workflow using these patterns
Related¶
- Idempotency - Making operations safe to repeat
- Graceful Degradation - Fallback when detection fails
- Three-Stage Design - Workflow structure that enables work avoidance