Switch Ports
Switch port profiles as reviewable JSONC files: export, edit, apply, diff
Switch port configuration is a config-as-code surface: export a switch’s port overrides to a JSONC file, keep it in git, edit it in review, and apply it back. Three commands make the loop:
unifly devices ports <SWITCH> # Read current port config
unifly devices ports-export <SWITCH> # Export overrides as JSONC
unifly devices port-set <SWITCH> -F ports.jsonc # Apply a file
<SWITCH> accepts a device ID or MAC. Port indices are 1-based throughout, matching the labels on the hardware and the controller’s wire format.
🔗Reading Ports
unifly devices ports <SWITCH> # Table of ports and overrides
unifly devices ports <SWITCH> --with-clients # Annotate with what's plugged in
unifly devices ports <SWITCH> -o json # Full structured output
--with-clients adds a connections column counting the end-user clients and adopted devices (APs, downstream switches) observed on each port; JSON output carries a connections array with kind, mac, name, and, for clients, ip and vlan_id.
🔗Quick Single-Port Changes
For one-off tweaks, port-set takes the port index and flags directly:
unifly devices port-set <SWITCH> 9 --mode access --native-vlan IoT
unifly devices port-set <SWITCH> 1 --mode trunk --tagged-vlans "Infra,IoT,Cameras"
unifly devices port-set <SWITCH> 5 --name "camera-ne" --poe auto
unifly devices port-set <SWITCH> 3 --speed 2500
unifly devices port-set <SWITCH> 7 --reset # Back to controller defaults
--native-vlanand--tagged-vlansaccept network names or IDs. Names are resolved against the controller’s network list, and an ambiguous name errors out rather than picking one.--mode trunkwithout--tagged-vlanstrunks all VLANs; passing an explicit list switches the port to a custom tagged set.--poeacceptsoff,auto,pasv24, andpassthrough. There is noon:autois the on/negotiate mode.--speed autore-enables auto-negotiation; the numeric values pin a link speed.--resetremoves the port’s override entirely, returning it to controller defaults. It prompts for confirmation unless-yis passed.
🔗The JSONC Payload
port-set -F applies a JSONC file (comments and trailing commas are allowed) describing one or more ports on a single device:
{
"ports": [
// Trunk uplink carrying all VLANs
{
"index": 1,
"name": "uplink",
"mode": "trunk",
"native_vlan": "Infra",
"tagged_all": true,
"poe": "off",
},
// Access port pinned to one VLAN
{
"index": 9,
"name": "mac-mini",
"mode": "access",
"native_vlan": "Personal",
"poe": "auto",
},
// Clear a stale override
{ "index": 7, "reset": true },
],
}
Per-port fields: name, mode (access / trunk / mirror), native_network_id (alias native_vlan), tagged_network_ids (alias tagged_vlans), tagged_all, poe, speed, and reset. Unknown fields are rejected with an error, so typos surface instead of silently disappearing.
🔗Splice Semantics
The payload is a splice, not a replacement:
- Ports not listed keep their existing override untouched.
- A listed port merges the given fields into its override; omitted fields are unchanged.
- An empty
tagged_network_ids: []clears the tagged list (JSON Merge Patch style); omitting the field leaves it alone. "reset": trueremoves that port’s override entry entirely.
This means a payload file can safely describe just the ports you care about, and applying it twice is idempotent.
🔗Export and Drift Detection
ports-export emits the device’s current configuration in exactly the shape port-set -F accepts:
unifly devices ports-export <SWITCH> > ports.jsonc # Only ports with overrides
unifly devices ports-export <SWITCH> --all > ports.jsonc # Every port
unifly devices ports-export <SWITCH> --with-clients > ports.jsonc
The round-trip is non-destructive: export, then re-apply the same file, and the device configuration is unchanged.
With --with-clients, the export prepends a comment line above each port recording what was observed on it:
// last-seen 2026-08-05T17:20:00Z: aa:bb:cc:dd:ee:01 (Living Room AP, device)
{
"index": 3,
"name": "ap-living-room",
...
}
Commit the export to git and re-export on a schedule to catch moved cables, swapped APs, or surprise devices. Every export stamps a fresh timestamp into each // last-seen marker, so strip the timestamps before diffing to see only real occupant changes:
unifly devices ports-export <mac> --with-clients \
| sed -E 's|// last-seen [^:]+: |// occupant: |' > ports/<mac>.jsonc
git diff ports/<mac>.jsonc
The // last-seen prefix (with a single trailing space) is a stable parse anchor if you script against the export.
🔗Authentication
Port configuration lives on Session API routes; the Integration API does not expose port VLAN settings. On UniFi OS consoles an Integration API key satisfies these routes, so no username or password is needed. Classic standalone controllers require auth_mode = "session" or "hybrid".
🔗Next Steps
- CLI Commands: the condensed switch-port command list
- Networks: the VLANs your port profiles reference
- Troubleshooting: auth-mode errors and fixes