Caution
This is a beta release of NetBox intended for testing and evaluation. Do not use this software in production. Also be aware that no upgrade path is provided to future releases.
Warning
This release of NetBox drops support for PostgreSQL 14.
Warning
The PostgreSQL database must support the ltree extension. This is a trusted module which ships with PostgreSQL and does not require superuser permission to activate. It will be installed automatically upon upgrade.
Warning
This release of NetBox drops support for Redis 5.x.
Breaking Changes
- PostgreSQL 14 is no longer supported. NetBox now requires PostgreSQL 15 or later: The upgrade script will abort when connected to an earlier release. (NetBox v4.6 reported this as a warning.)
- Redis 5.x is no longer supported. NetBox now requires Redis 6.0 or later.
- Selection and multiple selection custom field values are now returned as objects specifying both the raw value and its human-friendly label (e.g.
{"value": "datacenter", "label": "Data Center"}) in both the REST and GraphQL APIs. These fields continue to accept the raw value on write. - The
protocolandportsfields on theipam.Serviceandipam.ServiceTemplatemodels have been replaced by a unifiedport_mappingsfield, which supports multiple protocols per service. The legacy fields are retained (as deprecated) in the REST and GraphQL APIs, but at the ORM level they are now read-only properties derived fromport_mappings: Passingprotocolorportsto the model raises aTypeError, and assigning toservice.portsraises anAttributeError. - Because
protocolis now filtered against theport_mappingsarray rather than a dedicated model field, the character-based REST filter lookups previously generated for it (protocol__ic,protocol__isw,protocol__empty, etc.) are no longer available. Theport__emptylookup has been removed as well. - The GraphQL filters for
ipam.Serviceandipam.ServiceTemplatehave changed shape: The nestedportsinteger lookup has been replaced by the flatport,port__gt,port__gte,port__lt, andport__lteparameters (each accepting a list of values), alongside the newport_mappingsparameter. Additionally, the members ofServiceProtocolEnumhave been renamed to drop a spuriousROLE_prefix (e.g.ROLE_TCPis nowTCP). - Config context data is now pre-rendered and cached for each device and virtual machine, and is always included in their REST API representations. The
DeviceWithConfigContextSerializerandVirtualMachineWithConfigContextSerializerclasses have been removed (merged into the base serializers), and the?exclude=config_contextquery parameter is now silently ignored. - Failed bulk create and update operations via the REST API now return a structured response of the form
{"detail": ..., "errors": [{"index": N, "errors": {...}}]}, correlating each error with the index of the offending object in the submitted list. (Bulk operations remain all-or-none.) - API token plaintexts can no longer be specified by the client when creating a token via the REST API. The
tokenfield is now read-only, and any value supplied is ignored. (This restriction was already in effect in the web UI.) - Executing a custom script via the REST API now requires that the calling token have its write ability enabled.
- Updates to the global search cache are now deferred to a background task. As a result, a newly created or modified object may not appear in search results for a brief period. (When no background worker is running, the index is updated synchronously as before.)
- Nested group models (Region, SiteGroup, Location, DeviceRole, Platform, TenantGroup, ContactGroup, WirelessLANGroup, etc.) are now backed by a PostgreSQL
ltreecolumn rather than django-mptt. The MPTT-backedNestedGroupModelbase class is retained for backward compatibility with plugins, but is deprecated: New code should useNestedLtreeGroupModelinstead. - django-tables2 has been upgraded to v3.0, which renames its
querystringtemplate tag toquerystring_replaceand removes theRelatedLinkColumnclass. - The
requestobject passed to custom link templates is now a sanitized subset of the current request. Only theid,path,path_info,method,GET, anduserattributes are available; cookies, headers, and session state are no longer accessible. - URL custom field values are now validated against the
ALLOWED_URL_SCHEMESconfiguration parameter. A value entered without a scheme is assumed to usehttpsand stored as an absolute URL. - Webhooks now support a configurable timeout. If you have lowered
RQ_DEFAULT_TIMEOUTto 60 seconds or less, you must also setWEBHOOK_DEFAULT_TIMEOUTto a lower value; NetBox will refuse to start otherwise. - Specifying an email server under the
EMAILconfiguration parameter is now mandatory in order to send mail: A deployment which does not defineEMAIL['SERVER']will raise anInvalidMailerexception when attempting to send, rather than failing at the SMTP connection. - The upgrade script now runs the
rebuild_config_context_cachemanagement command to populate the new config context cache. This may extend the duration of the upgrade for deployments with a large number of devices and virtual machines. - Removal of deprecated behavior
- The
housekeepingmanagement command has been removed. (Its constituent tasks are performed by the individual management commands introduced in NetBox v4.6.) - NetBox's custom
querystringtemplate tag has been removed in favor of Django's built-in tag of the same name. - The legacy Sentry configuration parameters
SENTRY_DSN,SENTRY_SAMPLE_RATE,SENTRY_SEND_DEFAULT_PII, andSENTRY_TRACES_SAMPLE_RATEhave been removed. UseSENTRY_CONFIGinstead. - The obsolete
DEFAULT_ACTION_PERMISSIONSconstant has been removed. - Support for legacy view action mappings has been dropped, and the
LEGACY_ACTIONSconstant has been removed. - Registered models are no longer populated under
registry['models']. (UseObjectType.objects.public()instead.) Theregistry['denormalized_fields']store has been removed as well. - The backward compatibility shims for
OptionalLimitOffsetPagination(nowNetBoxPagination),ExpandableIPAddressField(nowExpandableIPNetworkField), andexpand_ipaddress_pattern()(nowexpand_ipnetwork_pattern()) have been removed. - The
request_idandusernamekeys have been removed from the context available to outgoing webhooks. Userequest.idandrequest.userinstead. - The automatic reverse relationship created by
OwnerMixin(e.g.site_set) has been removed.
- The
New Features
Cooling Infrastructure Modeling (#22447)
NetBox has long modeled power distribution end to end, but had no equivalent for cooling. This release introduces a cooling data model which deliberately mirrors the power model, so that the concepts and workflows feel familiar.
Two new top-level models parallel PowerPanel and PowerFeed: CoolingSource represents facility-level cooling plant (a chiller, cooling tower, dry cooler, or facility water system) scoped to a site or location, and CoolingFeed represents a coolant loop delivered from a source to a rack. Two new device components parallel PowerPort and PowerOutlet: CoolingIntake represents a coolant intake on a device (e.g. a server cold-plate connection or a CDU's facility water inlet), and CoolingOutflow represents a coolant outlet on a CDU or manifold which supplies downstream equipment. Each intake may reference the upstream outflow which serves it, and both components have corresponding device type templates. CDUs and manifolds are modeled as ordinary devices carrying these components.
Lightweight descriptive attributes have also been added for users who want to record cooling characteristics without modeling the full plumbing: a cooling_method field (air, liquid, hybrid, or immersion) on the Device, DeviceType, and ModuleType models, and cooling_capability (air-only, hybrid, or liquid-only) and cooling_capacity fields on the Rack and RackType models.
Channelized Subinterfaces (#20972)
Channelized (breakout) interfaces can now be modeled natively. A new channels field on the Interface model indicates the number of physical channels into which an interface is divided, and each channel is represented by a subinterface of the new generic channel type, bound to its parent via the new channel_id field. A single cable terminates to the channelized parent interface, and NetBox traces a distinct cable path for each channel subinterface. Both fields are available on interface templates as well.
Multi-Protocol Application Services (#20285)
Application services and service templates can now expose the same port on multiple protocols — for example, DNS listening on both tcp/53 and udp/53. The single-protocol protocol and ports fields have been replaced by a unified port_mappings field, represented in the APIs as a flat list of protocol/port strings (e.g. ["tcp/80", "udp/53"]). New port_mappings, protocol, and port filters are available in the UI and in both APIs, with the latter two correlated so that they must be satisfied by a single mapping.
Module Bay Types (#19731)
A new ModuleBayType model has been introduced to convey which kinds of modules a module bay is able to accommodate (e.g. an SFP28 cage or a PCIe x16 slot). Bay types can be assigned to module bays, module bay templates, and module types; where both a bay and a module type declare bay types, NetBox validates that the two sets share at least one type in common before permitting installation. Bay types assigned to a module bay template propagate automatically to each instantiated module bay.
Relocating Installed Modules (#15289)
An installed module can now be moved to a different module bay, including a bay on a different device, rather than having to be deleted and recreated. A move relocates the module's entire subtree — its components, its own module bays, and any child modules installed within them — and re-resolves any component names, labels, and positions derived from the module type's templates for the destination bay. Cross-device moves are permitted only where the moved components carry no active topology or device-scoped configuration.
Background Processing for REST API Requests (#21992)
Bulk write operations via the REST API can now be processed as a background job rather than synchronously, avoiding proxy and gateway timeouts on large batches. Appending ?background=true to a bulk write request enqueues a job and immediately returns an HTTP 202 Accepted response containing the job's ID and URL; the job's data field records the response the synchronous request would have returned. Note that validation is deferred to the worker, so a 202 response indicates only that the request was accepted, and the job's final status must be inspected to confirm the outcome.
Per-Object Errors for Bulk Operations (#20054)
When a bulk create or update via the REST API fails validation, the response now identifies each offending object by its index within the submitted list, along with its specific field errors, rather than reporting only the first failure. This enables clients to correct and resubmit only the objects which actually failed.
Pre-Rendered Config Context Data (#21025)
Rather than compiling config context data on demand from the full set of applicable ConfigContext instances, NetBox now pre-renders each device's and virtual machine's merged context data and caches it on the object itself. The cache is invalidated automatically whenever an upstream change is detected — a config context being created, modified, or deleted, or a change to an attribute which determines which contexts apply — and repopulated by a non-blocking background job. During the brief window between invalidation and re-render, reads fall back to the original on-demand rendering path, so the data returned is always correct rather than stale.
Snapshot-Aware Event Rule Conditions (#18159)
Event rule conditions can now inspect the pre-change and post-change snapshots captured at the time of an event, rather than only the object's current data. New changed and unchanged operators compare an attribute's value across the two snapshots, and the snapshots.prechange.<attr> and snapshots.postchange.<attr> dot-path syntax exposes either snapshot to any standard operator. This makes it possible to express the long-requested "fire only when status changes to active" rule, avoiding webhooks and scripts triggered by unrelated updates. A new regex operator has been added as well, and conditions which reference an attribute that cannot be resolved now fail closed and log an error rather than silently disabling the rule.
Enhancements
- #15165 - Re-render only the affected fieldset, rather than the entire form, when an HTMX-driven selection changes
- #18645 - Support the bulk import of cables having multiple terminations per side
- #18821 - Set or update an interface's primary MAC address in a single operation via the
mac_addressfield - #20897 - Include the label alongside the value for selection custom fields in the REST & GraphQL APIs
- #21367 - Add a read-only
is_primaryfield to the MAC address REST API representation - #21712 - Support description annotations for static choice fields, and permit choices to be declared as dictionaries in
FIELD_CHOICES - #22205 - Add an
end_of_lifedate field to device types and module types to aid in hardware lifecycle planning - #22231 - Introduce a
nulls_firstparameter to control the placement of empty values when ordering by a custom field - #22409 - Disallow client-specified API token plaintexts via the REST API
- #22411 - Enforce token write ability when executing a custom script via the REST API
- #22441 - Record and display the execution time of each background job
- #22446 - Introduce breadcrumbs support for declarative layouts
- #22486 - Support a configurable timeout for webhooks, with a new
WEBHOOK_DEFAULT_TIMEOUTconfiguration parameter - #22595 - Introduce the
BULK_UPDATE_CHUNK_SIZEconfiguration parameter to bound the number of rows affected by a single bulkUPDATEstatement - #22604 - Document the experimental Python package installation and upgrade workflow
- #22607 - Sanitize the HTTP request passed to the template context when rendering custom links
- #22640 - Enforce
ALLOWED_URL_SCHEMESwhen validating URL custom field values - #22757 - Support arbitrary help text on inline form fields
- #22786 - Publish NetBox releases to the production Python Package Index (PyPI)
- #22851 - Unpin
social-auth-coreto permit the installation of newer PyJWT versions
Performance Improvements
- #21326 - Defer updates to the global search cache to a background job, so that they no longer delay the response
- #21355 - Maintain denormalized field data using PostgreSQL triggers rather than Python signal handlers
- #21418 - Replace django-mptt with a PostgreSQL
ltreeimplementation for hierarchical models
Plugins
- #19821 - Introduce
GenericObjectChoiceFieldandGenericObjectFormMixinto represent a generic foreign key relation as a single form field - #22351 - Enable plugins to register custom Jinja filters and to inject context variables for config template rendering
- #22592 - Enable plugins to add fields and filters to NetBox's existing core GraphQL types
- #22770 - Enable plugins to register custom Event Rule action types by subclassing
EventRuleAction
Deprecations
- #22288 - The
JINJA2_FILTERSconfiguration parameter has been renamed toJINJA_FILTERS. The old name remains supported, but will be removed in NetBox v5.0. - #22593 - The
form_factor,width,outer_width,outer_height,outer_depth, andouter_unitfields on the Rack model have been deprecated, and will be removed in NetBox v5.0. These values will instead be inferred from the rack's assigned rack type, which will become a mandatory assignment. - #22935 - The custom scripts functionality in core NetBox has been deprecated in favor of a dedicated plugin, and will be removed in NetBox v5.0.
- The
protocolandportsfields on application services and service templates have been deprecated in favor ofport_mappings, and will be removed from the REST & GraphQL APIs in NetBox v5.0. - The MPTT-backed
NestedGroupModelbase class has been deprecated in favor ofNestedLtreeGroupModel, and will be removed in a future release.
Other Changes
- #19091 - Remove NetBox's custom
querystringtemplate tag in favor of Django's built-in tag - #20546 - Raise the minimum required PostgreSQL version from 14 to 15
- #20547 - Consolidate paired uniqueness constraints on nullable fields into single constraints using PostgreSQL's
NULLS NOT DISTINCT - #21565 - Remove the obsolete
housekeepingmanagement command - #21883 - Drop support for the deprecated Sentry configuration parameters
- #21886 - Remove the obsolete
DEFAULT_ACTION_PERMISSIONSconstant - #21888 - Remove support for legacy view actions
- #21891 - Remove the
modelskey from the application registry - #21902 - Upgrade django-tables2 to v3.0
- #22052 - Remove the backward compatibility shim for
OptionalLimitOffsetPagination - #22053 - Remove the backward compatibility shim for
ExpandableIPAddressField - #22054 - Remove the backward compatibility shim for
expand_ipaddress_pattern() - #22161 - Rename the filterset test mixin base classes to use a
*TestMixinsuffix - #22300 - Drop the automatic reverse relationship defined by
OwnerMixin - #22393 - Drop support for Redis 5.x
- #22438 - Omit the "2" suffix from the new Jinja plugin resources (
jinja_filters,get_jinja_context(),register_jinja_filters()) for consistency withJINJA_FILTERS - #22485 - Move the search subsystem's signal wiring into
AppConfig.ready()and break its import cycle - #22571 - Migrate from django-pglocks to django-pgware
- #22615 - Remove the legacy
request_idandusernamekeys from the webhook context - #22942 - Upgrade to Django 6.1