---
tags:
  - Command
  - Getting started
---

# deploy command

### Description

The `deploy` command spins up a lab using the topology expressed via [topology definition file](../manual/topo-def-file.md).
When the lab is already deployed, `deploy` reconciles the running lab with the topology
definition: supported node and link changes are applied in place without destroying and
redeploying the whole lab. `apply` is an alias of `deploy`; both command forms accept the same
flags and behave identically. `--reconfigure` retains its explicit destroy-and-recreate behavior,
and `--dry-run` previews the planned changes.
<!-- --8<-- [start:env-vars-flags] -->
> All command line arguments can be also provided via environment variables (CLI flags take precedence). The environment variable names are constructed by prepending `CLAB_` to the flag name, then adding the command path and ending with the flag name in its full form, all in uppercase and with hyphens replaced by underscores.
>
> For example, the `--max-workers` flag for the `deploy` command can be set via `CLAB_DEPLOY_MAX_WORKERS` environment variable.
> Or `CLAB_INSPECT_ALL=1` to set `--all` flag for the `inspect` command.
> Or `CLAB_TOPO=srlinux.dev/clab-srl clab dep -c` to deploy a lab with the topology passed via environment variable.
<!-- --8<-- [end:env-vars-flags] -->

### Usage

`containerlab [global-flags] deploy [local-flags]`

**aliases:** `dep`, `apply`

## Reconciliation behavior

Deploy converges a lab to the topology definition provided by the user. If the lab is not
deployed yet, it is deployed. If the lab is already deployed, containerlab discovers the current
state from the container runtime and applies supported topology deltas without destroying and
redeploying the whole lab. The `--dry-run` flag previews the planned changes without applying
them.

Reconciliation focuses on topology shape changes:

- add nodes
- delete nodes
- add links
- delete links

Deploy also tracks a small set of existing node definition changes from the last saved state.
Any tracked change—including `exec`, `environment`, `image`, `type`, `binds`, `ports`, resources,
runtime, or components—conservatively recreates only the affected node.

Use [`redeploy`](redeploy.md) instead when:

- you modify or add node properties that reconciliation does not support
- you need to change the startup configuration
- the generated configuration artifacts need to change

When existing nodes need their dataplane adjusted, deploy uses the same endpoint parking
mechanism as the `stop`, `start`, and `restart` commands: affected nodes are stopped, their
dataplane interfaces are parked in a temporary network namespace, and the interfaces are restored
after the node starts again.

### Link apply modes

When deploy adds or removes a link on a node that keeps running, the node kind decides how
disruptive that change is. Three modes exist:

- `live` - the link change is applied in place; the node is neither restarted nor recreated.
  This requires the NOS to detect interfaces that appear or disappear at runtime (hotplug).
- `restart` - the link change is applied first and the existing container is then restarted so
  the NOS picks up the new interface inventory.
- `recreate` - the node container is deleted and created again. Generated runtime metadata such
  as the `CLAB_INTFS` environment variable and startup files are rebuilt. This is the
  conservative default for kinds that have not been validated for anything better.

The currently declared modes per kind:

| Kind                    | Mode       | Notes                                                          |
| ----------------------- | ---------- | -------------------------------------------------------------- |
| `nokia_srlinux`         | `live`     | SR Linux detects hot-plugged interfaces                        |
| `nokia_srsim`           | `live`     | SR-SIM detects hot-plugged interfaces                          |
| `linux`                 | `live`     | Plain Linux containers see new interfaces immediately          |
| `arista_ceos`           | `restart`  | cEOS requires a restart to enumerate new interfaces            |
| vrnetlab-based VM kinds | `recreate` | VM NIC wiring is fixed at VM boot; live changes cannot work    |
| images built with Boxen | `live`     | Detected via the `org.opencontainers.image.vendor=Boxen` label |
| all other kinds         | `recreate` | Conservative default for kinds not yet validated               |

#### Overriding the mode

If you know that a node's NOS handles hot-plugged interfaces (or at least survives a plain
restart), you can override the kind default with the `link-apply-mode` property on a node, a
group, a kind, or the topology defaults:

```yaml
topology:
  nodes:
    r1:
      kind: juniper_crpd
      image: crpd:24.4R1.9
      link-apply-mode: live # apply link changes without recreating the node
```

The override takes precedence over the kind's declaration. When the override is more permissive
than the kind default, containerlab logs a warning: it is then your responsibility to verify the
NOS actually uses interfaces added this way.

#### Validating that a kind supports live link changes

The kernel will always show a hot-plugged interface inside the container namespace—the real
question is whether the NOS picks it up. To validate a kind:

1. Deploy a small lab with two nodes of that kind and one link.
2. Add a second link between the nodes in the topology file and run
   `containerlab deploy -t <topo>` with `link-apply-mode: live` set on the nodes.
3. Confirm the node was not recreated (`docker inspect` start time is unchanged and the apply
   summary lists the change under `added links` without recreating the nodes).
4. Confirm the NOS sees and can use the new interface: it shows up in the NOS CLI, can be
   configured, and passes traffic.
5. Remove the link again with deploy and confirm the NOS handles the removal gracefully.

If a kind passes this validation, please open an issue or pull request so the kind's default can
be changed for everyone—the change is a one-line declaration in the kind's node implementation.

### Reconciliation limitations

Only a subset of topology changes can be reconciled:

- supported link types are `veth`, brief links, `host`, `mgmt-net`, `macvlan`, `vxlan`,
  `vxlan-stitch`, `dummy`, and `bridge`
- distributed nodes, such as SR-SIM with components, are supported for node and link add/delete
- root-namespace-based and `ext-container` nodes can participate in link reconciliation; deploy
  does not create or delete their underlying resource
- configuration drift that would require recreating an externally managed node is rejected
- nodes with `auto-remove` enabled are not supported
- `network-mode: container:<...>` users/providers are not supported
- existing node definition reconciliation is limited to fields captured in the state file
- existing link parameter/type changes with the same runtime interface names are not applied in
  place; use `redeploy` for those changes

Containerlab discovers existing links from live interfaces that carry its ownership marker and
persists a `.state.clab.yaml` file under the lab directory after deployment or reconciliation. The
state file stores the resolved topology used as the baseline for limited node definition
reconciliation. Older labs without this state file can still reconcile supported shape changes,
but existing node definition changes are not inferred until a state file has been written. Older
or manually created interfaces without containerlab's ownership marker are left untouched. If
such an interface blocks a requested link change, deployment fails instead of deleting it.
Removed `vxlan-stitch` host-side interfaces are cleaned up on a best-effort basis when their
default runtime names can be derived from the stale node endpoint.

Deleted nodes are removed directly from the runtime. Node lab directories are kept.

### Flags

#### topology

With the global `--topo | -t` flag a user sets the path to the topology definition file that will be used to spin up a lab.

When the topology path refers to a directory, containerlab will look for a file with `.clab.yml` or `.clab.yaml` extension in that directory and use it as a topology definition file.

When the topology file flag is omitted, containerlab will try to find the matching file name by looking at the current working directory.

If more than one file is found for directory-based path or when the flag is omitted entirely, containerlab will fail with an error.

It is possible to read the topology file from stdin by passing `-` as a value to the `--topo` flag. See [examples](#deploy-a-lab-from-a-remote-url-with-curl) for more details.

##### Remote topology files

###### Git

To simplify the deployment of labs that are stored in remote version control systems, containerlab supports the use of remote topology files for GitHub.com and GitLab.com hosted projects.

By specifying a URL to a repository or a `.clab.yml` file in a repository, containerlab will automatically clone[^1] the repository in your current directory and deploy it. If the URL points to a `.clab.yml` file, containerlab will clone the repository and deploy the lab defined in the file.

The following URL formats are supported:

| Type                                  | Example                                                             | Which topology file is used                                                        |
| ------------------------------------- | ------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| Link to github repository             | https://github.com/hellt/clab-test-repo/                            | An auto-find procedure will find a `clab.yml` in the repository root and deploy it |
| Link to a file in a github repository | https://github.com/hellt/clab-test-repo/blob/main/lab1.clab.yml     | A file specified in the URL will be deployed                                       |
| Link to a repo's branch               | https://github.com/hellt/clab-test-repo/tree/branch1                | A branch of a repo is cloned and auto-find procedure kicks in                      |
| Link to a file in a branch of a repo  | https://github.com/hellt/clab-test-repo/blob/branch1/lab2.clab.yml  | A branch is cloned and a file specified in the URL is used for deployment          |
| Link to a file in a subdir of a repo  | https://github.com/hellt/clab-test-repo/blob/main/dir/lab3.clab.yml | A file specified in the subdir of the branch will be deployed                      |
| Shortcut of a github project          | hellt/clab-test-repo                                                | An auto-find procedure will find a `clab.yml` in the repository root and deploy it |

When the lab is deployed using the URL, the repository is cloned in the current working directory. If the repository is already cloned it will be used and not cloned again; containerlab will try to fetch the latest changes from the remote repository.

Subsequent lab operations (such as destroy) must use the filesystem path to the topology file and not the URL.

???note "Remote labs workflow in action"
    <div class="iframe-container">
        <iframe width="100%" src="https://www.youtube.com/embed/0QlUZsJGQDo" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
    </div>

###### HTTP(S)

Labs can be deployed from remote HTTP(S) URLs as well. These labs should be self-contained and not reference any external resources, like startup-config files, licenses, binds, etc.

The following URL formats are supported:

| Type                           | Example                                                             | Description                                           |
| ------------------------------ | ------------------------------------------------------------------- | ----------------------------------------------------- |
| Link to raw github gist        | https://gist.githubusercontent.com/hellt/abc/raw/def/linux.clab.yml | A file is downloaded to a temp directory and launched |
| Link to a short schemaless URL | srlinux.dev/clab-srl                                                | A file is downloaded to a temp directory and launched |

Containerlab distinct HTTP URLs from GitHub/GitLab by checking if github.com or gitlab.com is present in the URL. If not, it will treat the URL as a plain HTTP(S) URL.

###### S3

Containerlab supports using S3 URLs to retrieve topology files and startup configurations for network devices. Check out the documentation on [S3 usage](../manual/s3-usage-example.md) for more details.

#### name

With the global `--name | -n` flag a user sets a lab name. This value will override the lab name value passed in the topology definition file.

For an already deployed lab, `--name` can be used without `--topo`. Containerlab tries to derive
the topology file from the labels on the deployed containers. If the original topology file is no
longer available, provide `--topo` explicitly.

#### vars

Global `--vars` option for using specified json or yaml file to load template variables from for generating topology file.

Default is to lookup files with "_vars" suffix and common json/yaml file extensions next to topology file.
For example, for `mylab.clab.gotmpl` template of topology definition file, variables from `mylab.clab_vars.yaml` file will be used by default, if it exists, or one with `.json` or `.yml` extension.

See documentation on [Generated topologies](../manual/topo-def-file.md#generated-topologies) for more information and examples on how to use these variables.

#### reconfigure

The local `--reconfigure | -c` flag instructs containerlab to first **destroy** the lab and all its directories and then start the deployment process. That will result in a clean (re)deployment where every configuration artefact will be generated (TLS, node config) from scratch.

Without this flag present, containerlab will reuse the available configuration artifacts found in the lab directory.

Refer to the [configuration artifacts](../manual/conf-artifacts.md) page to get more information on the lab directory contents.

Management network overrides (`--network`, `--ipv4-subnet` and `--ipv6-subnet`) require a fresh
deployment. They are rejected when an existing lab is reconciled; use `--reconfigure` to apply
them by destroying and redeploying the lab.

#### dry-run

The local `--dry-run` flag prints the planned changes without applying them. For an already deployed lab this shows the [reconciliation plan](#reconciliation-behavior)—the nodes and links to add, delete, recreate, or restart. For a lab that is not deployed yet it reports that the lab would be deployed.

`--dry-run` cannot be combined with `--reconfigure`, since reconfigure always destroys and redeploys the full lab.

#### max-workers

With `--max-workers` flag, it is possible to limit the number of concurrent workers that create containers or wire virtual links. By default, the number of workers equals the number of nodes/links to create.

#### runtime

Containerlab nodes can be started by different runtimes, with `docker` being the default one. Besides that, containerlab has experimental support for `podman` runtime.

A global runtime can be selected with a global `--runtime | -r` flag that will select a runtime to use. The possible value are:

* `docker` - default
* `podman` - experimental support

#### timeout

A global `--timeout` flag drives the timeout of API requests that containerlab send toward external resources. Currently the only external resource is the container runtime (i.e. docker).

In a busy compute the runtime may respond longer than anticipated, in that case increasing the timeout may help.

The default timeout is set to 2 minutes and can be changed to values like `30s, 10m`.

#### export-template

The local `--export-template` flag allows a user to specify a custom Go template that will be used for exporting topology data into `topology-data.json` file under the lab directory. If not set, the [default template](https://github.com/srl-labs/containerlab/blob/main/clab/export_templates/auto.tmpl) is used.

To export the full topology data instead of a subset of fields exported by default, use `--export-template __full` which is a special value that instructs containerlab to use the [full.tmpl](https://github.com/srl-labs/containerlab/blob/main/clab/export_templates/full.tmpl) template file. Note, some fields exported via `full.tmpl` might contain sensitive information like TLS private keys. To customize export data, it is recommended to start with a copy of `auto.tmpl` and change it according to your needs.

#### export-rendered

The local `--export-rendered <path>` flag writes the **fully rendered** topology definition to the given file: after Go template execution and environment-variable substitution, but before containerlab proceeds with the rest of deployment. This is useful for debugging templated labs or capturing the exact YAML that was parsed.

The path argument is **required**. Relative paths are interpreted from the process working directory.

```bash
containerlab deploy -t lab0.clab.gotmpl --vars lab0.clab_vars.yml --export-rendered lab0.rendered.clab.yml
```

#### log-level

Global `--log-level` parameter can be used to configure logging verbosity of all containerlab operations.
`--debug | -d` option is a shorthand for `--log-level debug` and takes priority over `--log-level` if specified.

Following values are accepted, ordered from most verbose to least: `trace`, `debug`, `info`, `warning`, `error`, `fatal`. Default level is `info`.

It should be useful to enable more verbose logging when something doesn't work as expected, to better understand what's going on, and to provide more useful output logs when reporting containerlab issues, while making it more terse in production environments.

#### node-filter

The local `--node-filter` flag allows users to specify a subset of topology nodes targeted by `deploy` command. The value of this flag is a comma-separated list of node names as they appear in the topology.

When a subset of nodes is specified, containerlab will only deploy those nodes and links belonging to all selected nodes and ignore the rest. This can be useful e.g. in CI/CD test case scenarios, where resource constraints may prohibit the deployment of a full topology.

Node filtering applies to fresh deployments (including `--reconfigure`) only. When deploy [reconciles](#reconciliation-behavior) an already deployed lab, the filter is rejected, because running nodes excluded by the filter would otherwise be deleted.

Read more about [node filtering](../manual/node-filtering.md) in the documentation.

#### skip-post-deploy

The `--skip-post-deploy` flag skips the post-deploy phase of the lab deployment, affecting all nodes.

The post-deploy phase runs after containers and network endpoints are created. Depending on the node kind, it may include:

* Readiness and health checks
* TLS certificate provisioning
* Saving startup configuration
* Applying overlay CLI configuration
* Populating `/etc/hosts` with peer node entries
* Disabling TX checksum offload

Node kinds with notable post-deploy actions include Nokia SR Linux, Nokia SR OS, Arista cEOS, Juniper cRPD, Linux, and vrnetlab-based nodes. Kinds without a post-deploy phase are unaffected by this flag.

This flag is useful to bypass post-deploy validation failures or to speed up deployment when only the running containers are needed.

#### skip-labdir-acl

The `--skip-labdir-acl` flag can be used to skip the lab directory access control list (ACL) provisioning.

The extended File ACLs are provisioned for the lab directory by default, unless this flag is set. Extended File ACLs allow a sudo user to access the files in the lab directory that might be created by the `root` user from within the container node.

While this is useful in most cases, sometimes extended File ACLs might prevent your lab from working, especially when your lab directory end up being mounted from the network filesystem (NFS, CIFS, etc.). In such cases, you can use this flag to skip the ACL provisioning.

#### owner

The local `--owner` flag allows you to specify a custom owner for the lab. This value will be applied as the owner label for all nodes in the lab.

This flag is designed for multi-user environments where you need to track ownership of lab resources. Only users who are members of the `clab_admins` group can set a custom owner. If a non-admin user attempts to set an owner, the flag will be ignored with a warning, and the current user will be used as the owner instead.

Example:

```bash
containerlab deploy -t mylab.clab.yml --owner alice
```

#### restore-all

The local `--restore-all` flag enables restoring vrnetlab-based nodes from previously saved snapshots. When specified, containerlab will look for snapshot files named `{nodename}.tar` in the provided directory and automatically restore nodes that have matching snapshots.

Nodes without snapshots in the directory will deploy normally (fresh deployment).

**Default directory**: `./snapshots` (if flag is used without a value)

```bash
# Restore all nodes that have snapshots in ./snapshots directory
containerlab deploy -t mylab.clab.yml --restore-all

# Restore from custom directory
containerlab deploy -t mylab.clab.yml --restore-all /backups/lab1
```

**Note**: Only vrnetlab-based nodes support snapshot restore. The snapshot feature requires vrnetlab images with snapshot support.

**Note**: Snapshot restore requires a fresh deployment. Restoring into an already deployed lab is rejected; use `--reconfigure` to destroy the lab and redeploy it from snapshots.

#### restore

The local `--restore` flag allows per-node snapshot restoration by explicitly specifying the snapshot file path for individual nodes. This flag can be specified multiple times to restore different nodes from different snapshot files.

**Format**: `--restore node=path/to/snapshot.tar`

```bash
# Restore only r1 from a specific snapshot
containerlab deploy -t mylab.clab.yml --restore r1=./snapshots/r1.tar

# Restore multiple nodes with specific snapshots
containerlab deploy -t mylab.clab.yml \
  --restore r1=./snapshots/r1.tar \
  --restore r2=./snapshots/r2.tar
```

**Priority**: Per-node `--restore` specifications override `--restore-all` for the specified nodes.

**Combined usage**:

```bash
# Restore all from ./snapshots, but override r3 with a different snapshot
containerlab deploy -t mylab.clab.yml \
  --restore-all ./snapshots \
  --restore r3=./backups/r3-old.tar
```

In this example:

* Nodes with snapshots in `./snapshots/` will restore from there
* Node `r3` will restore from `./backups/r3-old.tar` (override)
* Nodes without snapshots will deploy fresh

> See [tools snapshot save](tools/snapshot/save.md) for information on creating snapshots.

### Environment variables

#### `CLAB_RUNTIME`

Default value of "runtime" key for nodes, same as global `--runtime | -r` flag described above.
Affects all containerlab commands in the same way, not just `deploy`.

Intended to be set in environments where non-default container runtime should be used, to avoid needing to specify it for every command invocation or in every configuration file.

Example command-line usage: `CLAB_RUNTIME=podman containerlab deploy`

#### `CLAB_VERSION_CHECK`

Can be set to "disable" value to prevent deploy command making a network request to check new version to report if one is available.

Useful when running in an automated environments with restricted network access.

Example command-line usage: `CLAB_VERSION_CHECK=disable containerlab deploy`

#### `CLAB_LABDIR_BASE`

To change the [lab directory](../manual/conf-artifacts.md#identifying-a-lab-directory) location, set `CLAB_LABDIR_BASE` environment variable accordingly. It denotes the base directory in which the lab directory will be created.

The default behavior is to create the lab directory in the same directory as the topology file (`clab.yml` file).

### Examples

#### Deploy a lab using the given topology file

```bash
containerlab deploy -t mylab.clab.yml
```

#### Deploy a lab and regenerate all configuration artifacts

```bash
containerlab deploy -t mylab.clab.yml --reconfigure
```

#### Preview changes to an already deployed lab

```bash
containerlab deploy -t mylab.clab.yml --dry-run
```

Shows the [reconciliation plan](#reconciliation-behavior) without applying it. Running the same command without `--dry-run` applies the changes in place.

The `apply` alias can be used for the same operation:

```bash
containerlab apply -t mylab.clab.yml
```

It can also reconcile an already deployed lab by name:

```bash
containerlab apply --name mylab
```

#### Deploy a lab without specifying topology file

Given that a single topology file is present in the current directory.

```bash
containerlab deploy
```

#### Deploy a lab using short flag names

```bash
clab dep -t mylab.clab.yml
```

#### Deploy a lab from a remote URL with curl

```bash
curl -s https://gist.githubusercontent.com/hellt/9baa28d7e3cb8290ade1e1be38a8d12b/raw/03067e242d44c9bbe38afa81131e46bab1fa0c42/test.clab.yml | \
    sudo containerlab deploy -t -
```

[^1]: The repository is cloned with `--depth 1` parameter.
