Contributor notes#
This page collects the conventions that the framework code itself follows. It covers module layout, naming rules, and the invariants each subsystem must preserve. Read it before sending a patch that touches the core packages.
Note
This page targets framework contributors editing next/.
Documentation authoring rules live under Contributing.
Contribution workflow (tooling, CI, benchmarks, PR checklist) lives in CONTRIBUTING.md.
A patch passes through a fixed set of gates before it merges.
flowchart LR
lint[Lint] --> types[Types]
types --> tests[Tests]
tests --> checks[System checks]
checks --> pr[Pull request]
Conventions#
Module layout#
Each subsystem keeps a flat layout where every submodule is small.
A new submodule joins __init__.py only when its public surface needs a shorter import path.
Annotations#
Modules that participate in dependency resolution never use from __future__ import annotations.
This applies to page.py, component.py, providers.py, every action handler, and every get_initial callable.
The DI resolver inspects real annotations, not strings, and typing.get_origin returns None on stringified generics.
Public callables#
Names exposed through @page.context, @component.context, @action, and through provider classes never start with an underscore.
@context imported from next is the documented alias for @page.context used in page modules.
Names prefixed with _ stay module internal.
System checks#
Every check lives next to the subsystem it validates.
The codes follow next.E<NNN> for errors and next.W<NNN> for warnings.
A new check registers through next.checks.register_all.
Signals#
Every signal lives in a signals submodule of its subsystem.
The aggregator next.signals re-exports each name.
A new signal adds an entry to the aggregator and to the topic catalog in docs/content/topics/signals.rst.
Module docstrings#
Test modules carry no module-level docstring. Every production module opens with a one-line summary at the top.
Imports#
Every import lives at the top of the module.
Imports inside functions or methods are not used, including inside tests.
Docstrings#
A docstring is one summary line, or at most a short paragraph. Examples, enumerations, and historical notes belong in the guide documentation, not in docstrings.
Prose punctuation#
The same punctuation rules that bind the documentation also bind every docstring, comment, and log message in next/.
No semicolon joins two clauses.
No em or en dash separates one statement from the next.
The full rule set lives in Documentation style guide.
Decorative separators#
CSS, JavaScript, and Jinja files in docs/_static and docs/_templates carry no decorative /* ---- section ---- */ banners.
A comment explains a non-obvious choice and nothing else.
Testing the framework#
The repository ships its own pytest suite plus a per example suite under examples/.
uv run pytest
uv run pytest examples/admin
uv run python examples/admin/manage.py check
The system checks run through an example project because the framework itself ships no manage.py.
Always run the framework suite and the system checks before opening a pull request.
Documentation tests#
When introducing or removing a public API, update the import-presence coverage in tests/test_public_api.py or the matching area suite so an accidental removal fails CI.
Code style#
The project uses ruff for linting and mypy for static type checks.
Run both before submitting.
uv run ruff check
uv run mypy
See also#
See also
CONTRIBUTING.md for the full contribution workflow (setup, testing, benchmarks, PRs). Writing documentation for the documentation rules.