Nornir
Network automation framework for Python — parallel task execution across network device inventories. Nornir features: InitNornir for initialization with inventory (YAML/SimpleInventory), nr.run() for parallel task execution across all/filtered hosts, built-in tasks (netmiko_send_command, napalm_get), nornir-netmiko and nornir-napalm plugins, host/group filtering (nr.filter()), results processing (Result.result), failed_hosts tracking, task functions as plain Python, connection management (nornir.core.connections), and JSON/YAML output. Pure-Python alternative to Ansible for network automation — agent runs tasks on 100s of devices simultaneously.
Score Breakdown
⚙ Agent Friendliness
🔒 Security
Network device credentials in inventory files — must use environment variables or secrets manager, never commit credentials to git. Parallel SSH to production devices can cause SSH daemon overload. Agent network automation requires change window and rollback plan. hosts.yaml should be gitignored if containing credentials.
⚡ Reliability
Best When
Automating tasks across a fleet of network devices (10+ devices) in Python — Nornir provides inventory management, parallel execution, and task composability that Netmiko/NAPALM lack, with full Python flexibility that Ansible YAML lacks.
Avoid When
You need single-device automation (use Netmiko directly), GUI tooling, or your team prefers YAML playbooks (use Ansible).
Use Cases
- • Agent parallel device config — nr = InitNornir(config_file='config.yaml'); result = nr.run(task=netmiko_send_config, config_commands=['logging buffered 10000']); print_result(result) — push config to all devices simultaneously; agent configures 200 switches in parallel in seconds instead of minutes sequentially
- • Agent inventory-based automation — nr = InitNornir(config_file='config.yaml'); routers = nr.filter(type='router', site='NYC'); result = routers.run(task=napalm_get, getters=['interfaces', 'bgp_neighbors']) — filter devices by attributes; agent collects BGP state from all NYC routers simultaneously
- • Agent custom task function — def backup_config(task): output = task.run(task=netmiko_send_command, command_string='show running-config'); Path(f'backups/{task.host.name}.cfg').write_text(output.result) — Python function as Nornir task; agent runs backup_config on all devices in parallel; full Python flexibility inside tasks
- • Agent failed device handling — result = nr.run(task=deploy_acl); failed = result.failed_hosts; if failed: nr.filter(filter_func=lambda h: h.name in failed).run(task=deploy_acl, retry=True) — re-run failed hosts; agent automation handles partial failure gracefully; Nornir tracks which hosts succeeded and failed
- • Agent multi-vendor workflow — cisco = nr.filter(platform='cisco_ios'); juniper = nr.filter(platform='junos'); cisco.run(task=netmiko_send_config, config_commands=cisco_acl); juniper.run(task=napalm_configure, configuration=junos_config) — agent handles different vendors with appropriate tasks; one inventory, multiple execution strategies
Not For
- • Single device automation — Nornir's framework overhead isn't worth it for single device; use Netmiko directly
- • Non-network Python parallelism — Nornir is network-automation focused; for general parallel task execution use concurrent.futures or Ray
- • GUI or low-code network automation — Nornir is code-first; for low-code network automation use Ansible or NetBox
Interface
Authentication
Device credentials in inventory YAML or via environment variables. Inventory supports password and SSH key auth per host or group. Secrets should come from environment not hardcoded in inventory.
Pricing
Nornir is Apache 2.0 licensed. Free for all use.
Agent Metadata
Known Gotchas
- ⚠ Plugins installed separately — nornir_netmiko and nornir_napalm are separate packages; pip install nornir alone gives empty task library; agent Nornir scripts must: pip install nornir nornir-netmiko nornir-napalm; import from correct module: from nornir_netmiko.tasks import netmiko_send_command
- ⚠ num_workers affects device SSH load — InitNornir(runner={'plugin': 'threaded', 'options': {'num_workers': 20}}) runs 20 parallel SSH sessions; too many workers overwhelms device SSH daemon (default max 10 sessions); agent automation must tune num_workers per device type and SSH capacity
- ⚠ result.failed_hosts doesn't re-run — result = nr.run(task=fn); result.failed_hosts returns dict of failed hosts; Nornir doesn't retry automatically; agent code must explicitly: failed_nr = nr.filter(filter_func=lambda h: h.name in result.failed_hosts); failed_nr.run(task=fn)
- ⚠ Inventory must use group defaults for credentials — hosts.yaml credentials override group.yaml defaults; if credentials in group 'all' and host has no credentials, host inherits; agent inventory architecture must use group 'all' defaults with per-host overrides for device-specific credentials
- ⚠ Connection plugin keeps connection open — Nornir caches SSH connections across task runs; task2 reuses task1's SSH session; if device reboots between tasks, cached connection fails; call task.host.close_connections() before tasks requiring fresh connection in agent workflows with device restarts
- ⚠ Task result.result may be None on exception — if task raises exception, result.exception has traceback but result.result is None; agent code checking result.result without checking result.failed first raises TypeError; always check 'if not result[host].failed:' before accessing result.result
Alternatives
Full Evaluation Report
Detailed scoring breakdown, competitive positioning, security analysis, and improvement recommendations for Nornir.
Scores are editorial opinions as of 2026-03-06.