The Foundation: Two Configurations, One Device
If you're coming from Cisco IOS, the Junos configuration model will feel foreign at first. On IOS, when you type a command in config mode, it takes effect immediately. That's it. Done. There's no second chance.
Junos works differently. Every Juniper device running Junos OS maintains two separate configuration states: the candidate configuration and the active configuration. The active configuration is what's actually running on the device right now — routing protocols, interfaces, firewall filters, all of it. The candidate configuration is the working copy you're editing. Nothing you type in configuration mode affects the live network until you issue a commit.
This isn't just a design quirk. It's a deliberate architecture that gives you a window to review, validate, and stage changes before they hit the wire. Once you've worked with it for a while, going back to platforms that apply changes immediately starts to feel genuinely reckless.
Walking Through a Commit
When you enter configuration mode on a Junos device, you're working against the candidate config. You can make sweeping changes — modify OSPF timers, rearrange interface addresses, add firewall filters — and none of it matters to the running device until commit is issued.
infrarunbook-admin@sw-infrarunbook-01> configure
Entering configuration mode
[edit]
infrarunbook-admin@sw-infrarunbook-01# set interfaces ge-0/0/1 unit 0 family inet address 10.10.10.1/30
[edit]
infrarunbook-admin@sw-infrarunbook-01# set protocols ospf area 0.0.0.0 interface ge-0/0/1.0
[edit]
infrarunbook-admin@sw-infrarunbook-01# commit
commit completeWhat happens under the hood during that commit? Junos performs a syntax check, validates the logical consistency of the configuration — things like referencing a policy that doesn't exist will fail here — and then atomically applies the configuration to the active state. If any part of that validation fails, the entire commit is rejected and the active configuration is untouched.
That atomicity is key. You won't end up in a half-applied state where three of your five changes went through and two didn't. Either it all works or nothing changes. In my experience, this alone has prevented more partial-outage scenarios than I can count.
commit check: Validate Before You Touch Anything
Before committing, you can run commit check to validate the candidate configuration without actually applying it. This is especially useful in change windows when you want to pre-stage changes and verify them hours before the maintenance.
[edit]
infrarunbook-admin@sw-infrarunbook-01# commit check
configuration check succeedsIf something's wrong, you'll know before the change window rather than during it. I've seen engineers skip this step and then discover a typo in a policy name at 2 AM. Don't be that engineer. Make commit check the first thing you run after staging a change, before you even think about the actual commit.
Comparing Before You Commit
Junos gives you another essential pre-commit tool: show | compare. This outputs a diff between the candidate config and the active config, similar to unified diff format. Lines prefixed with + are additions, lines with - are deletions.
[edit]
infrarunbook-admin@sw-infrarunbook-01# show | compare
[edit interfaces ge-0/0/2 unit 0 family inet]
+ address 192.168.50.1/29;
[edit protocols bgp group UPSTREAM]
+ neighbor 10.20.30.2 {
+ description "Transit uplink";
+ peer-as 65100;
+ }
[edit policy-options policy-statement EXPORT-TO-UPSTREAM]
+ term PERMIT-LOCAL {
+ from {
+ route-filter 192.168.50.0/29 exact;
+ }
+ then accept;
+ }Running this before every commit should be muscle memory. It's the final sanity check — is this actually what I intended to change? You'd be surprised how often the answer is no, especially when working from a script or a paste buffer that got mangled somewhere.
commit confirmed: Your Safety Net
This is where Junos genuinely shines compared to most other platforms. commit confirmed applies the configuration but automatically rolls back after a specified timeout unless you confirm it with a second commit.
[edit]
infrarunbook-admin@sw-infrarunbook-01# commit confirmed 5
commit confirmed will be rolled back in 5 minutes
commit complete
### If you don't issue 'commit' within 5 minutes ###
Waiting for commit confirmed rollback (170 seconds)...
Rollback complete.The default timer is 10 minutes if you don't specify one. You can set anywhere from 1 to 65535 minutes, but in practice most engineers use 5–15 minutes for firewall changes and 2–5 for anything touching BGP or OSPF where you can verify convergence quickly.
The workflow is this: you issue commit confirmed 5, the config goes live, you verify your change worked — ping across the new link, check the routing table, test the application — and then you issue a plain commit to lock it in. If something went wrong — your SSH session drops, the routing change broke your path back to the device, or you just panicked — the timer expires and the device rolls back on its own. You come back to the original working config, no emergency procedure required.
I have seen this save a production environment more than once. A BGP policy change accidentally started advertising internal RFC 1918 routes to an upstream provider. The commit confirmed timer expired, the BGP session came back to its original state, and the NOC never even opened a ticket. Without commit confirmed, that would have been a full manual rollback procedure under pressure with half the team paged in.
Understanding Rollback History
Junos keeps a history of committed configurations. By default, up to 50 rollback files are retained — rollback 0 through rollback 49. Rollback 0 is always the currently active configuration. Rollback 1 is the previous commit. Rollback 2 is the one before that, and so on down the line.
infrarunbook-admin@sw-infrarunbook-01> show system rollback
Index Date Time User Log
0 2026-04-08 14:32:11 UTC infrarunbook-admin Added BGP neighbor 10.20.30.2
1 2026-04-08 11:15:04 UTC infrarunbook-admin OSPF timer tuning
2 2026-04-07 22:48:33 UTC infrarunbook-admin
3 2026-04-07 09:12:01 UTC infrarunbook-admin Interface renumber for migration
4 2026-04-06 16:55:21 UTC infrarunbook-adminTo roll back to a previous configuration, enter configuration mode and use the rollback command followed by the index number. This loads that historical config into the candidate config. It does not automatically apply it — you still need to review and commit.
infrarunbook-admin@sw-infrarunbook-01> configure
Entering configuration mode
[edit]
infrarunbook-admin@sw-infrarunbook-01# rollback 1
load complete
[edit]
infrarunbook-admin@sw-infrarunbook-01# show | compare
[edit protocols bgp group UPSTREAM]
- neighbor 10.20.30.2 {
- description "Transit uplink";
- peer-as 65100;
- }
[edit]
infrarunbook-admin@sw-infrarunbook-01# commit
commit completeThat intermediate review step is intentional. You have a chance to verify you're loading exactly what you think you're loading before the rollback takes effect on the live device.
commit comment: Leaving a Paper Trail
When you commit, you can attach a comment that will appear in the rollback history. This is more useful than it sounds in environments with multiple engineers making changes throughout the day.
[edit]
infrarunbook-admin@sw-infrarunbook-01# commit comment "CR-2041: Added ge-0/0/3 to VLAN 120 for new server segment"
commit completeThat comment shows up when you run show system rollback. When you're staring at rollback index 7 at midnight trying to figure out what changed three days ago, a descriptive comment is the difference between a 2-minute investigation and a 20-minute one. Make it a team habit — ideally tied to your change request numbers.
Real-World Scenario: Firewall Filter Deployment
Let's walk through a realistic change. You need to deploy a firewall filter on a transit interface to block a known-bad source prefix that's been generating junk traffic toward your 10.100.0.0/16 infrastructure.
[edit]
infrarunbook-admin@sw-infrarunbook-01# edit firewall family inet
[edit firewall family inet]
infrarunbook-admin@sw-infrarunbook-01# set filter BLOCK-JUNK-SOURCES term DROP-KNOWN-BAD from source-address 172.16.99.0/24
infrarunbook-admin@sw-infrarunbook-01# set filter BLOCK-JUNK-SOURCES term DROP-KNOWN-BAD then discard
infrarunbook-admin@sw-infrarunbook-01# set filter BLOCK-JUNK-SOURCES term ACCEPT-ALL then accept
[edit firewall family inet]
infrarunbook-admin@sw-infrarunbook-01# top
[edit]
infrarunbook-admin@sw-infrarunbook-01# set interfaces ge-0/0/0 unit 0 family inet filter input BLOCK-JUNK-SOURCES
[edit]
infrarunbook-admin@sw-infrarunbook-01# commit check
configuration check succeeds
[edit]
infrarunbook-admin@sw-infrarunbook-01# show | compare
[edit firewall]
+ family inet {
+ filter BLOCK-JUNK-SOURCES {
+ term DROP-KNOWN-BAD {
+ from {
+ source-address {
+ 172.16.99.0/24;
+ }
+ }
+ then discard;
+ }
+ term ACCEPT-ALL {
+ then accept;
+ }
+ }
+ }
[edit interfaces ge-0/0/0 unit 0 family inet]
+ filter {
+ input BLOCK-JUNK-SOURCES;
+ }
[edit]
infrarunbook-admin@sw-infrarunbook-01# commit confirmed 10 comment "Block 172.16.99.0/24 inbound on ge-0/0/0"
commit confirmed will be rolled back in 10 minutes
commit completeYou then verify the filter is counting hits with show firewall filter BLOCK-JUNK-SOURCES, confirm legitimate traffic is passing, and issue the confirming commit. This is the right way to push a firewall change into production — with a safety net that recovers automatically if a misconfigured term locks you out of the device.
Real-World Scenario: Emergency Rollback Under Pressure
Now for the scenario everyone eventually faces. A change went out and something is wrong. BGP is flapping, an OSPF adjacency isn't forming, calls are coming in from the help desk. You need to roll back fast.
infrarunbook-admin@sw-infrarunbook-01> configure
Entering configuration mode
[edit]
infrarunbook-admin@sw-infrarunbook-01# rollback 1
load complete
[edit]
infrarunbook-admin@sw-infrarunbook-01# show | compare
[edit protocols ospf area 0.0.0.0]
- interface ge-0/0/2.0 {
- metric 1000;
- }
[edit]
infrarunbook-admin@sw-infrarunbook-01# commit comment "Emergency rollback - OSPF adjacency failure post-change"
commit completeThe whole sequence takes under a minute when you know the steps. That speed matters enormously. Every second a routing adjacency is down is another second of impact. Practicing this workflow before you need it — not in production, but in a lab or on a non-critical device — means your hands know the commands when your brain is under pressure.
commit synchronize on Dual-RE Platforms
On platforms with dual Routing Engines — like the MX480 or PTX series — there's an important additional consideration. When you commit, the change applies to the master RE. For it to also be applied to the backup RE, you either configure chassis redundancy graceful-switchover with commit synchronization, or you explicitly use commit synchronize.
[edit]
infrarunbook-admin@sw-infrarunbook-01# commit synchronize comment "VLAN 200 added for storage segment"
re0:
commit complete
re1:
commit completeWithout this, a switchover to the backup RE brings up the old configuration — the one predating your most recent commits. I've seen this bite teams who carefully tested and committed a change on the master RE, then triggered a failover during an unrelated maintenance window, and suddenly found themselves running a config that predated weeks of work. Always use commit synchronize on dual-RE platforms. Make it a standard in your runbooks.
Automation: The Same Safety Properties Apply
When automating Junos configuration changes via NETCONF, the Python
ncclientlibrary, or Ansible's
junos_configmodule, the same commit semantics apply. Commit confirmed is available through NETCONF's confirmed-commit capability, defined in RFC 6241. If your automation pipeline pushes a change and the session drops before a confirming commit is sent, the device rolls back automatically.
# Conceptual NETCONF confirmed-commit flow
# Management host connecting to sw-infrarunbook-01 at 10.10.10.1
from ncclient import manager
with manager.connect(
host="10.10.10.1",
port=830,
username="infrarunbook-admin",
hostkey_verify=False
) as m:
m.lock(target="candidate")
m.edit_config(target="candidate", config=config_xml)
m.commit(confirmed=True, timeout="300") # 5-minute rollback window
# Verify change is correct, then confirm
m.commit()
m.unlock(target="candidate")The discipline that commit confirmed enforces manually translates cleanly into automation. Your scripts get the same safety property a human operator gets at the CLI — transient network failures or script crashes don't leave the device in a broken half-changed state.
Common Misconceptions
Misconception 1: commit confirmed is itself a rollback mechanism. It isn't. commit confirmed is a deferred rollback trigger. The configuration you committed is live the moment you issue the command. You're not in a preview mode. Real traffic is hitting your new firewall filter, your new routing policy is in effect. If you want to keep it, confirm it. If you don't confirm in time, the device rolls itself back.
Misconception 2: rollback immediately reverts the live config. As shown above, the rollback command loads a historical configuration into the candidate config. It doesn't touch the active configuration until you issue a commit. This is a common point of confusion for engineers who are used to IOS-style
copy startup-config running-configsemantics, where the action is immediate.
Misconception 3: rollback 0 resets the device to factory defaults. Rollback 0 is the current active configuration, not a blank slate. Running rollback 0 in configuration mode discards any uncommitted changes in the candidate config and resets the candidate back to match active. The live config is unchanged either way. If you want factory defaults, that's a different procedure entirely.
Misconception 4: commit check covers everything. Commit check validates syntax and referential integrity — it catches a missing policy name, a malformed address, an invalid interface reference. It cannot tell you whether your routing policy logic is correct, whether your firewall filter has unintended side effects, or whether a metric change will cause suboptimal path selection. It's a necessary sanity check, not a guarantee of correctness. That's what commit confirmed is for.
Misconception 5: rollback history is unlimited. Junos retains up to 50 rollback files by default. After that, the oldest entries are dropped as new commits push them out. On actively managed devices that see multiple commits a day, 50 commits might only cover a week of history. If you need audit trails longer than that — and in most regulated or enterprise environments, you do — you need external configuration backup tooling. RANCID, Oxidized, or a proper network automation platform all solve this. Device-side rollback history alone is not a compliance-grade audit trail.
Final Thoughts
The commit and rollback system in Junos is one of the best-designed aspects of the platform. It forces a clean separation between staging a change and applying it, gives you syntax and consistency validation before anything goes live, and provides an automatic recovery mechanism that can pull you out of bad situations without any human intervention at all.
The workflow — stage, check, compare, commit confirmed, verify, confirm — takes maybe 60 extra seconds compared to just typing commands and hoping. Those 60 seconds have saved me hours of incident response more than once. Build the habit, enforce it in your team runbooks, and make commit confirmed the default for anything that touches a production path.
