Run FFmpeg in the Background on macOS Using launchd

This article explains how to automate and run FFmpeg commands as persistent background processes on macOS using launchd, Apple’s native service management framework. You will learn how to create a custom Property List (.plist) configuration file, place it in the correct system directory, and use launchctl commands to load, start, and manage your background FFmpeg task.

Step 1: Locate the FFmpeg Binary Path

Because launchd runs in a non-interactive shell environment, it does not inherit your user shell’s PATH variable. You must use the absolute path to your FFmpeg executable.

To find the absolute path, open Terminal and run:

which ffmpeg

Typically, the output will be: * /opt/homebrew/bin/ffmpeg (on Apple Silicon Macs using Homebrew) * /usr/local/bin/ffmpeg (on Intel Macs using Homebrew)

Step 2: Create the launchd Plist File

launchd services are configured using XML files with a .plist extension. You should save this file in your user’s LaunchAgents directory so it runs with your user permissions: ~/Library/LaunchAgents/.

Create a file named com.user.ffmpeg.plist in that directory. You can use any text editor to create and edit it.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <!-- A unique identifier for your job -->
    <key>Label</key>
    <string>com.user.ffmpeg</string>

    <!-- The exact command and arguments to execute -->
    <key>ProgramArguments</key>
    <array>
        <string>/opt/homebrew/bin/ffmpeg</string>
        <string>-re</string>
        <string>-i</string>
        <string>/path/to/input.mp4</string>
        <string>-c</string>
        <string>copy</string>
        <string>-f</string>
        <string>flv</string>
        <string>rtmp://live.twitch.tv/app/stream_key</string>
    </array>

    <!-- Run the job as soon as the plist is loaded or the user logs in -->
    <key>RunAtLoad</key>
    <true/>

    <!-- Keep the process alive. If FFmpeg crashes or finishes, launchd will restart it -->
    <key>KeepAlive</key>
    <true/>

    <!-- Working directory for the process -->
    <key>WorkingDirectory</key>
    <string>/Users/yourusername</string>

    <!-- Standard output and error logs (highly recommended for troubleshooting) -->
    <key>StandardOutPath</key>
    <string>/tmp/ffmpeg.out.log</string>
    <key>StandardErrorPath</key>
    <string>/tmp/ffmpeg.err.log</string>
</dict>
</plist>

Note: Replace /opt/homebrew/bin/ffmpeg, /path/to/input.mp4, and /Users/yourusername with your actual system paths. The arguments array separates every command-line option and value into its own <string> tag.

Step 3: Set Correct File Permissions

For security reasons, launchd requires strict permissions on .plist files. Run the following command in Terminal to ensure the file is owned by your user and has the correct read/write permissions:

chmod 644 ~/Library/LaunchAgents/com.user.ffmpeg.plist

Step 4: Load and Start the Service

Use the launchctl command-line utility to load and start your background service.

To load and immediately start the agent:

launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.user.ffmpeg.plist

If you are using an older version of macOS (macOS Catalina or older), use the legacy command:

launchctl load ~/Library/LaunchAgents/com.user.ffmpeg.plist

The FFmpeg command is now running in the background. You can verify it is active by checking the active system processes:

ps aux | grep ffmpeg

Step 5: Stop and Unload the Service

To stop the background process and prevent it from running automatically when you log in, unload it from launchd.

launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/com.user.ffmpeg.plist

Or for legacy macOS versions:

launchctl unload ~/Library/LaunchAgents/com.user.ffmpeg.plist