# Difference Between Machine and Container Commands in Apple Container

> Understand the key differences between container machine commands and regular container commands. Learn how container machines offer persistent Linux environments for stateful applications, unlike ephemeral single-process conta...

- Repository: [Apple/container](https://github.com/apple/container)
- Tags: deep-dive
- Published: 2026-07-11

---

**Container machine commands provide a persistent, VM-like Linux environment with init system support and state survival, while regular container commands execute ephemeral, single-process workloads that exit after completion.**

The Apple Container project offers two distinct paradigms for running OCI images on macOS. Understanding the difference between machine and container commands is essential for choosing the right tool for development workflows versus isolated tasks. This guide examines the architectural distinction, source implementation, and practical use cases based on the `apple/container` repository.

## Architectural Overview: Machines vs. Containers

A **container machine** operates as a lightweight VM that boots an OCI image's init system, creating a persistent Linux environment managed by the Container runtime. In contrast, **regular container commands** launch individual OCI containers that share the runtime but function as ephemeral, single-process execution contexts without persistent state.

## Key Differences Between Machine and Container Commands

### Purpose and Execution Model

Container machines provide a full Linux host environment capable of running long-lived services like **systemd** or databases. Regular container commands execute short-lived workloads where the container starts, runs a specific command, then exits.

### State Persistence

The machine's root filesystem, user data, and configuration survive reboots and can be resumed later using `container machine stop` and `container machine run`. Regular containers are ephemeral by default; stopping destroys runtime state unless explicitly preserved with flags.

### User and Home Directory Mapping

Machines automatically map the macOS user's UID/GID and `$HOME` directory into the Linux environment at `/home/<user>`, enabling seamless file editing between macOS and the Linux environment. Regular containers run as root by default and require manual volume mounts (`-v` or `--mount`) to share files with the host.

### Init System Support

According to the source implementation in [`Sources/ContainerCommands/Machine/MachineRun.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/Machine/MachineRun.swift), container machines boot the image's init system at `/sbin/init`, allowing systemd-managed services to function immediately. Regular containers lack an init system; the specified entrypoint becomes PID 1 without service management capabilities.

### Resource Configuration

Resource allocation for machines persists across reboots and is configured via `container machine set` in [`Sources/ContainerCommands/Machine/MachineSet.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/Machine/MachineSet.swift), affecting CPU, memory, and nested virtualization settings. Regular containers accept resource limits (`--cpus`, `--memory`) only for the duration of a single invocation.

## Source Code Implementation

The machine abstraction is implemented across several key files in the repository:

- [`Sources/ContainerCommands/Machine/MachineCreate.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/Machine/MachineCreate.swift) handles the creation logic invoked by `container machine create`.
- [`Sources/ContainerCommands/Machine/MachineRun.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/Machine/MachineRun.swift) manages the boot sequence and interactive shells for machine instances.
- [`Sources/ContainerCommands/Machine/MachineSet.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/Machine/MachineSet.swift) implements persistent configuration changes stored in [`Sources/ContainerPersistence/MachineConfig.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPersistence/MachineConfig.swift).
- [`Sources/Services/MachineAPIService/Server/MachinesService.swift`](https://github.com/apple/container/blob/main/Sources/Services/MachineAPIService/Server/MachinesService.swift) contains the server-side lifecycle management for machine operations.
- [`Sources/Services/MachineAPIService/Client/MachineClient.swift`](https://github.com/apple/container/blob/main/Sources/Services/MachineAPIService/Client/MachineClient.swift) provides the client interface used by the CLI to communicate with the machine API.

Regular container commands follow a different execution path focused on ephemeral OCI container management without the persistence layer defined in [`MachineConfig.swift`](https://github.com/apple/container/blob/main/MachineConfig.swift).

## Practical Usage Examples

Creating and managing a persistent development environment:

```bash

# Create a machine named "dev" from Alpine

container machine create alpine:latest --name dev

# Run an interactive shell (user matches host macOS user)

container machine run -n dev

# Execute a command inside the running machine

container machine run -n dev uname -a

```

Running ephemeral containers for isolated tasks:

```bash

# Start a one-off Ubuntu shell

container run -it ubuntu:latest /bin/bash

# Run a detached web server

container run -d --name web -p 8080:80 nginx:latest

```

Configuring resources:

```bash

# Set persistent machine resources (requires restart)

container machine set -n dev cpus=4 memory=8G

# Apply temporary limits to a regular container

container run -it --cpus 2 --memory 2G alpine sh

```

Managing persistent services with systemd:

```bash

# Start PostgreSQL inside a machine

container machine run -n dev -- systemctl start postgresql

# Query the database

container machine run -n dev -- psql -U postgres -c "SELECT version();"

```

## Summary

- **Container machines** provide persistent, VM-like Linux environments with init system support and automatic user mapping, ideal for development workflows requiring long-running services.
- **Regular container commands** execute ephemeral, single-process workloads without persistent state or automatic home directory mapping, suited for isolated tasks and image building.
- Machine configuration persists across reboots via [`MachineConfig.swift`](https://github.com/apple/container/blob/main/MachineConfig.swift), while regular container resources apply only to individual invocations.
- The machine implementation in `Sources/ContainerCommands/Machine/` handles lifecycle management distinct from the ephemeral container runtime.

## Frequently Asked Questions

### Can I run systemd in a regular container command?

No. Regular container commands execute your specified process as PID 1 without an init system. Only container machines boot `/sbin/init`, enabling systemd and other service managers to function properly.

### Why does my container machine show my macOS home directory?

Container machines automatically map your macOS user's UID/GID and `$HOME` to `/home/<user>` in the Linux environment, facilitating seamless file editing between macOS and Linux. Regular containers require manual volume mounts to access host files.

### How do I persist changes in a regular container?

Regular containers are ephemeral by design. To preserve changes, commit the container to a new image using `container commit` or use volumes for data persistence. Alternatively, use a container machine for development scenarios requiring persistent state across sessions.

### Can I adjust CPU and memory for both machines and containers?

Yes, but with different persistence models. Use `container machine set` to permanently configure machine resources in [`MachineConfig.swift`](https://github.com/apple/container/blob/main/MachineConfig.swift), requiring a stop/start cycle to apply. For regular containers, pass `--cpus` and `--memory` flags to `container run` for temporary, per-execution limits.