Managing infrastructure as code (IaC) for networks isn’t just about writing YAML files; it’s about treating your network devices like software artifacts, complete with version control, automated testing, and continuous deployment pipelines.

Let’s peek under the hood of a typical network automation workflow using IaC. Imagine we’re deploying a new VLAN across a fleet of Cisco switches.

First, we define the desired state in a declarative configuration file, say, a Jinja2 template that generates Cisco IOS configuration.

# templates/vlans.j2

{% for vlan_id, vlan_name in vlans.items() %}


vlan {{ vlan_id }}


 name {{ vlan_name }}


{% endfor %}

This template is populated from a data source, perhaps a YAML file defining our VLANs:

# data/vlans.yaml
vlans:
  10: Marketing
  20: Engineering
  30: Sales

Now, a tool like nornir with the nornir-jinja2 plugin can render this template for each target device, generating the specific configuration needed.

# Example nornir task
from nornir import InitNornir
from nornir_jinja2.plugins.tasks import render_from_template

nr = InitNornir(config_file="config.yaml")

# Filter for specific devices if needed
switches = nr.filter(role="switch")

# Render the template
rendered_configs = switches.run(
    task=render_from_template,
    template="templates/vlans.j2",
    data="data/vlans.yaml"
)

The output for a specific switch might look like this:

!
vlan 10
 name Marketing
!
vlan 20
 name Engineering
!
vlan 30
 name Sales
!

This generated configuration is then applied to the devices. Tools like nornir-netmiko or napalm can handle the actual connection and configuration push.

# Example nornir task to apply config
from nornir_netmiko import NetmikoDriver

def apply_config(task):
    result = task.run(
        task=NetmikoDriver.send_config_set,
        config_commands=rendered_configs[task.host].result
    )
    # Handle results, errors, etc.

switches.run(task=apply_config)

The core problem IaC for networks solves is drift: the insidious divergence between what your network should be and what it actually is. Without IaC, manual changes, forgotten configurations, and undocumented modifications lead to inconsistencies that are incredibly difficult to track and remediate. IaC brings order by defining the desired state in a central, version-controlled repository.

The mental model here is that your network configuration is no longer a collection of disparate device states, but a single, auditable source of truth. Every change goes through a review process (like a Git pull request), is tested against a staging environment, and is deployed automatically. This drastically reduces human error, improves compliance, and accelerates deployment times.

A key aspect of this is idempotency. When you apply configuration generated by your IaC, the system should be able to run it multiple times without unintended side effects. For example, if a VLAN already exists, trying to create it again should result in no change, not an error. Tools and modules used for applying configuration, like Netmiko’s send_config_set or NAPALM’s load_merge_candidate and commit_config, are designed with idempotency in mind. They check the current state and only push the necessary changes to reach the desired state.

The next hurdle you’ll encounter is managing secrets, like device credentials, securely within your IaC pipeline.

Want structured learning?

Take the full Computer Networking course →