| name | add-config-param |
| description | Step-by-step guide for adding a new configuration parameter to NetBox, covering both static parameters (settings.py) and dynamic parameters (database-backed, editable via the admin UI). Use when the user asks to add a new configuration option, setting, or parameter to NetBox. |
Adding a Configuration Parameter to NetBox
NetBox has two distinct kinds of configuration parameters. Choose the right one before writing any code:
| Type | Where defined | Changed by | Takes effect |
|---|
| Static | settings.py via getattr(configuration, ...) | Editing configuration.py + restart | On WSGI restart |
| Dynamic | config/parameters.py PARAMS tuple | Admin UI or configuration.py | Immediately (cached in Redis) |
Use dynamic when:
- Operators need to tune the value without a service restart
- The parameter controls UI behavior or defaults (banners, page sizes, default values)
- Examples:
PAGINATE_COUNT, MAINTENANCE_MODE, BANNER_TOP
Use static when:
- The value must not change at runtime (auth backends, database config, secret keys)
- The value controls infrastructure that requires a restart anyway
- Examples:
ALLOWED_HOSTS, REMOTE_AUTH_BACKEND, LOGGING
Adding a Dynamic Configuration Parameter
Dynamic parameters are defined in netbox/netbox/config/parameters.py, stored in the ConfigRevision.data JSONField, cached in Redis, and editable via Admin > System > Configuration History.
Step 1 — Add to PARAMS
File: netbox/netbox/config/parameters.py
Add a ConfigParam entry to the PARAMS tuple, grouped logically with related parameters:
ConfigParam(
name='MY_PARAM',
label=_('My param'),
default=<default_value>,
description=_("One-sentence description of what this controls"),
field=forms.BooleanField,
field_kwargs={
'widget': forms.Textarea(attrs={'class': 'vLargeTextField'}),
},
),
Common field choices:
| Field | Use for |
|---|
forms.CharField (default) | Short strings |
forms.BooleanField | On/off toggles |
forms.IntegerField | Counts, sizes, timeouts |
forms.JSONField | Dicts/lists with free-form structure |
SimpleArrayField | Lists of strings (add field_kwargs={'base_field': forms.CharField()}) |
The default value is returned whenever no ConfigRevision row exists and the parameter is not hard-coded in configuration.py.
Step 2 — Use the parameter in code
Access via get_config() (request-scoped, cached) or the ConfigItem callable (deferred):
from netbox.config import get_config
value = get_config().MY_PARAM
from netbox.config import ConfigItem
MY_PARAM = ConfigItem('MY_PARAM')
get_config() returns the Config object which tries:
- Hard-coded value in Django
settings (set by configuration.py)
- Redis-cached active
ConfigRevision
ConfigParam.default
Step 3 — Document in the configuration docs
Add a section to the appropriate file under docs/configuration/:
| File | Category |
|---|
miscellaneous.md | General / doesn't fit elsewhere |
default-values.md | Default values for object fields |
security.md | Auth, permissions, URL validation |
data-validation.md | CUSTOM_VALIDATORS, PROTECTION_RULES |
graphql-api.md | GraphQL settings |
error-reporting.md | Sentry, logging |
remote-authentication.md | Remote auth settings |
development.md | Developer-only flags |
system.md | Low-level system settings |
Template for a dynamic parameter doc section:
## MY_PARAM
!!! tip "Dynamic Configuration Parameter"
Default: `<default_value>`
One or two sentences describing what the parameter does, what values are accepted,
and any side effects.
Step 4 — Register in the dynamic params index
File: docs/configuration/index.md
Add the new parameter to the bulleted list under "Dynamic Configuration Parameters", keeping the list alphabetically ordered:
* [`MY_PARAM`](./miscellaneous.md#my_param)
Step 5 — Optionally add to the example config
If the parameter is important enough that operators should know they can hard-code it, add a commented entry to netbox/netbox/configuration_example.py:
Place it near related parameters.
No migration needed
Dynamic parameters are stored in the ConfigRevision.data JSONField, which already exists. No database migration is required when adding a new ConfigParam.
Adding a Static Configuration Parameter
Static parameters live in settings.py and are read at startup from configuration.py. They take effect only after the WSGI service is restarted.
Step 1 — Add to settings.py
File: netbox/netbox/settings.py
Add a line in the "Set static config parameters" block, alphabetically within its logical group:
MY_PARAM = getattr(configuration, 'MY_PARAM', <default_value>)
For required parameters (no default), use getattr(configuration, 'MY_PARAM') with no fallback and add the parameter name to the required check near the top:
for parameter in ('ALLOWED_HOSTS', 'MY_PARAM', 'SECRET_KEY', 'REDIS'):
if not hasattr(configuration, parameter):
raise ImproperlyConfigured(f"Required parameter {parameter} is missing from configuration.")
Step 2 — Add validation (if needed)
If the parameter has constrained values, add an ImproperlyConfigured check immediately after the getattr line:
MY_PARAM = getattr(configuration, 'MY_PARAM', 'option_a')
if MY_PARAM not in ('option_a', 'option_b'):
raise ImproperlyConfigured(f"MY_PARAM must be 'option_a' or 'option_b' (found {MY_PARAM})")
For complex validation (importable paths, valid URLs, etc.) follow the patterns of PROXY_ROUTERS or RELEASE_CHECK_URL in settings.py.
Step 3 — Add to the example config
File: netbox/netbox/configuration_example.py
Add a commented entry with a brief inline comment explaining the parameter:
Step 4 — Document
Add a section to the appropriate docs/configuration/*.md file:
## MY_PARAM
Default: `<default_value>`
One or two sentences describing the parameter, accepted values, and any constraints.
---
Static parameters do not get the !!! tip "Dynamic Configuration Parameter" admonition.
Common Gotchas
- Dynamic params don't need a migration — the value is stored in the
ConfigRevision.data JSONField which already exists.
- Hard-coding a dynamic param in
configuration.py overrides the UI — the loop at the bottom of settings.py (for param in CONFIG_PARAMS: ...) sets the Django setting, which Config.__getattr__ checks first. Document this behaviour in the parameter's doc page.
forms.BooleanField with required=False: the ConfigFormMetaclass always adds required=False, so a BooleanField correctly represents a three-state (True / False / unset-use-default) UI. No extra field_kwargs needed for booleans.
SimpleArrayField needs base_field: always pass field_kwargs={'base_field': forms.CharField()}.
- No
ruff format on existing files — use ruff check only.
References
- Dynamic param definitions:
netbox/netbox/config/parameters.py
- Config loading /
Config class: netbox/netbox/config/__init__.py
ConfigRevision model: netbox/core/models/config.py
ConfigRevisionForm (metaclass): netbox/core/forms/model_forms.py
- Static config loading:
netbox/netbox/settings.py lines 67–213
- Example config:
netbox/netbox/configuration_example.py
- Config tests:
netbox/netbox/tests/test_config.py
- Documentation:
docs/configuration/