Why Automate File Conversions?
Manual file conversion is a time sink. If you regularly convert video for social media, resize images for your website, transform documents for clients, or process uploaded files in your application, those repetitive tasks add up to hours of lost productivity every week.
Automation eliminates this repetitive work entirely. A well-designed conversion pipeline runs unattended, processes files consistently, scales to any volume, and frees you to focus on work that actually requires human judgment.
This guide covers every major approach to automating file conversions, from simple shell scripts to enterprise-grade API integrations, with practical examples you can implement today.

Shell Scripts: The Foundation
Shell scripts are the fastest way to automate conversions for anyone comfortable with the command line. They require no additional infrastructure — just the conversion tools and a script file.
FFmpeg for Video and Audio
FFmpeg is the backbone of nearly every video and audio conversion pipeline in existence. It supports virtually every media format and provides granular control over every encoding parameter.
Basic video conversion script:
#!/bin/bash
# convert-videos.sh — Convert all videos in a folder to MP4 (H.264)
INPUT_DIR="${1:-.}"
OUTPUT_DIR="${2:-./converted}"
mkdir -p "$OUTPUT_DIR"
for file in "$INPUT_DIR"/*.{avi,mkv,mov,wmv,flv,webm}; do
[ -f "$file" ] || continue
filename=$(basename "${file%.*}")
echo "Converting: $file"
ffmpeg -i "$file" \
-c:v libx264 -preset medium -crf 23 \
-c:a aac -b:a 128k \
-movflags +faststart \
"$OUTPUT_DIR/${filename}.mp4"
echo "Done: ${filename}.mp4"
done
echo "All conversions complete."
Audio extraction from video:
#!/bin/bash
# extract-audio.sh — Extract audio from video files as MP3
for video in "$1"/*.{mp4,mkv,mov,avi}; do
[ -f "$video" ] || continue
filename=$(basename "${video%.*}")
ffmpeg -i "$video" \
-vn -acodec libmp3lame -q:a 2 \
"$2/${filename}.mp3"
done
Batch video compression:
#!/bin/bash
# compress-videos.sh — Compress videos to a target file size
TARGET_MB=25 # Target 25 MB (for email attachments)
for video in "$1"/*.mp4; do
[ -f "$video" ] || continue
duration=$(ffprobe -v error -show_entries format=duration \
-of default=noprint_wrappers=1:nokey=1 "$video")
target_bitrate=$(echo "scale=0; ($TARGET_MB * 8192) / $duration" | bc)
filename=$(basename "$video")
ffmpeg -i "$video" \
-c:v libx264 -b:v "${target_bitrate}k" -pass 1 -f null /dev/null
ffmpeg -i "$video" \
-c:v libx264 -b:v "${target_bitrate}k" -pass 2 \
-c:a aac -b:a 96k \
"$2/$filename"
done
For a deeper understanding of video conversion parameters, explore our video converter tool page.
ImageMagick for Images
ImageMagick handles image format conversion, resizing, compression, and manipulation from the command line.
Batch image conversion and optimization:
#!/bin/bash
# optimize-images.sh — Convert and optimize images for web
INPUT_DIR="${1:-.}"
OUTPUT_DIR="${2:-./optimized}"
mkdir -p "$OUTPUT_DIR"
for img in "$INPUT_DIR"/*.{png,tiff,bmp,heic,raw}; do
[ -f "$img" ] || continue
filename=$(basename "${img%.*}")
# Convert to JPEG, resize to max 1920px width, quality 85
magick "$img" \
-resize '1920x1920>' \
-quality 85 \
-strip \
-interlace Plane \
"$OUTPUT_DIR/${filename}.jpg"
echo "Optimized: ${filename}.jpg"
done
Generate thumbnails:
#!/bin/bash
# thumbnails.sh — Generate thumbnails at multiple sizes
SIZES=(150 300 600 1200)
for img in "$1"/*.{jpg,jpeg,png,webp}; do
[ -f "$img" ] || continue
filename=$(basename "${img%.*}")
ext="${img##*.}"
for size in "${SIZES[@]}"; do
magick "$img" \
-resize "${size}x${size}" \
-quality 80 \
"$2/${filename}-${size}w.${ext}"
done
done
For more on image optimization strategies, see our image converter and our guide on optimizing images for websites.
Pandoc and LibreOffice for Documents
Batch document conversion:
#!/bin/bash
# convert-docs.sh — Convert DOCX files to PDF
for doc in "$1"/*.docx; do
[ -f "$doc" ] || continue
filename=$(basename "${doc%.*}")
pandoc "$doc" -o "$2/${filename}.pdf" \
--pdf-engine=xelatex \
-V geometry:margin=1in
echo "Converted: ${filename}.pdf"
done
LibreOffice headless conversion (broader format support):
#!/bin/bash
# libreoffice-convert.sh — Convert office docs to PDF using LibreOffice
libreoffice --headless --convert-to pdf --outdir "$2" "$1"/*.{docx,xlsx,pptx,odt,ods,odp}
LibreOffice's headless mode is particularly useful because it handles the full range of office formats, including complex spreadsheets and presentations that Pandoc cannot process. Use our PDF converter for a browser-based alternative.
Watch Folders: Automatic Conversion on File Drop
A watch folder monitors a directory and automatically converts any new file that appears. This creates a dead-simple workflow: drop a file in the input folder, find the converted result in the output folder.
Using fswatch (macOS/Linux)
#!/bin/bash
# watch-convert.sh — Watch a folder and convert new files automatically
INPUT_DIR="$HOME/ConvertInput"
OUTPUT_DIR="$HOME/ConvertOutput"
mkdir -p "$INPUT_DIR" "$OUTPUT_DIR"
echo "Watching $INPUT_DIR for new files..."
fswatch -0 "$INPUT_DIR" | while IFS= read -r -d '' file; do
# Skip temporary files and directories
[ -f "$file" ] || continue
[[ "$file" == *.part ]] && continue
[[ "$file" == .* ]] && continue
ext="${file##*.}"
filename=$(basename "${file%.*}")
case "$ext" in
avi|mkv|mov|wmv|flv)
echo "Converting video: $file"
ffmpeg -i "$file" -c:v libx264 -crf 23 -c:a aac \
"$OUTPUT_DIR/${filename}.mp4"
;;
png|tiff|bmp|heic)
echo "Converting image: $file"
magick "$file" -resize '1920x1920>' -quality 85 \
"$OUTPUT_DIR/${filename}.jpg"
;;
docx|odt)
echo "Converting document: $file"
pandoc "$file" -o "$OUTPUT_DIR/${filename}.pdf"
;;
*)
echo "Skipping unsupported format: $ext"
;;
esac
done
Using systemd on Linux (Production)
For a production watch folder that runs as a system service:
# /etc/systemd/system/file-converter.service
[Unit]
Description=File Conversion Watch Service
After=network.target
[Service]
Type=simple
User=converter
ExecStart=/usr/local/bin/watch-convert.sh
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
sudo systemctl enable file-converter
sudo systemctl start file-converter
Pro Tip: When building watch folder systems, add a short delay (1-2 seconds) after detecting a new file before starting conversion. Large files may still be copying when the filesystem event fires, and converting an incomplete file will produce a corrupt output.
CI/CD Pipeline Integration
Integrating file conversion into your CI/CD pipeline automates conversions as part of your build and deployment process. This is ideal for content-heavy projects like documentation sites, media galleries, and marketing platforms.
GitHub Actions
Image optimization on pull request:
# .github/workflows/optimize-images.yml
name: Optimize Images
on:
pull_request:
paths:
- "content/images/**"
jobs:
optimize:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install ImageMagick
run: sudo apt-get install -y imagemagick
- name: Optimize new images
run: |
for img in content/images/*.{png,jpg,jpeg}; do
[ -f "$img" ] || continue
magick "$img" -resize '1920x1920>' -quality 85 -strip "$img"
done
- name: Generate WebP versions
run: |
for img in content/images/*.{jpg,jpeg,png}; do
[ -f "$img" ] || continue
filename="${img%.*}"
magick "$img" -quality 80 "${filename}.webp"
done
- name: Commit optimized images
run: |
git config user.name "GitHub Actions"
git config user.email "actions@github.com"
git add content/images/
git diff --staged --quiet || git commit -m "Optimize images"
git push
Document conversion in build pipeline:
# .github/workflows/build-docs.yml
name: Build Documentation
on:
push:
branches: [main]
paths:
- "docs/**"
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Pandoc
run: sudo apt-get install -y pandoc texlive-xetex
- name: Convert Markdown to PDF
run: |
mkdir -p dist/pdf
for md in docs/*.md; do
filename=$(basename "${md%.md}")
pandoc "$md" -o "dist/pdf/${filename}.pdf" \
--pdf-engine=xelatex \
-V geometry:margin=1in
done
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: documentation-pdfs
path: dist/pdf/

GitLab CI
# .gitlab-ci.yml
convert-media:
stage: build
image: jrottenberg/ffmpeg:5-ubuntu
script:
- mkdir -p public/videos
- |
for video in assets/videos/*.{mov,avi,mkv}; do
[ -f "$video" ] || continue
filename=$(basename "${video%.*}")
ffmpeg -i "$video" \
-c:v libx264 -crf 23 -c:a aac -b:a 128k \
"public/videos/${filename}.mp4"
done
artifacts:
paths:
- public/videos/
API Integration
For applications that need to convert files as part of their business logic, API integration provides the most scalable and maintainable approach.
Node.js Integration
const fs = require("fs");
const path = require("path");
class ConversionPipeline {
constructor(apiKey, baseUrl) {
this.apiKey = apiKey;
this.baseUrl = baseUrl;
}
async convertFile(inputPath, outputFormat, options = {}) {
const formData = new FormData();
formData.append("file", fs.createReadStream(inputPath));
formData.append("outputFormat", outputFormat);
formData.append("options", JSON.stringify(options));
const response = await fetch(`${this.baseUrl}/api/convert`, {
method: "POST",
headers: { Authorization: `Bearer ${this.apiKey}` },
body: formData,
});
if (!response.ok) {
throw new Error(`Conversion failed: ${response.statusText}`);
}
return response;
}
async processDirectory(inputDir, outputDir, rules) {
const files = fs.readdirSync(inputDir);
const results = [];
for (const file of files) {
const ext = path.extname(file).toLowerCase().slice(1);
const rule = rules[ext];
if (!rule) continue;
const inputPath = path.join(inputDir, file);
const outputFile = `${path.basename(file, `.${ext}`)}.${rule.outputFormat}`;
const outputPath = path.join(outputDir, outputFile);
try {
const result = await this.convertFile(inputPath, rule.outputFormat, rule.options);
const buffer = await result.arrayBuffer();
fs.writeFileSync(outputPath, Buffer.from(buffer));
results.push({ file, status: "success", output: outputFile });
} catch (error) {
results.push({ file, status: "error", error: error.message });
}
}
return results;
}
}
// Usage
const pipeline = new ConversionPipeline(process.env.API_KEY, "https://api.convertintomp4.com");
const rules = {
png: { outputFormat: "webp", options: { quality: 80 } },
mov: { outputFormat: "mp4", options: { codec: "h264", crf: 23 } },
docx: { outputFormat: "pdf", options: {} },
};
const results = await pipeline.processDirectory("./uploads", "./converted", rules);
console.table(results);
For a comprehensive guide to API integration patterns, including webhooks, batch processing, and error handling, see our file conversion API guide.
Python Integration
import os
import requests
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor, as_completed
class ConversionPipeline:
def __init__(self, api_key, base_url, max_workers=4):
self.api_key = api_key
self.base_url = base_url
self.max_workers = max_workers
self.session = requests.Session()
self.session.headers["Authorization"] = f"Bearer {api_key}"
def convert_file(self, input_path, output_format, options=None):
with open(input_path, "rb") as f:
response = self.session.post(
f"{self.base_url}/api/convert",
files={"file": f},
data={
"outputFormat": output_format,
"options": json.dumps(options or {}),
},
)
response.raise_for_status()
return response.content
def process_directory(self, input_dir, output_dir, rules):
input_path = Path(input_dir)
output_path = Path(output_dir)
output_path.mkdir(parents=True, exist_ok=True)
tasks = []
for file in input_path.iterdir():
ext = file.suffix.lstrip(".").lower()
if ext in rules:
tasks.append((file, rules[ext]))
results = []
with ThreadPoolExecutor(max_workers=self.max_workers) as executor:
futures = {}
for file, rule in tasks:
future = executor.submit(
self.convert_file, file, rule["output_format"], rule.get("options")
)
futures[future] = (file, rule)
for future in as_completed(futures):
file, rule = futures[future]
try:
content = future.result()
out_name = f"{file.stem}.{rule['output_format']}"
(output_path / out_name).write_bytes(content)
results.append({"file": file.name, "status": "success"})
except Exception as e:
results.append({"file": file.name, "status": "error", "error": str(e)})
return results
Workflow Automation Tools
For non-developers or teams that want visual automation without writing code, workflow automation platforms provide a no-code approach to file conversion.
Zapier
Zapier connects thousands of apps with trigger-action workflows (called "Zaps").
Example: Automatically convert uploaded Google Drive files to PDF
- Trigger: New File in Google Drive folder
- Action: Download the file
- Action: Send to conversion API (using Zapier's Webhooks integration)
- Action: Upload converted PDF to a different Google Drive folder
- Action: Send Slack notification with the converted file link
n8n (Self-Hosted Alternative)
n8n is an open-source workflow automation tool that you can self-host for full control over data privacy.
{
"nodes": [
{
"name": "Watch Folder",
"type": "n8n-nodes-base.localFileTrigger",
"parameters": {
"path": "/data/input",
"events": ["add"]
}
},
{
"name": "Convert File",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"method": "POST",
"url": "https://api.convertintomp4.com/convert",
"sendBody": true,
"bodyContentType": "multipart-form-data"
}
},
{
"name": "Save Output",
"type": "n8n-nodes-base.writeFile",
"parameters": {
"fileName": "/data/output/{{ $json.filename }}"
}
},
{
"name": "Notify Team",
"type": "n8n-nodes-base.slack",
"parameters": {
"channel": "#file-conversions",
"text": "Converted: {{ $json.filename }}"
}
}
]
}
Automation Tool Comparison
| Feature | Zapier | n8n | Make (Integromat) | Custom Script |
|---|---|---|---|---|
| Hosting | Cloud | Self-hosted or cloud | Cloud | Your infrastructure |
| Pricing | Per task | Free (self-hosted) | Per operation | Free (tooling costs) |
| Code required | No | Optional | No | Yes |
| Conversion tools | Via API/webhook | Via API/webhook | Via API/webhook | Direct (FFmpeg, etc.) |
| File size limits | 150 MB (Pro) | Unlimited (self-hosted) | 300 MB (Pro) | Unlimited |
| Scheduling | Built-in | Built-in | Built-in | Cron jobs |
| Error handling | Basic retry | Advanced | Basic retry | Custom |
| Audit trail | Yes | Yes | Yes | Custom logging |

Monitoring and Error Handling
Automated conversions will eventually fail. Network issues, corrupt files, disk space, and resource limits all cause problems. Robust monitoring and error handling are essential.
Logging Best Practices
#!/bin/bash
# Conversion script with structured logging
LOG_FILE="/var/log/conversions/$(date +%Y-%m-%d).log"
log() {
echo "[$(date -Iseconds)] [$1] $2" >> "$LOG_FILE"
}
convert_file() {
local input="$1"
local output="$2"
log "INFO" "Starting conversion: $input -> $output"
start_time=$(date +%s)
if ffmpeg -i "$input" -c:v libx264 -crf 23 "$output" 2>> "$LOG_FILE"; then
end_time=$(date +%s)
duration=$((end_time - start_time))
log "INFO" "Success: $input -> $output (${duration}s)"
else
log "ERROR" "Failed: $input -> $output (exit code: $?)"
# Move failed file to error directory
mv "$input" "/data/errors/"
return 1
fi
}
Error Recovery Strategies
| Error Type | Detection | Recovery |
|---|---|---|
| Corrupt input file | Non-zero exit code | Move to error directory, alert |
| Disk full | Disk usage check before conversion | Clean temp files, alert admin |
| Out of memory | Process killed (OOM) | Reduce quality/resolution, retry |
| Network timeout (API) | HTTP timeout | Exponential backoff retry |
| Rate limit (API) | HTTP 429 response | Wait for Retry-After, resume |
| Unsupported format | Conversion tool error | Skip, log, notify |
Pro Tip: Always implement a "dead letter queue" for failed conversions. Move files that fail repeatedly to a separate directory with a log of why they failed. This prevents the automation from retrying endlessly and gives you a clear list of files that need manual attention.
Performance Optimization
Parallel Processing
Converting files sequentially wastes time when you have multiple CPU cores available:
#!/bin/bash
# parallel-convert.sh — Convert files using GNU Parallel
find "$INPUT_DIR" -name "*.mov" -print0 | \
parallel -0 -j$(nproc) \
'ffmpeg -i {} -c:v libx264 -crf 23 -c:a aac '"$OUTPUT_DIR"'/{/.}.mp4'
Resource Management
| Resource | Monitoring | Optimization |
|---|---|---|
| CPU | htop, process limits | Limit concurrent jobs |
| Memory | free -h, OOM alerts | Set per-process memory limits |
| Disk I/O | iotop, disk usage | Use SSD for temp files |
| Disk space | df -h, threshold alerts | Clean temp files after conversion |
| Network | iftop (API conversions) | Batch uploads, compress before transfer |
Conversion Speed by Tool
| Tool | Best For | Speed Rating | Quality |
|---|---|---|---|
| FFmpeg | Video/audio | Fast (hardware accel) | Excellent |
| ImageMagick | Images | Very fast | Excellent |
| Sharp (Node.js) | Images | Very fast | Excellent |
| LibreOffice | Documents | Slow-medium | Good |
| Pandoc | Markup docs | Fast | Excellent |
| Ghostscript | PDF operations | Medium | Excellent |
| HandBrake CLI | Video | Fast (GPU support) | Excellent |
Putting It All Together
The best automation approach depends on your volume, technical resources, and requirements:
- Low volume, occasional use: Shell scripts with cron scheduling
- Medium volume, regular use: Watch folders with logging and error handling
- High volume, business-critical: API integration with queuing, webhooks, and monitoring
- Non-technical team: Workflow tools (Zapier, n8n, Make) with visual configuration
- CI/CD integration: GitHub Actions or GitLab CI for build-time conversions
Start simple and add complexity as your needs grow. A basic shell script that converts 10 files a day does not need Kubernetes orchestration. But if you are processing thousands of files daily, invest in proper queuing, monitoring, and error recovery from the start.
For more on handling large numbers of files efficiently, see our batch processing guide. And for API-specific integration patterns, our file conversion API guide covers authentication, webhooks, rate limiting, and SDK examples in depth. Visit our tool pages for video conversion, image conversion, and PDF processing to try browser-based conversions before building automation around them.



