How to Clean Up All Stopped Containers in Apple Container
The container prune command removes every stopped container by filtering for status .stopped, calculating disk usage, and deleting each container through the XPC client.
The Apple Container framework provides a dedicated CLI subcommand and Swift API to clean up all stopped containers. Whether you are scripting maintenance tasks or building a management interface, understanding the underlying implementation in ContainerPrune.swift helps you reclaim disk space safely and efficiently.
How the Prune Operation Works
The cleanup logic orchestrates three distinct phases to ensure accurate accounting and safe removal.
Filter Stopped Containers
The process begins in ContainerPrune.swift by constructing a ContainerListFilters value with status: .stopped. The implementation calls withoutMachines() to exclude machine containers from the deletion scope, ensuring only user-created stopped containers are targeted. This filter model is defined in Sources/ContainerResource/Container/ContainerListFilters.swift.
Calculate Reclaimed Space
For each container returned by the filtered list, the command gathers usage data. It invokes ContainerClient.diskUsage(id:) to compute the total bytes that will be freed. This step occurs in the client implementation at Sources/Services/ContainerAPIService/Client/ContainerClient.swift, which communicates with the container daemon over XPC.
Execute Deletion
Finally, the prune loop calls ContainerClient.delete(id:) for every stopped container. The accumulated disk usage totals are logged to provide immediate feedback on reclaimed storage. All XPC RPCs are handled asynchronously through the ContainerClient interface.
Key Source Files and Architecture
Understanding the file structure clarifies how the components interact:
Sources/ContainerCommands/Container/ContainerPrune.swift– Declares thecontainer pruneCLI command and implements the pruning flow that wires the filters, client, and deletion loop.Sources/Services/ContainerAPIService/Client/ContainerClient.swift– The XPC client exposinglist,diskUsage, anddeletemethods that send RPCs to the container daemon.Sources/ContainerResource/Container/ContainerListFilters.swift– Model for constructing list filters, including the "stopped" status selector and thewithoutMachines()helper.
Practical Code Examples
Using the CLI
The simplest way to clean up all stopped containers is via the command line:
container prune
This command automatically filters for stopped containers, calculates reclaimed space, and prints the IDs of deleted containers.
Swift Implementation
To implement the same logic programmatically:
import ContainerAPIClient
import ContainerResource
let client = ContainerClient()
let stoppedFilters = ContainerListFilters(status: .stopped).withoutMachines()
let stopped = try await client.list(filters: stoppedFilters)
var reclaimed: UInt64 = 0
for c in stopped {
let size = try await client.diskUsage(id: c.id)
reclaimed += size
try await client.delete(id: c.id)
}
print("Removed \(stopped.count) stopped containers, reclaimed \(reclaimed) bytes")
Constructing Filters
When building custom management tools, you can inspect the filter construction:
let filters = ContainerListFilters(status: .stopped).withoutMachines()
// The filter encodes as JSON for transmission to the daemon
print(filters)
Summary
- The
container prunecommand targets only containers with status.stoppedwhile excluding machine containers viawithoutMachines(). - The operation relies on
ContainerClientXPC methodslist,diskUsage, anddeleteto communicate with the container daemon. - All logic is implemented in
ContainerPrune.swift, with supporting filter models inContainerListFilters.swift. - Both CLI and Swift APIs provide accurate byte-level reporting of reclaimed disk space.
Frequently Asked Questions
What is the difference between container prune and manual deletion?
Manual deletion requires you to specify individual container IDs and does not automatically calculate reclaimed space. The container prune command aggregates all stopped containers, computes total disk usage via diskUsage(id:), and removes them in a single operation with detailed logging.
Why does the prune command exclude machine containers?
The withoutMachines() filter removes infrastructure containers that support the Apple Container runtime itself. According to the source in ContainerListFilters.swift, machine containers are system-level resources that should persist regardless of user cleanup operations to maintain daemon functionality.
How does the XPC client communicate with the container daemon?
The ContainerClient defined in ContainerClient.swift establishes an XPC connection to the container daemon. When you call list, diskUsage, or delete, the client serializes requests and sends them as RPCs, awaiting asynchronous responses before updating the local process with container state or confirmation of deletion.
Is it safe to run container prune on a production system?
Yes, provided you verify that no stopped containers contain data you wish to preserve. The command only affects containers with status .stopped and leaves running containers untouched. However, the deletion via delete(id:) is irreversible, so ensure critical stopped containers are backed up or committed to images before pruning.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →