# Leveraging act's --reuse Flag for Docker Containers to Maintain State Between Runs

> Master Docker stateful testing with act's --reuse flag. Preserve containers and volumes between runs for efficient local development and debugging. Simplify your workflow today.

- Repository: [nektos/act](https://github.com/nektos/act)
- Tags: how-to-guide
- Published: 2026-03-03

---

**The `--reuse` (or `-r`) flag tells act to preserve Docker containers, volumes, and networks after successful workflow runs, enabling stateful local testing by conditionally skipping cleanup logic defined in the runner configuration.**

The `nektos/act` CLI tool executes GitHub Actions workflows locally using Docker containers. By default, act creates fresh containers for each run and deletes them immediately after completion. **Leveraging act's `--reuse` flag for Docker containers** allows developers to maintain state between executions, significantly speeding up iterative development when working with databases or cached build artifacts.

## How the `--reuse` Flag Works

The reuse functionality spans the CLI interface, runner configuration, and container lifecycle management. When enabled, the flag propagates through three architectural layers to suppress container removal operations.

### CLI Flag Definition and Configuration

The flag is defined in **[[`cmd/root.go`](https://github.com/nektos/act/blob/main/cmd/root.go)](https://github.com/nektos/act/blob/master/cmd/root.go#L83-L84)** using Cobra's boolean flag syntax:

```go
rootCmd.Flags().BoolVarP(&input.reuseContainers, "reuse", "r", false,
    "don't remove container(s) on successfully completed workflow(s) to maintain state between runs")

```

The value is stored in the `Input` struct and later copied into the runner configuration at **[[`cmd/root.go`](https://github.com/nektos/act/blob/main/cmd/root.go) line 613](https://github.com/nektos/act/blob/master/cmd/root.go#L613)**:

```go
ReuseContainers: input.reuseContainers,

```

### Runner Configuration Structure

The flag ultimately resides in the `Config` struct defined in **[[`pkg/runner/runner.go`](https://github.com/nektos/act/blob/main/pkg/runner/runner.go) lines 31-32](https://github.com/nektos/act/blob/master/pkg/runner/runner.go#L31-L32)**:

```go
type Config struct {
    // …
    ReuseContainers bool // reuse containers to maintain state
    // …
}

```

This boolean field drives all conditional cleanup logic throughout the execution pipeline.

## Container Lifecycle Modifications

When `ReuseContainers` is set to `true`, act modifies the cleanup behavior for three distinct container types: job containers, step containers, and service containers.

### Job Container Preservation

In **[[`pkg/runner/run_context.go`](https://github.com/nektos/act/blob/main/pkg/runner/run_context.go) lines 55-63](https://github.com/nektos/act/blob/master/pkg/runner/run_context.go#L55-L63)**, the cleanup closure checks the configuration before removing the job container and its associated volumes:

```go
reuseJobContainer := func(_ context.Context) bool {
    return rc.Config.ReuseContainers
}
...
return rc.JobContainer.Remove().IfNot(reuseJobContainer)
    .Then(container.NewDockerVolumeRemoveExecutor(rc.jobContainerName(), false)).IfNot(reuseJobContainer)
    .Then(container.NewDockerVolumeRemoveExecutor(rc.jobContainerName()+"-env", false)).IfNot(reuseJobContainer)

```

When `ReuseContainers` is `true`, the `IfNot(reuseJobContainer)` condition disables removal calls. This leaves the job container intact along with its named volumes (`<job-name>` and `<job-name>-env`).

### Step Container Preservation

Individual step containers follow the same conditional pattern. In **[[`pkg/runner/step_docker.go`](https://github.com/nektos/act/blob/main/pkg/runner/step_docker.go) lines 79-84](https://github.com/nektos/act/blob/master/pkg/runner/step_docker.go#L79-L84)**:

```go
stepContainer.Remove().IfBool(!rc.Config.ReuseContainers)

```

Similarly, composite actions that spawn their own containers use identical logic in **[[`pkg/runner/action.go`](https://github.com/nektos/act/blob/main/pkg/runner/action.go) lines 350-354](https://github.com/nektos/act/blob/master/pkg/runner/action.go#L350-L354)**:

```go
stepContainer.Remove().IfBool(!rc.Config.ReuseContainers)

```

If `ReuseContainers` evaluates to `true`, the `IfBool` condition prevents container removal.

### Service Containers and Networks

Service containers defined in the `services:` block of your workflow (such as MySQL or Redis) are governed by the same `reuseJobContainer` flag. The network cleanup code in [`run_context.go`](https://github.com/nektos/act/blob/main/run_context.go) also respects the flag, ensuring that the Docker network connecting job and service containers persists between runs when reuse is enabled.

## Practical Usage Examples

### Basic Reuse Workflow

Start by invoking act with the short or long flag form:

```bash

# First run creates containers and preserves them

act -r

# Subsequent runs reuse existing containers

act --reuse

```

### Stateful Database Testing

Consider a workflow that initializes a PostgreSQL database. Without reuse, each run recreates the database from scratch. With `--reuse`, the database state persists:

```yaml

# .github/workflows/ci.yml

name: CI
on: [push]

jobs:
  test:
    runs-on: ubuntu-latest
    services:
      db:
        image: postgres:15
        env:
          POSTGRES_PASSWORD: password
        ports: ["5432:5432"]
    steps:
      - uses: actions/checkout@v4
      - name: Seed database
        run: |
          psql -h localhost -U postgres -c "CREATE TABLE test (id serial);"

```

Execute with reuse to maintain the seeded data:

```bash

# First run initializes PostgreSQL

act -r

# Second run connects to the existing container with previous state intact

act -r

```

Inspect the preserved container using standard Docker commands:

```bash
docker ps -a | grep act-
docker exec -it <container-name> bash

```

### Manual Cleanup Procedures

When you need to remove containers that were preserved with `--reuse`, use Docker's CLI:

```bash

# Remove specific job containers

docker rm -f $(docker ps -aq -f name=<workflow-job-name>)

# Remove associated volumes

docker volume rm $(docker volume ls -q -f name=<workflow-job-name>)

# Or run act without --reuse to trigger automatic cleanup on the next execution

act

```

## Summary

- The `--reuse` flag maps to **`Config.ReuseContainers`** in the runner configuration struct.
- **Job containers**, **step containers**, and **service containers** are all preserved when the flag is enabled.
- The flag only affects **successful** workflow runs; failed runs still trigger container cleanup unless combined with other flags.
- Associated Docker volumes (named `<job-name>` and `<job-name>-env`) remain intact between executions.
- Manual cleanup requires explicit `docker rm` and `docker volume rm` commands targeting the preserved resources.

## Frequently Asked Questions

### Does the `--reuse` flag prevent cleanup when a workflow fails?

No. According to the implementation in [`cmd/root.go`](https://github.com/nektos/act/blob/main/cmd/root.go), the `--reuse` flag specifically applies to "successfully completed workflow(s)." If your workflow fails, act removes the containers regardless of the `--reuse` setting. To force cleanup after failures, you would use the `--rm` flag instead.

### Can I access files written inside reused containers on my host machine?

No. The `--reuse` flag preserves the container's filesystem state in Docker's storage layer, but it does not mount or sync those files to your host filesystem. Files written inside the container remain inside the container's writable layer. To extract artifacts, use `docker cp` to copy files from the preserved container to your host.

### Are service containers defined in the workflow YAML also reused?

Yes. Service containers (such as databases or cache services defined under the `services:` key) are governed by the same `reuseJobContainer` logic in [`run_context.go`](https://github.com/nektos/act/blob/main/run_context.go). When `--reuse` is enabled, these containers persist alongside the main job container, maintaining their state (including database tables, cached data, and configuration) between workflow runs.

### How do I clean up containers when I'm done using `--reuse`?

You have two options for cleanup. First, run `act` without the `--reuse` flag on your next successful execution, which will remove containers created in that specific run. Second, manually remove containers using `docker rm -f` and volumes using `docker volume rm`, targeting resources by the job name prefix (e.g., `act-<job-name>`). Docker's filtering flags (`-f name=act-`) help identify act-managed resources.