Docs / Automation & IaC / Use Justfile as a Task Runner for DevOps

Use Justfile as a Task Runner for DevOps

By Admin · Mar 15, 2026 · Updated Apr 23, 2026 · 173 views · 4 min read

Just is a modern command runner that provides a convenient way to save and run project-specific commands. Think of it as a modern, more user-friendly alternative to Makefiles for DevOps task automation. With a simple syntax and powerful features, Justfile helps standardize common operations across your team.

Why Just over Make?

  • Simpler syntax: No tabs-vs-spaces issues, no implicit rules
  • Better error messages: Clear, helpful error reporting
  • Built-in features: Variable interpolation, conditionals, OS detection, dotenv support
  • Cross-platform: Works on Linux, macOS, and Windows
  • Not a build system: Focused on running commands, not tracking file dependencies

Installation

# Install on Linux
curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/local/bin

# Or via package managers
# Ubuntu/Debian
sudo apt install just

# macOS
brew install just

# Verify
just --version

DevOps Justfile

# justfile — DevOps task runner

# Load environment variables from .env
set dotenv-load

# Default recipe (runs when you type 'just')
default:
    @just --list

# ============ Server Management ============

# SSH into a server
ssh server="web1":
    ssh deploy@{{server}}.example.com

# Check server status across all hosts
status:
    @echo "=== Server Status ==="
    ansible all -m shell -a "uptime && df -h / | tail -1" -i inventory/production

# Update packages on all servers
update-packages:
    ansible-playbook playbooks/patch-servers.yml -i inventory/production

# Reboot a specific server with confirmation
reboot server:
    @echo "About to reboot {{server}}.example.com"
    @read -p "Are you sure? (y/N) " confirm && [ "$$confirm" = "y" ] || exit 1
    ssh deploy@{{server}}.example.com 'sudo reboot'

# ============ Deployment ============

# Deploy application to production
deploy version="latest":
    @echo "Deploying version {{version}} to production..."
    ansible-playbook playbooks/deploy.yml \
        -i inventory/production \
        -e "app_version={{version}}"

# Deploy to staging first
deploy-staging version="latest":
    ansible-playbook playbooks/deploy.yml \
        -i inventory/staging \
        -e "app_version={{version}}"

# Rolling restart of web servers
rolling-restart:
    ansible webservers -m systemd -a "name=webapp state=restarted" \
        -i inventory/production --forks 1

# ============ Database ============

# Create database backup
db-backup:
    #!/usr/bin/env bash
    set -euo pipefail
    TIMESTAMP=$(date +%Y%m%d_%H%M%S)
    echo "Creating backup: db_backup_${TIMESTAMP}.sql.gz"
    ssh db1.example.com "pg_dump -U postgres myapp | gzip" > \
        backups/db_backup_${TIMESTAMP}.sql.gz
    echo "Backup saved: backups/db_backup_${TIMESTAMP}.sql.gz"

# Restore database from backup
db-restore file:
    @echo "Restoring from {{file}}"
    @read -p "This will OVERWRITE the database. Continue? (y/N) " confirm && [ "$$confirm" = "y" ] || exit 1
    zcat {{file}} | ssh db1.example.com "psql -U postgres myapp"

# ============ SSL Certificates ============

# Renew all SSL certificates
ssl-renew:
    /opt/scripts/ssl-renew-and-deploy.sh

# Check certificate expiry dates
ssl-check:
    /opt/scripts/check-ssl-expiry.sh

# ============ Docker ============

# Build and push Docker image
docker-build tag="latest":
    docker build -t myapp:{{tag}} .
    docker tag myapp:{{tag}} registry.example.com/myapp:{{tag}}
    docker push registry.example.com/myapp:{{tag}}

# Clean up Docker resources
docker-clean:
    docker system prune -af --volumes

# ============ Monitoring ============

# View recent logs
logs service="webapp" lines="100":
    ssh web1.example.com "journalctl -u {{service}} -n {{lines}} --no-pager"

# Check disk usage across all servers
disk-usage:
    ansible all -m shell -a "df -h / | tail -1" -i inventory/production

# ============ Terraform ============

# Plan infrastructure changes
tf-plan env="production":
    cd terraform && \
    terraform workspace select {{env}} && \
    terraform plan -var-file="environments/{{env}}.tfvars"

# Apply infrastructure changes
tf-apply env="production":
    cd terraform && \
    terraform workspace select {{env}} && \
    terraform apply -var-file="environments/{{env}}.tfvars"

Advanced Features

# Conditional logic based on OS
backup_cmd := if os() == "linux" { "tar czf" } else { "zip -r" }

# Set shell
set shell := ["bash", "-euo", "pipefail", "-c"]

# Private recipes (not shown in --list)
[private]
_check-ssh-agent:
    @ssh-add -l > /dev/null 2>&1 || (echo "SSH agent not running" && exit 1)

# Recipe dependencies
deploy version="latest": _check-ssh-agent
    @echo "Deploying {{version}}..."

# Run recipes from a different directory
[working-directory: 'terraform']
tf-init:
    terraform init

# Confirm before running
[confirm("Are you sure you want to deploy to production?")]
deploy-prod:
    ansible-playbook deploy.yml -i production

# OS-specific recipes
[linux]
install-deps:
    sudo apt install -y ansible terraform

[macos]
install-deps:
    brew install ansible terraform

Team Usage

# List all available commands
just --list

# Output:
# Available recipes:
#     db-backup          # Create database backup
#     db-restore file    # Restore database from backup
#     deploy version     # Deploy application to production
#     deploy-staging     # Deploy to staging first
#     disk-usage         # Check disk usage across all servers
#     docker-build tag   # Build and push Docker image
#     logs service lines # View recent logs
#     ssl-check          # Check certificate expiry dates
#     ssh server         # SSH into a server
#     status             # Check server status
#     tf-plan env        # Plan infrastructure changes

# Run with arguments
just deploy v2.1.0
just ssh web2
just logs nginx 500
just tf-plan staging

Best Practices

  • Commit your justfile to version control — it documents common operations
  • Add descriptions as comments above recipes for just --list documentation
  • Use confirmation prompts for destructive operations
  • Set default values for optional parameters to reduce typing
  • Use private recipes (prefix with _) for helper tasks
  • Load secrets from .env with set dotenv-load instead of hardcoding

Was this article helpful?