Introduction to macOS Automator Workflows
macOS Automator is a built-in automation tool that ships with every Mac, allowing developers and power users to chain together actions into reusable workflows. While many developers reach for shell scripts, Python, or AppleScript first, Automator provides a visual environment for assembling pipelines that can process files, manipulate text, control applications, and expose custom services across the operating system.
At its core, an Automator workflow is a directed graph of actions. Each action receives input, performs work, and passes output to the next action. Workflows can be saved as standalone applications, system Services, Print Plugins, Folder Actions, or Image Capture plugins—making them surprisingly versatile for both personal productivity and lightweight internal tooling.
Why Automator Matters for Developers
For developers, Automator occupies a useful niche between one-off shell scripts and full-fledged applications. It excels at scenarios where you want to integrate with GUI applications, expose functionality to non-technical teammates, or build quick utilities without spinning up an Xcode project.
- Rapid prototyping: Drag actions together to test an idea before committing to code.
- System integration: Services appear in the right-click menu and can be bound to keyboard shortcuts.
- Folder watching: Automate file processing without writing a launchd daemon.
- Hybrid automation: Embed shell scripts, AppleScript, and JavaScript for Automation (JXA) inside a visual pipeline.
- Distribution simplicity: Save a workflow as an
.appand ship it to colleagues—no dependencies required.
Understanding Workflow Types
When you create a new document in Automator (located in /Applications/Automator.app), you choose a workflow type. Each type determines how the workflow is triggered and where it appears in the system.
Standard Workflow
A general-purpose workflow you run manually from within Automator or as a saved application. Useful for batch processing tasks you trigger on demand.
Application
Saved as a standalone .app bundle. You can drag files onto it in Finder to feed them as input. This is ideal for distributing utilities to other users.
Service
Appears in the Services submenu of contextual menus and application menus. Services accept input from the current application (selected text, files, images) and can be assigned keyboard shortcuts in System Settings > Keyboard > Keyboard Shortcuts > Services.
Folder Action
Attached to a specific folder. Whenever files are added to that folder, the workflow runs automatically with those files as input. This replaces the need for a custom file watcher daemon in many cases.
Print Plugin and Image Capture Plugin
Print Plugins appear in the PDF menu of the macOS print dialog. Image Capture Plugins appear when importing photos from a camera or scanner. Both are niche but powerful for document and media pipelines.
Building Your First Workflow
Let's build a practical workflow that resizes selected images to a maximum width of 1200 pixels and saves them as JPEGs in a resized subfolder. This demonstrates file input, image processing, and shell script integration.
Step-by-Step
- Open Automator and choose Service as the document type.
- At the top, set "Service receives selected" to image files in any application.
- Drag the Copy Finder Items action from the library into the workflow. Configure it to create a folder named
resizedin the same directory. - Drag the Run Shell Script action below it. Set "Pass input" to as arguments.
- Paste the script below into the action.
- Save the service as "Resize Images for Web".
#!/bin/bash
# Process each image passed as an argument
for f in "$@"; do
# Use sips (built-in macOS image tool) to resize
# -Z resizes so the longest side matches the value, preserving aspect ratio
sips -Z 1200 "$f" --out "$f"
# Convert to JPEG with quality 80
sips -s format jpeg -s formatOptions 80 "$f" --out "${f%.*}.jpg"
# Remove the original copied file if it wasn't already a jpg
if [[ "$f" != *.jpg ]]; then
rm "$f"
fi
done
echo "Resized $(echo "$@" | wc -w | tr -d ' ') image(s)"
Now, select any image files in Finder, right-click, and choose "Resize Images for Web" from the Services menu. The images will be copied into a resized folder, resized, and converted to JPEG.
Embedding AppleScript and JXA
Automator's Run AppleScript and Run JavaScript actions let you orchestrate macOS applications that lack a command-line interface. This is where Automator shines over pure shell scripting.
AppleScript Example: Create a New GitHub Issue Draft in Notes
-- Receive selected text as input and create a note
on run {input, parameters}
set issueText to ""
repeat with anItem in input
set issueText to issueText & anItem & return
end repeat
tell application "Notes"
set newNote to make new note with properties {name:"Issue Draft", body:issueText}
show newNote
end tell
return input
end run
JavaScript for Automation (JXA) Example
JXA is Apple's modern scripting bridge using JavaScript syntax. It can be more approachable for developers already familiar with JavaScript.
// Run JavaScript action: count lines in selected text files
function run(input, parameters) {
var app = Application.currentApplication();
app.includeStandardAdditions = true;
var totalLines = 0;
for (var i = 0; i < input.length; i++) {
var path = input[i].toString();
var content = app.read(path);
var lines = content.split("\n").length;
totalLines += lines;
}
app.displayDialog("Total lines: " + totalLines, {
withTitle: "Line Counter",
buttons: ["OK"],
defaultButton: "OK"
});
return input;
}
Folder Actions in Practice
Folder Actions are one of the most useful workflow types for developers. A common use case is automatically organizing screenshots or downloaded files by extension.
Auto-Sort Downloads by Extension
- Create a new Folder Action workflow.
- Select your
~/Downloadsfolder as the target. - Add a Run Shell Script action with "Pass input" set to as arguments.
- Use the following script.
#!/bin/bash
DOWNLOADS="$HOME/Downloads"
for f in "$@"; do
# Skip directories
[ -d "$f" ] && continue
# Extract extension (lowercase)
ext=$(echo "${f##*.}" | tr '[:upper:]' '[:lower:]')
# Skip if no extension
[ "$ext" = "$(basename "$f")" ] && continue
# Create category folder
case "$ext" in
jpg|jpeg|png|gif|heic|webp) category="Images" ;;
pdf|doc|docx|txt|md|rtf) category="Documents" ;;
zip|tar|gz|rar|7z) category="Archives" ;;
mp4|mov|avi|mkv) category="Videos" ;;
mp3|wav|flac|m4a) category="Audio" ;;
dmg|pkg|app) category="Installers" ;;
*) category="Other" ;;
esac
mkdir -p "$DOWNLOADS/$category"
mv "$f" "$DOWNLOADS/$category/"
done
Attach this Folder Action to your Downloads folder, and every new file will be sorted automatically into categorized subfolders.
Combining Actions for Complex Pipelines
The real power of Automator emerges when you chain multiple actions. Consider a workflow that processes a selected text file: extracts URLs, validates them with curl, and writes a report.
Workflow Structure
- Get Selected Finder Items — captures the selected file.
- Run Shell Script — extracts URLs using grep and validates each with curl.
- New Text File — saves the report to your Desktop.
#!/bin/bash
# Extract URLs from input file and check HTTP status
input_file="$1"
report="$HOME/Desktop/url_report.txt"
# Extract http(s) URLs
urls=$(grep -oE 'https?://[^[:space:]"<>]+' "$input_file" | sort -u)
echo "URL Validation Report - $(date)" > "$report"
echo "Source: $input_file" >> "$report"
echo "----------------------------------------" >> "$report"
while IFS= read -r url; do
[ -z "$url" ] && continue
status=$(curl -o /dev/null -s -w "%{http_code}" -I --max-time 10 "$url")
if [ "$status" -ge 200 ] && [ "$status" -lt 400 ]; then
echo "[OK] $status $url" >> "$report"
else
echo "[FAIL] $status $url" >> "$report"
fi
done <<< "$urls"
echo "----------------------------------------" >> "$report"
echo "Report saved to $report"
Best Practices
1. Prefer Shell Scripts for Heavy Lifting
Automator's built-in actions are convenient, but for anything involving loops, conditionals, or data transformation, a Run Shell Script action is more maintainable and testable. You can develop the script in your terminal first, then paste it into Automator once it works.
2. Always Handle Empty Input
Workflows often receive unexpected input. Guard your scripts against empty arguments to avoid silent failures.
#!/bin/bash
if [ $# -eq 0 ]; then
osascript -e 'display notification "No input provided" with title "Workflow Error"'
exit 1
fi
3. Use Absolute Paths
Automator runs shell scripts with a minimal environment. Do not assume PATH includes Homebrew directories or custom binaries. Set the path explicitly at the top of your scripts.
#!/bin/bash
export PATH="/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin:$PATH"
4. Provide User Feedback
For long-running workflows, show notifications so users know progress. Use osascript for native macOS notifications.
osascript -e 'display notification "Processed 42 files" with title "Resize Workflow"'
5. Version Control Your Workflows
Automator files (.workflow) are XML property lists under the hood. Store them in Git alongside your other dotfiles and scripts. This makes them diffable and shareable across machines.
# Convert a workflow to readable XML for diffing
plutil -convert xml1 MyWorkflow.workflow/Contents/document.wflow
6. Test with Sample Input
Before saving a Service or Folder Action, test it inside Automator by clicking the Run button. You can drag sample files into the workflow input area to simulate real input.
7. Document the Purpose
Add a comment at the top of every shell script action explaining what the workflow does, its expected input, and its output. Automator workflows can become opaque months after you create them.
Debugging Workflows
Debugging Automator workflows can be tricky because errors are often swallowed silently. Use these techniques to surface problems.
Log to a File
#!/bin/bash
LOG="$HOME/Desktop/automator_debug.log"
echo "[$(date)] Workflow started with args: $@" >> "$LOG"
# ... your logic ...
echo "[$(date)] Workflow finished" >> "$LOG"
View Console Output
Open the Console app and filter by the process name or your script's output. Errors from osascript and shell commands often appear here.
Use set -x for Tracing
#!/bin/bash
set -x # Print each command before execution
# ... your logic ...
set +x
Exposing Workflows as Keyboard Shortcuts
Once you save a Service workflow, you can bind it to a global keyboard shortcut. Navigate to System Settings > Keyboard > Keyboard Shortcuts > Services, find your service under the appropriate category, and assign a shortcut. This turns any Automator workflow into a productivity-boosting hotkey.
For example, a Service that formats selected JSON in your clipboard can be bound to Cmd+Shift+J, giving you instant JSON prettification from anywhere.
#!/bin/bash
# Format JSON from clipboard and paste it back
input=$(pbpaste)
echo "$input" | python3 -m json.tool | pbcopy
osascript -e 'tell application "System Events" to keystroke "v" using command down'
Conclusion
macOS Automator is a deceptively powerful tool that bridges the gap between visual workflow design and serious scripting. By combining built-in actions with shell scripts, AppleScript, and JXA, you can build reusable utilities that integrate deeply with macOS—without the overhead of a full application project. Whether you need a quick Service to reformat text, a Folder Action to organize downloads, or a distributable application for non-technical teammates, Automator provides a fast path from idea to working tool. Start with simple workflows, test thoroughly, version control your files, and gradually compose more complex pipelines as you become comfortable with the action library and scripting bridges.