NetBox is an extensible open-source network source-of-truth application powering network automation. It manages network infrastructure data including data center infrastructure (DCIM), IP address management (IPAM), circuits, virtualization, wireless, VPNs, and more. It supports a plugin ecosystem and exposes both a REST API and GraphQL API.
NetBox is the core product maintained by NetBox Labs. The current version is 4.6 (Python 3.12+, Django 6.x).
docs/)pyproject.toml).
├── netbox/ — Django project root (run manage.py from here)
│ ├── manage.py
│ ├── netbox/ — Core settings, URLs, WSGI, plugin infrastructure
│ │ ├── settings.py — Main Django settings
│ │ ├── configuration.py — Instance configuration (gitignored)
│ │ ├── configuration_example.py — Configuration template
│ │ ├── configuration_testing.py — Test configuration
│ │ ├── urls.py — Root URL routing
│ │ ├── wsgi.py — WSGI entrypoint
│ │ ├── api/ — Core REST API infrastructure
│ │ ├── graphql/ — Core GraphQL schema
│ │ ├── models/ — Core model infrastructure (features, mixins)
│ │ ├── navigation/ — Navigation menu system
│ │ ├── plugins/ — Plugin system infrastructure
│ │ ├── registry.py — Object registry
│ │ ├── search/ — Full-text search implementation
│ │ ├── ui/ — UI utilities
│ │ └── tests/ — Core framework tests
│ ├── account/ — User account management
│ ├── circuits/ — Circuit and provider management
│ ├── core/ — Core data management (data sources, jobs)
│ ├── dcim/ — Data center infrastructure (devices, racks, cables, etc.)
│ ├── extras/ — Cross-cutting features (custom fields, tags, webhooks, scripts)
│ ├── ipam/ — IP address management (prefixes, addresses, VLANs, etc.)
│ ├── tenancy/ — Tenancy and organization
│ ├── users/ — User management and tokens
│ ├── utilities/ — Shared utilities (no models)
│ ├── virtualization/ — Virtual machines and clusters
│ ├── vpn/ — VPN tunnels and configurations
│ ├── wireless/ — Wireless LANs and links
│ ├── templates/ — Django templates (per-app subdirectories)
│ ├── static/ — Compiled static assets
│ ├── project-static/ — Source static assets
│ ├── media/ — User-uploaded media
│ └── translations/ — i18n translation files
├── docs/ — MkDocs documentation source
│ ├── administration/
│ ├── configuration/
│ ├── customization/
│ ├── development/ — Contributing guide, code style
│ ├── features/
│ ├── getting-started/
│ ├── installation/
│ ├── integrations/
│ ├── models/ — Per-model documentation (by app)
│ ├── plugins/
│ ├── reference/
│ └── release-notes/
├── scripts/ — Database management and verification scripts
├── contrib/ — Example configs (systemd, nginx, generated schemas)
├── pyproject.toml — Project metadata, ruff config
├── requirements.txt — Python dependencies
└── mkdocs.yml — Docs site configuration
Each Django app (account, circuits, core, dcim, extras, ipam, tenancy, users, virtualization, vpn, wireless) follows a standard layout:
<app>/
├── __init__.py
├── models/ — Database models (or models.py for smaller apps)
├── migrations/ — Database migrations
├── api/
│ ├── serializers.py
│ ├── views.py — DRF viewsets
│ └── urls.py — NetBoxRouter registrations
├── forms/ — Django forms (model forms, filter forms, bulk edit, etc.)
├── tables/ — django-tables2 table definitions
├── graphql/
│ └── types.py — Strawberry GraphQL types
├── filtersets.py — django-filter FilterSets
├── choices.py — ChoiceSet subclasses
├── views.py — UI views (registered with register_model_view())
├── urls.py — URL routing
├── search.py — SearchIndex registrations
├── signals.py — Django signal definitions (where applicable)
└── tests/
├── test_api.py
├── test_filtersets.py
├── test_models.py
├── test_views.py
└── test_forms.py
Use register_model_view() to register model views by action (e.g. "add", "list", etc.). List views typically don't need to add select_related() or prefetch_related() on their querysets — prefetching is handled dynamically by the table class so that only relevant fields are prefetched.
DRF serializers live in <app>/api/serializers.py; viewsets in <app>/api/views.py; URLs auto-registered in <app>/api/urls.py. NetBoxModelSerializer provides standard fields including url, display, tags, and custom_fields. drf-spectacular generates the OpenAPI schema automatically. REST API views typically don't need to add select_related() or prefetch_related() — prefetching is handled dynamically by the serializer.
Strawberry types live in <app>/graphql/types.py. The core GraphQL schema is assembled in netbox/netbox/graphql/. Use Strawberry's @strawberry.type and auto field resolution, following the patterns in existing apps.
django-rq drives background task processing. Job classes live in core/jobs.py and app-specific jobs.py files. Use JobRunner subclasses (from netbox.jobs) for all background work. The core app exposes job status in the UI.
Plugin infrastructure lives in netbox/netbox/plugins/. Plugins are Django apps registered in PLUGINS (configuration.py). The plugin API exposes stable extension points: custom models, views, navigation, template extensions, search indexes, object actions, and event rules. Internal NetBox APIs are subject to change without notice.
FilterSets live in <app>/filtersets.py, using NetBoxModelFilterSet as the base. Used for both UI filtering and API ?field= params. FK filters must declare an explicit <field>_id = ModelMultipleChoiceFilter(field_name='<field>', ...) — don't rely on Meta.fields to auto-generate _id variants.
extras is a catch-all for cross-cutting features: custom fields, custom links, tags, webhooks/event rules, export templates, config contexts, saved filters, bookmarks, notifications, scripts, and reports. New cross-cutting features belong here. Use FeatureQuery for generic relations (config contexts, custom fields, tags, etc.).
All commands run from the netbox/ subdirectory with the venv active. There is no Makefile or Justfile; use raw commands.
| Command | What it does |
|---|---|
python manage.py runserver |
Start development server |
python manage.py test |
Run full test suite (set NETBOX_CONFIGURATION first — see Testing) |
python manage.py test --keepdb --parallel 4 |
Faster test run (no DB rebuild, parallel) |
python manage.py test dcim.tests.test_api |
Run a single test module |
python manage.py makemigrations |
Generate migrations after model changes |
python manage.py migrate |
Apply migrations |
python manage.py nbshell |
NetBox-enhanced interactive shell |
python manage.py collectstatic |
Collect static assets |
ruff check |
Lint (run from repo root) |
mkdocs serve |
Preview documentation |
mkdocs build |
Build static docs site |
python -m venv ~/.venv/netbox
source ~/.venv/netbox/bin/activate
pip install -r requirements.txt
# Copy and configure
cp netbox/netbox/configuration.example.py netbox/netbox/configuration.py
# Edit configuration.py: set DATABASE, REDIS, SECRET_KEY, ALLOWED_HOSTS
cd netbox/
python manage.py migrate
python manage.py runserver
Requires PostgreSQL and Redis on localhost at their default ports.
Tests use django.test.TestCase (not pytest). Test modules mirror the app structure in <app>/tests/. Always set the NETBOX_CONFIGURATION environment variable before running tests:
export NETBOX_CONFIGURATION=netbox.configuration_testing
python manage.py test
# Faster runs
python manage.py test --keepdb --parallel 4
# Single module
python manage.py test dcim.tests.test_api
Standard test modules per app:
| Module | Coverage area |
|---|---|
test_api.py |
REST API endpoints (CRUD, filtering, bulk operations) |
test_filtersets.py |
FilterSet fields and query behavior |
test_models.py |
Model methods, validation, constraints |
test_views.py |
UI views (list, create, edit, delete, bulk actions) |
test_forms.py |
Form validation |
test_tables.py |
Table column rendering |
Additional specialized test modules exist in some apps (e.g., test_cablepaths.py in dcim, test_lookups.py in ipam).
GitHub Actions workflows in .github/workflows/:
ci.yml — Main CI pipeline: runs on every PR. Executes linting (ruff) and the full test suite across the supported Python version matrix.codeql.yml — CodeQL security scanning.claude.yml — Claude Code automation hook; triggers on issue/PR comments mentioning @claude.claude-issue-triage.yml — Automated issue triage via Claude AI.close-stale-issues.yml / close-incomplete-issues.yml — Issue hygiene automation.lock-threads.yml — Locks closed issue/PR threads after a period.update-translation-strings.yml — Extracts and updates i18n translation strings.models/ directory (or create a new module imported from models/__init__.py). Inherit from NetBoxModel for full feature support (custom fields, tags, etc.).python manage.py makemigrations — never write migrations manually.filtersets.py), forms (forms/), table (tables/), serializer (api/serializers.py), viewset (api/views.py), URL routes (api/urls.py, urls.py), UI views (views.py), navigation, and a template under templates/<app>/.SearchIndex in search.py if the model should appear in global search.api/serializers.py using NetBoxModelSerializer for NetBoxModel-based models. Include a url field.api/views.py. For custom actions use @action(detail=True, methods=['post']).api/urls.py via NetBoxRouter.FilterSet exists in filtersets.py; add explicit <field>_id = ModelMultipleChoiceFilter(field_name='<field>', ...) for FK filters.tests/test_api.py.<app>/graphql/types.py, inheriting from the appropriate base (see existing types for examples).auto fields and lazy-resolve relations.<app>/filtersets.py. Use NetBoxModelFilterSet as the base.<field> (name/slug lookup) and <field>_id (ID lookup) as explicit ModelMultipleChoiceFilter entries.forms/filtersets.py to expose the field in the UI.tests/test_filtersets.py.version in pyproject.toml.docs/release-notes/.register_model_view(). List views don't need manual select_related()/prefetch_related() — the table handles it.select_related()/prefetch_related() — handled dynamically.NetBoxModel; include created and last_updated fields.url field (absolute URL of the object).FeatureQuery for config contexts, custom fields, tags, etc.<field>_id variants in FilterSets; don't rely on Meta.fields.manage.py makemigrations.ruff format on existing files — tends to introduce unnecessary style changes.pyproject.toml. Line length 120, single quotes. Enabled rules: E/W/F/I/RET/UP/RUF022. Ignored: F403, F405, RET504, UP032.extras app.<issue-number>-short-description (e.g., 1234-device-typerror)main branch for patch releases; feature tracks work for the upcoming minor/major release.manage.py — manage.py lives in netbox/, not the repo root. Always cd netbox/ first or use the full path.NETBOX_CONFIGURATION=netbox.configuration_testing for tests.configuration.py not found — Copy configuration.example.py to configuration.py and fill in DATABASE, REDIS, SECRET_KEY, ALLOWED_HOSTS. This file is gitignored and must never be committed.python manage.py makemigrations and let Django generate them.configuration.py is gitignored — never commit it.manage.py lives in netbox/, NOT the repo root. Running from the wrong directory is a common mistake.NETBOX_CONFIGURATION env var controls which settings module loads; set to netbox.configuration_testing for tests.extras app is a catch-all for cross-cutting features (custom fields, tags, webhooks, scripts).docs/development/ for the full contributing guide and code style details.docs/docs/development/docs/release-notes/docs/plugins/