Skip to main content
Daniel J Glover
Back to Blog

Why every script needs a dry-run flag

5 min read
Article overview
Written by Daniel J Glover

Practical perspective from an IT leader working across operations, security, automation, and change.

Published 1 February 2026

5 minute read with practical, decision-oriented guidance.

Best suited for

Leaders and operators looking for concise, actionable takeaways.

There is a post trending on Hacker News today about the --dry-run flag. Henrik Warne writes about adding it to a reporting application early in development and being surprised by how useful it became. I have been nodding along because this matches my experience exactly.

A --dry-run option lets you inspect intended changes before executing them. If you have ever run rsync --dry-run before committing to a massive file sync, or used terraform plan before terraform apply, you already know the value.

What dry-run actually means

A dry-run flag tells your script to show what it would do without actually doing it. Print the files that would be deleted. Log the API calls that would be made. Display the database rows that would be updated. Then exit without changing anything.

The preview should show intended changes without executing them.

When a colleague asks "what will this script do?", you should be able to run it with --dry-run and show them. The preview should leave no changes to clean up.

Where this matters most

Database migrations

Before running a migration that modifies production data, a dry-run should output:

  • How many rows will be affected
  • Sample of the changes (first 10 rows, perhaps)
  • Any constraints that might fail
  • Estimated execution time

File operations

Scripts that move, rename, or delete files should preview the operations. I once watched a junior engineer accidentally delete a week of customer uploads because a cleanup script had no preview mode. That script has a --dry-run flag now.

API integrations

For external actions such as sending email, posting to Slack or updating CRM records, a dry-run should log the proposed action without executing it. This is invaluable for testing integrations without spamming real systems.

Infrastructure changes

Terraform popularised plan before apply. Ansible has --check mode. Kubernetes has --dry-run=client. These tools understood that showing the diff before making changes reduces incidents significantly.

Implementation patterns

The simplest approach is a global flag that gates all side effects:

def delete_old_files(directory, dry_run=False):
    files = find_files_older_than(directory, days=30)
    
    for file in files:
        if dry_run:
            print(f"Would delete: {file}")
        else:
            os.remove(file)
            print(f"Deleted: {file}")
    
    print(f"Total: {len(files)} files {'would be' if dry_run else ''} deleted")

For more complex scripts, consider a transaction-style approach where you collect all intended actions, display them, then execute only if not in dry-run mode:

class ActionPlan:
    def __init__(self):
        self.actions = []
    
    def add(self, description, execute_fn):
        self.actions.append((description, execute_fn))
    
    def preview(self):
        for desc, _ in self.actions:
            print(f"  - {desc}")
    
    def execute(self, dry_run=False):
        if dry_run:
            print("Dry run - the following actions would be taken:")
            self.preview()
            return
        
        for desc, fn in self.actions:
            print(f"Executing: {desc}")
            fn()

The hidden benefit: better logging

Adding dry-run support forces you to think about what your script actually does. You cannot preview an action without first describing it clearly. This naturally improves your logging, error messages, and overall observability.

Scripts with good dry-run output tend to have good production logging too. The same descriptions you write for preview mode become your audit trail.

Common objections

"IT adds complexity"

Yes, but minimal complexity. A single boolean flag and some conditional prints. Previewing changes is easier to review than diagnosing an unexpected destructive action.

"Our scripts are simple enough"

Adding preview support early lets you test it as the script grows. Retrofitting it after an incident may miss existing side effects.

"We have staging environments"

Staging helps, but it is not the same as previewing against production data. A dry-run against your actual database shows you what will really happen, not what would happen to synthetic test data.

Making it the default

I have started making --dry-run the default for destructive scripts. You have to explicitly pass --execute or --no-dry-run to make changes. This requires an explicit execution flag before the script changes data.

$ ./cleanup-old-data.py
$ ./cleanup-old-data.py --execute

This is particularly valuable for scripts that run via cron or automation. A misconfigured job that runs in dry-run mode by default produces logs instead of damage.

Use previews in routine work

Henrik Warne added --dry-run on a whim and found himself using it daily. That matches my experience. It can help before deployments, during debugging and incident response, and when demonstrating changes to stakeholders.

The pattern is old. Subversion had it. rsync has had it for decades. But it remains underused in custom scripts and internal tools. Automation that changes state should provide a way to preview those changes.

Test that the preview path leaves data unchanged before relying on it.

If you are building automation that touches production systems, dry-run is just one layer of defence. Pair it with proper governance controls and a solid engineering practice to keep technical debt from creeping in. For hands-on support with engineering practices, automation architecture, or infrastructure design, my technical consulting practice can help.


Inspired by Henrik Warne's post which is worth reading in full.

Share this post

About the author

DG

Daniel J Glover

IT Leader with experience spanning IT management, compliance, development, automation, AI, and project management. I write about technology, leadership, and building better systems.

Continue exploring

Keep building context around this topic

Jump to closely related posts and topic hubs to deepen understanding and discover connected ideas faster.

Browse all articles

Ready to improve your IT operations?

Request a free 30-minute consultation to discuss your IT challenges. Send a short outline and I will reply to arrange a suitable time. No obligation.

Request a free 30-minute consultation

Get Occasional IT Leadership Insights

IT leadership insights, occasionally. No fluff. Unsubscribe any time.

No spam. Unsubscribe any time.