Context

Context is the data that pages and components publish into their template scope. This page covers the two shapes of the @context decorator and the ways to vary them. It also walks inheritance down the route tree, how component context differs from page context, and how to expose values to the JavaScript bundle. A final section covers how to swap out the serializer that ships values to the browser.

This page is the concept reference for context. Once you understand the decorator and the serialize flag here, JavaScript Context covers the full window.Next.context mechanics. The Override the JS Context Serializer how-to walks through replacing the serializer.

Overview

A context function is a Python callable that returns a value. The framework calls it at request time, resolves its parameters through the dependency injector, and publishes the result under a key that the template can render.

Two call sites share the same decorator surface.

Page context.

@context("key") in a page.py. Resolves once for that page request. Add inherit_context=True to publish the value to every descendant route.

Component context.

@component.context("key") in a component.py. Resolves once per component instance during render.

Framework-Provided Keys

Every page render starts with three keys already populated, before any user-defined @context callable runs.

request.

The active HttpRequest, when the route was reached through the HTTP stack.

current_template_path.

The absolute path of the body source on disk. It points at the sibling template.djx when one exists, or at the page.py itself when the body comes from render or template.

current_page_module_path.

The absolute path of the page.py module being rendered.

User @context callables can read these keys by parameter name, and template-side machinery such as the {% component %} and {% form %} tags relies on them.

The Decorator

The page-side @context decorator has two shapes. One is a keyed single value, the other is an unkeyed dict. The inherit_context flag and direct registration, covered after the two shapes, vary how a function is registered.

Keyed Single Value

The most common shape. The decorator takes a single key and the function returns the value.

notes/pages/page.py
from notes.models import Note
from next.pages import context

@context("notes")
def recent_notes() -> list[Note]:
    return list(Note.objects.all())

Templates reference the value as {{ notes }}.

Unkeyed Dict

Decorating a function with bare @context and returning a dict merges every key into the template scope.

shared dependency
from next.pages import context

@context
def post_context(post: Post) -> dict[str, object]:
    return {
        "post": post,
        "comments": list(post.comment_set.all()),
    }

This shape runs the dependency once. Two separate @context("post") and @context("comments") would each hit the resolver and possibly the database twice.

The inherit_context Flag

inherit_context=True makes a keyed value visible to every descendant route, not only to the page that declares it.

notes/pages/page.py
from next.pages import context

@context("site_name", inherit_context=True)
def site_name() -> str:
    return "Notes"

Use this for header copy, brand colors, feature flags, and other shared values. Without the flag the value is only available when that exact page.py handles the request, and descendant routes cannot read it.

Direct Registration

Treat context("key") as a callable that registers an existing function.

registering an external function
from notes.cache import pending_clicks
from next.pages import context

context("pending_clicks")(pending_clicks)

This is useful when the function lives in a shared module and you want to register it without a decorator on the original source.

Reading Values Into a Context Function

A context function receives its parameters through the dependency injector. Three forms pull a value out of the surrounding context, and they differ only in how explicit the source is.

Plain parameter name.

Declare a parameter whose name matches a context key and the value is injected with no marker. def greeting(user_name): ... receives the user_name context value. This terse form implies the source from the parameter name.

Context(...) default.

Context() reads the parameter name from the context, exactly like the plain form. Context("user_name") reads a named key when the parameter name differs from the key. Context("user_name", default=...) supplies a fallback when the key is absent. Context(callable) calls a factory with its own DI-resolved arguments, and Context(value) injects a constant. Use Context when the source differs from the parameter name, when you need a default, or when you want the source visible at the call site.

The Context(callable) form is useful when a parameter needs a value computed from a factory rather than a context key. The factory takes its own dependency-injected arguments, so it can ask for the request, captured URL parameters, any registered provider, and the active form when one is bound.

notes/pages/notes/[int:note_id]/page.py
from notes.models import Note
from next.pages import Context, context
from next.urls import DUrl

def load_note(note_id: DUrl[int]) -> Note:
    return Note.objects.get(pk=note_id)

@context("word_count")
def word_count(note: Note = Context(load_note)) -> int:
    return len(note.body.split())

The framework resolves load_note with its own note_id argument from the URL, then passes the resulting Note into word_count as the note parameter.

Depends(...) default.

Reads a callable registered through next.deps.resolver.dependency rather than the request context. Use it for values produced by shared dependency callables. See Dependency Injection.

Resolution Order

The framework computes the template scope in this order.

  1. URL kwargs from the matched route are seeded into the context dict.

  2. Inherited context functions from every ancestor page.py, walked from the route root inward.

  3. Page level context functions declared in the current page.py.

  4. Context processors run after every @context callable. The first source is OPTIONS.context_processors on each page backend entry inside DEFAULT_PAGE_BACKENDS. The second source is the context_processors list of the first TEMPLATES entry in Django settings. See Settings and Project Layout for the backend layout. The two lists merge in that order with duplicate dotted paths dropped, so a processor listed twice runs once. Each processor return dict is applied with update, so a processor key overwrites a page or inherited value.

  5. Component context functions when a {% component %} tag is encountered during render.

A later step that uses the same key overrides earlier values. The full merged dict is shared across the entire layout.djx chain for that request, so all layout wrappers see the same final scope. The Layouts page restates this from the layout side under Context Processors.

Inheritance Rules

Inherited context follows the filesystem route tree. The framework walks up from the current page.py directory and runs every @context callable marked inherit_context=True that it finds in ancestor page.py files.

  • A page.py at notes/pages/ publishes inherited values for every page under that root.

  • A page.py at notes/pages/admin/ publishes inherited values only for pages under /admin/.

  • A page at /admin/links/ sees both layers because it sits below both directories.

The current page can shadow an inherited value by declaring a context function with the same key. The page level value takes precedence, and every layout wrapper in the chain sees that value.

Inherited Function That Names a URL Parameter

When an inherited context function is keyed under the same name as a captured URL segment, the parameter it asks for changes type across runs. On the first run it holds the raw URL string. On a descendant re-run it holds the resolved object the function already produced. Leave the parameter untyped and return early if it is already an instance of the model.

notes/pages/notes/[category]/page.py
from notes.models import Category
from next.pages import context

@context("category", inherit_context=True)
def category(category: object) -> Category:
    if isinstance(category, Category):
        return category
    return Category.objects.get(slug=category)

Declaring the parameter as str would break the descendant re-run.

Serialization for the Browser

next.dj ships a window.Next object to the browser through the static pipeline. Pass serialize=True on @context or @component.context to publish the return value under window.Next.context. Pass serializer= on that decorator for a per-key encoder, or set NEXT_FRAMEWORK["JS_CONTEXT_SERIALIZER"] for a project-wide default.

A value marked serialize=True must be encodable by the active serializer. The default JsonJsContextSerializer runs values through Django DjangoJSONEncoder. That encoder handles primitives, list, dict, datetime, date, time, timedelta, Decimal, UUID, and Django Promise instances such as lazy translation strings. Switching JS_CONTEXT_SERIALIZER to PydanticJsContextSerializer also unwraps pydantic.BaseModel subclasses via model_dump. A QuerySet, a Manager, a bare model instance, a Django Form, and any other unsupported type raises TypeError at render time with the offending key in the message. Materialise such values before returning. Use list(queryset) for collections and a plain dict projection for model instances.

Values not marked serialize=True stay server-side only. Template rendering iterates a queryset or resolves a lazy string directly. The materialisation rule applies only to keys that travel to the client.

See JavaScript Context for serializers, duplicate-key policies, NEXT_JS_OPTIONS, and reading values from co-located JS. See Override the JS Context Serializer for a guided recipe when the default JSON encoder is not enough.

Component Context vs Page Context

Component context and page context share the same decorator pattern but differ in scope.

Page context.

Resolves once per request for the page.py module that defines it. Use inherit_context=True to make it available to every descendant route in the filesystem tree.

Component context.

Resolves once per component render. The framework forwards the surrounding template scope into the component automatically. The @component.context decorator accepts only serialize and serializer. There is no inherit_context flag, and component context never flows beyond the component that declares it.

A component context function can ask for any value that the template forwards, plus any value that the dependency injector knows how to produce. This includes the request, captured URL parameters, query strings, and custom providers.

Signal When Context Registers

The framework fires context_registered after a @context callable in a page.py joins the registry. Subscribe to it when an external system needs to track page context functions across reloads.

@component.context does not emit its own signal. Folder discovery registers components through register_many, which fires components_registered once per discovery batch with an infos tuple of ComponentInfo. The singular component_registered fires only on a one-at-a-time register call.

Common Patterns

Per Page Title

Publish the page title from each page.

notes/pages/notes/[id]/page.py
from notes.models import Note
from next.pages import context
from next.urls import DUrl

@context("page_title")
def page_title(note_id: DUrl[int]) -> str:
    return Note.objects.get(pk=note_id).title

Render it in the layout.

layout
<title>{{ page_title|default:"Notes" }}</title>

Site Wide Configuration

Publish branding and navigation from the root page.py with inherit_context=True. Every page under that directory reads the values without redeclaring them.

Filter Values From Query String

Combine a context function with the DQuery[T] marker to read filters from the URL.

notes/pages/page.py
from next.pages import context
from next.urls import DQuery

@context("active_tag")
def active_tag(tag: DQuery[str] = "") -> str:
    return tag

Shared Dependency

When two context functions need the same expensive value, factor the dependency into a custom DI provider or use the unkeyed dict shape.

System Checks

The framework validates context functions through check_context_functions. A keyless @context callable with a non-dict return annotation reports next.E029 during uv run python manage.py check. A keyless callable with no return annotation is accepted by the check and raises TypeError at render time if the value is not a mapping. Functions decorated with a key may return any value.

See Also

See also

Pages for page level context. Layouts for layout composition rules. Dependency Injection for the resolver and providers. JavaScript Context for the browser side Next object. Decorators and Markers for the page-side @context API. Components Reference for the @component.context API.