Back to blog

Cisco / IOS-XE  ·  Modern  ·  July 2026

Cisco IOS-XE
Model-Driven Config (NETCONF/RESTCONF)

The Ansible post pushed config as code, but it was still screen-scraping the CLI underneath. Model-driven programmability is the grown-up version: structured data validated against a schema, changed transactionally, over NETCONF or RESTCONF. This is how you talk to modern IOS-XE like an API instead of pretending to be a human at a terminal.

Cisco IOS-XE NETCONF RESTCONF YANG Automation

CLI automation — even good CLI automation — has a ceiling: you're parsing human-readable output that was never meant to be parsed, and pushing lines that either apply cleanly or leave the box half-configured. Model-driven programmability removes the guesswork. Config and state are described by YANG models (a schema); you read and write that structured data over NETCONF (XML over SSH, port 830) or RESTCONF (JSON/XML over HTTPS). Because it's schema-validated, an invalid change is rejected as a whole rather than half-applied, and reading state gives you clean JSON instead of show output to regex.

The trade-off versus the Ansible/CLI approach: model-driven is more rigid and has a learning curve (you must learn the models), but it's transactional, idempotent by nature, and truly programmable. For a fleet you drive from software — a NetBox-to-network pipeline, a self-service portal — this is the interface you want. Requires modern IOS-XE; classic IOS doesn't have it.

Prerequisites

01

Turn It On

Two features, one AAA user. NETCONF listens on SSH 830; RESTCONF rides the HTTPS server. Enable what you'll use.

IOS-XE — enable NETCONF-YANG and RESTCONF
R1(config)# aaa new-model
R1(config)# username auto privilege 15 secret <strong>

# NETCONF over SSH (tcp/830):
R1(config)# netconf-yang

# RESTCONF over the secure HTTP server (tcp/443):
R1(config)# ip http secure-server
R1(config)# restconf
# Give both a few seconds to initialise (the YANG stack starts lazily).
R1# show netconf-yang datastores
◆ Lock the API Down Like Any Management Plane

NETCONF (830) and RESTCONF (443) are full configuration channels — everything the management-plane hardening post says applies here. Restrict them to your automation host with a control-plane/VTY ACL, use real AAA (ideally TACACS+), and never expose them to anything untrusted. A model-driven API is more powerful than the CLI, which cuts both ways.

02

RESTCONF — the Quick Win

If you can curl, you can drive RESTCONF. Read structured state as JSON, and PATCH a change with a small body — no SSH session, no expect scripts.

Workstation — read and change interfaces over RESTCONF
# READ: every interface as clean JSON (ietf-interfaces model).
$ curl -sk -u auto:secret https://203.0.113.1/restconf/data/ietf-interfaces:interfaces \
    -H 'Accept: application/yang-data+json' | jq .

# CHANGE: set a description on Gi2 with a PATCH (merge, idempotent).
$ curl -sk -u auto:secret -X PATCH \
    https://203.0.113.1/restconf/data/ietf-interfaces:interfaces/interface=GigabitEthernet2 \
    -H 'Content-Type: application/yang-data+json' \
    -d '{"ietf-interfaces:interface":{"name":"GigabitEthernet2","description":"uplink-to-core"}}'
# Re-running the same PATCH is a no-op — idempotent by construction.

03

NETCONF — Transactional, With a Candidate Datastore

NETCONF's edge is the datastore model: on platforms that support a candidate config, you stage changes and commit them atomically — all or nothing — which is exactly what you want for multi-part changes.

Python (ncclient) — get-config, then an atomic edit
from ncclient import manager
m = manager.connect(host="203.0.113.1", port=830, username="auto",
                    password="secret", hostkey_verify=False)

# READ running config for one model subtree:
filt = "<interfaces xmlns='urn:ietf:params:xml:ns:yang:ietf-interfaces'/>"
print(m.get_config(source="running", filter=("subtree", filt)))

# WRITE: edit-config, then commit (candidate-capable platforms):
cfg = """<config><interfaces xmlns='urn:ietf:params:xml:ns:yang:ietf-interfaces'>
  <interface><name>GigabitEthernet2</name>
    <description>managed-by-netconf</description></interface>
</interfaces></config>"""
m.edit_config(target="candidate", config=cfg)
m.commit()   # atomic — rejected as a whole if any part is invalid
⚠ Gotcha — Native vs Standard Models, and Capabilities Vary

There are three model families and you'll meet all of them: IETF (ietf-interfaces — portable, lowest common denominator), OpenConfig (vendor-neutral, richer), and Cisco-IOS-XE-native (everything the CLI can do, but Cisco-specific). Portable code targets IETF/OpenConfig; anything the standard models don't cover forces you into the native model. Also, not every platform/version advertises a writable candidate datastore — check the capabilities the device returns on connect and fall back to running if needed. Don't assume; the device tells you what it supports.

04

Why Bother vs the Ansible Post Safe to Run

Both configure the box; they're different tools for different jobs. Here's the honest comparison so you pick right.

DimensionCLI / Ansible ios_config
DataUnstructured text you parse/generate
ValidationApplied line by line; can half-apply
Readsshow output → regex
IdempotencyYou engineer it
Best forQuick wins, brownfield, any IOS
DimensionNETCONF / RESTCONF
DataStructured, schema-validated (YANG)
ValidationTransactional — all or nothing
ReadsClean JSON/XML
IdempotencyInherent (merge to desired state)
Best forSoftware-driven pipelines, modern IOS-XE

Takeaways

  1. Model-driven beats screen-scraping — YANG-described data over NETCONF (SSH/830) or RESTCONF (HTTPS), validated against a schema.
  2. RESTCONF is the quick win — if you can curl, you can read clean JSON and PATCH idempotent changes.
  3. NETCONF adds a candidate datastore on capable platforms — stage and commit atomically, so multi-part changes never half-apply.
  4. Three model families: IETF (portable), OpenConfig (vendor-neutral), IOS-XE-native (everything, but Cisco-specific). Portable code prefers the first two.
  5. Check capabilities on connect — not every version has a writable candidate; the device advertises what it supports.
  6. It's a management channel — lock 830/443 to your automation host and use real AAA, exactly like the CLI.

Automating a Cisco fleet and tired of parsing show output?

NOCTIS builds model-driven automation for Cisco and MikroTik estates across Crete — NETCONF/RESTCONF pipelines, structured state, and transactional changes that don't half-apply — not brittle screen-scraping.

Book a Discovery Call →