Auto-Removing Containers After Workflow Execution with `act --rm`

The act --rm command-line flag automatically deletes Docker containers and their attached volumes immediately after a GitHub Actions workflow finishes, preventing disk space exhaustion from accumulated stopped containers.

The open-source CLI tool act (nektos/act) executes GitHub Actions workflows locally by spawning Docker containers for each job. Without explicit cleanup, these containers persist on your host as stopped instances, cluttering the Docker daemon and consuming storage. The --rm flag triggers a robust cleanup mechanism that removes containers regardless of whether the workflow succeeds or fails.

How act --rm Works Internally

The flag operates through a multi-layered pipeline that spans command-line parsing, configuration propagation, and Docker runtime integration.

Flag Registration in cmd/root.go

At line 95 of cmd/root.go, the Cobra CLI framework registers the --rm boolean flag. When parsed, its value is stored in the input.autoRemove field:

// Simplified representation of the registration
cmd.PersistentFlags().BoolVarP(&input.autoRemove, "rm", "", false, "automatically remove the container after execution")

Propagation to Runner Configuration

At line 637 in the same file (cmd/root.go), the autoRemove value is copied into the runtime configuration struct as rc.Config.AutoRemove. This makes the setting available to the job executor and container runtime throughout the lifecycle of the workflow.

Docker CLI Integration

In pkg/container/docker_cli.go at line 205, the boolean translates directly into Docker’s native --rm option. When constructing the docker run command, the code injects copts.autoRemove, instructing the Docker daemon to delete the container automatically upon exit:

// From pkg/container/docker_cli.go
if c.autoRemove {
    args = append(args, "--rm")
}

Fallback Cleanup in job_executor.go

Even if Docker’s native --rm fails to trigger (for example, when a job errors before the container fully starts), the pkg/runner/job_executor.go file implements a manual safety net at lines 107-108. The cleanup logic evaluates the condition rc.Config.AutoRemove || jobError == nil, meaning:

  • If --rm is set, the container is removed regardless of job status.
  • If --rm is omitted, the container is removed only if the job succeeded (jobError == nil).

This ensures containers never leak when the explicit removal flag is active.

Usage Examples

Basic Auto-Removal

Run a specific job and automatically clean up the container afterward, even if steps fail:

act --rm -j build

Combining with Other Flags

Pull fresh images, bind-mount the working directory, and enable auto-removal in a single command:

act --pull --bind --rm -j test

Debugging Container Lifecycle

Verify that --rm actually deletes containers by comparing docker ps output:


# First run without --rm to observe the leftover container

act -j lint
docker ps -a  # Shows a stopped container named "act-<uuid>"

# Now run with --rm

act --rm -j lint
docker ps -a  # The previous container is gone; no new stopped instances appear

Key Source Files

Understanding the implementation requires examining these specific locations in the nektos/act repository:

  • cmd/root.go (lines 95, 637): Defines the global --rm flag and propagates input.autoRemove into rc.Config.AutoRemove.
  • pkg/container/docker_cli.go (line 205): Appends the --rm option to the Docker run command when c.autoRemove is true.
  • pkg/runner/runner.go (lines 22-23): Contains the Config struct definition, including the AutoRemove boolean field that controls cleanup behavior.
  • pkg/runner/job_executor.go (lines 107-108): Houses the fallback cleanup logic that removes containers when AutoRemove is enabled or when jobs exit without error.

Summary

  • act --rm registers a boolean flag in cmd/root.go that flows into rc.Config.AutoRemove.
  • The flag injects Docker’s native --rm option via pkg/container/docker_cli.go, ensuring automatic deletion on container exit.
  • A fallback mechanism in pkg/runner/job_executor.go guarantees container removal even when Docker’s auto-remove cannot execute, such as during early job failures.
  • When --rm is omitted, containers persist after runs unless the job succeeds, while the --reuse flag intentionally retains containers for caching purposes.

Frequently Asked Questions

Does act --rm remove containers even when workflow jobs fail?

Yes. According to the source code in pkg/runner/job_executor.go, the cleanup condition rc.Config.AutoRemove || jobError == nil evaluates to true whenever the --rm flag is set, ensuring removal regardless of whether jobError is nil or contains an error from a failed step.

How does --rm differ from the --reuse flag?

The --reuse flag is designed to keep containers alive between runs to cache the GitHub Actions environment and dependencies, speeding up subsequent executions. In contrast, --rm explicitly destroys the container immediately after the job finishes, reclaiming disk space but requiring fresh container creation on the next run.

Will --rm delete Docker volumes created during the workflow?

Yes. When Docker’s native --rm flag is passed (via pkg/container/docker_cli.go), the Docker daemon automatically removes any anonymous volumes attached to the container. However, named volumes declared in your workflow may persist depending on your Docker daemon configuration.

Where can I find the configuration struct that stores the --rm setting?

The AutoRemove field is defined in pkg/runner/runner.go at lines 22-23 within the Config struct. This field is populated from the command-line input in cmd/root.go and is referenced by both the Docker container logic and the job executor to determine cleanup behavior.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →