---
title: 'navigator'
description: 'Two roles: the runtime-introspection surface (Baseline''s phpinfo()-style page for current build state), and the public read surface for plugin-produced cross-page data (the content graph and backlinks).'
slug: 'navigator'
type: 'article'
date: 2026-04-15T00:00:00.000Z
lang: 'en'
url: 'https://www.eleventy-baseline.dev/docs/module/navigator/'
---

`INTERNAL_KEY`: '\_navigator'

---

## What it does

The navigator module wears two hats. It is Baseline's runtime-introspection surface, and it is the public read surface for plugin-produced cross-page data.

As the **runtime-introspection surface**, the navigator gives every install a single page that dumps the current state of the build: Eleventy's render context (the values Nunjucks has in scope), Baseline's runtime stores, the resolved options, the page-context registry. The mental model is closer to PHP's `phpinfo()` than to a stack-trace overlay; you visit `/navigator-core.html` to answer "what is actually configured right now?" without pausing the build or wiring a debugger.

The supporting tools are two Nunjucks globals (`_runtime`, `_ctx`), three filters (`_inspect`, `_json`, `_keys`), a computed `_snapshot` of Baseline's runtime state, and the virtual page itself (a synthetic template Baseline injects into the build, not a file you write) at `/navigator-core.html`. The same tools work in any template you author, so you can drop targeted inspection into a layout without enabling the virtual page.

As the **public read surface**, it registers the `_navigator` Nunjucks global with shape `{ nodes, edges, backlinks }`. `nodes` is the per-URL map from the content graph; `edges` is a flat array of every link in the graph; `backlinks` is the target-keyed enriched backlinks map.

Authors paginate over `_navigator.backlinks` to generate "what links here" subpages, or read `_navigator.nodes` and `_navigator.edges` for cross-page features (related-page lists, navigation indices, link audits). The per-page view of the same substrate is on `data._node`, `data._backlinks`, and `data._outgoing`; see [[globals | Globals]].

{% alertBlock "warning" %}

`_runtime` and `_ctx` dump the full render context and may include secrets from your data layer or environment. Only use them in local development or secured environments.

{% endalertBlock %}

---

### Active when

Always. The module loads unconditionally, so `_navigator`, `_runtime`, `_ctx`, the debug filters, and the computed `_snapshot` are available on every build. The `navigator` option governs the virtual page only:

- `navigator: true` (the default when `ELEVENTY_ENV=development`): virtual page enabled.
- `navigator: false` (the default otherwise): virtual page suppressed. Globals and filters still register.
- `navigator: { template, inspectorDepth }`: virtual page enabled when `template` is truthy, inspector depth tuned by `inspectorDepth`.

---

### Lifecycle

- **Build-time.** Registers the Nunjucks globals, the debug filters, the computed `_snapshot`, and (when enabled) the virtual page at `/navigator-core.html`.
- **Cascade-time.** `_snapshot` resolves on every page; its `contentMap` and `pageContext` fields are read from the runtime stores.

---

## How it works

1. **Resolve options.** The module reads `options.navigator` from state. Boolean shorthand activates the virtual page; object form unwraps to `{ template, inspectorDepth }`.
2. **Register `_snapshot`.** Added as `eleventyComputed._snapshot`. Resolves per page from the runtime stores.
3. **Register `_navigator`.** Added as a global thunk reading `{ nodes, edges, backlinks }` from `runtime.contentGraph`. Empty objects (or array) when the graph is unavailable, so templates can read it without guarding.
4. **Register debug globals.** `_runtime` and `_ctx` are added as Nunjucks globals.
5. **Register debug filters.** `_inspect`, `_json`, `_keys`.
6. **Register the virtual page (when enabled).** A bundled HTML template is read from disk and registered with `permalink: '/navigator-core.html'`, excluded from collections.

---

## Defaults

- **Virtual page.** On in development (`ELEVENTY_ENV=development`), off otherwise.
- **Inspector depth.** `4`. Controls how deep `_inspect` renders nested objects on the virtual page.
- **Globals.** Always registered when the module is loaded.

---

### Options

{% tableBlock true %}

| Option      | Type                                                         | Default       | Meaning                                                                                                                                                               |
| ----------- | ------------------------------------------------------------ | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `navigator` | `boolean \| { template?: boolean, inspectorDepth?: number }` | `true` in dev | `true` activates the virtual page; `false` skips it. Object form lets you set `template` and `inspectorDepth` independently: `{ template: true, inspectorDepth: 6 }`. |

{% endtableBlock %}

---

## Globals

Three Nunjucks globals, available in any template once the module is loaded.

- **`_navigator`** returns `{ nodes, edges, backlinks }`, the cross-page read surface for plugin-produced data:
  - `nodes`: the per-URL map from the content graph. Each entry merges identity fields (`title`, `slug`, `description`, `lang`, `locale`, `date`, `url`, `breadcrumbs`) with extracted fields (`excerpt`, `headings`, `sections`, `images`).
  - `edges`: a flat array of every link in the graph, shape `{ internal, from, to, text, rel }`. One edge per anchor in each page's extracted root.
  - `backlinks`: the target-keyed enriched backlinks map, `{ targetUrl: Array<{ url, title?, excerpt? }> }`. Pre-joined with source title and excerpt.
  - Use it to paginate over backlinks for "what links here" subpages, or to walk `nodes` and `edges` for related-page lists and link audits.
- **`_runtime()`** returns `{ env, ctx, globals }`:
  - `env`: the Nunjucks environment instance (filters, globals, configured engines).
  - `ctx`: the current render context (the values in scope at this point in the template, including `page`, `eleventy`, your data cascade).
  - `globals`: registered Nunjucks globals.
- **`_ctx()`** returns the render context directly (the same `ctx` object as `_runtime().ctx`). A shortcut for the common case.

`_runtime` and `_ctx` are functions, called with `()`. `_navigator` is a plain object.

### Computed `_snapshot`

Every page receives a computed `_snapshot` with two fields, read from Baseline's runtime stores:

- **`contentMap`**: the inputPath ↔ url lookup Baseline builds during the cascade. Used by the head module for canonical resolution.
- **`pageContext`**: the page-context registry's snapshot, keyed by URL. The same per-page context the head module reads at transform-time. See [[page-context | Page context]].

`_snapshot.contentMap` is `null` on the navigator template itself, because the template renders before Eleventy's `eleventy.contentMap` event fires. Read `_snapshot` from any ordinary page to see a populated `contentMap`.

---

## Debug filters

Three filters registered alongside the globals. Full reference on [[filters | Filters]].

- `_inspect(value, opts)`: pretty-prints any value with configurable depth.
- `_json(value)`: stringifies as JSON.
- `_keys(value)`: returns the top-level keys of an object.

---

## The virtual page

When the virtual page is enabled, Baseline registers a synthetic template that lives at `/navigator-core.html`. The template iterates over `_runtime()` and renders each key with `_inspect` at the configured depth.

{% alertBlock %}

See the navigator template [in action](/navigator-core.html).

{% endalertBlock %}

Note on the URL: the path still ends in `-core.html`. That is the historical filename of the bundled template. The user-facing module name is `navigator`; the URL path may be aligned in a future release.

You do not need the virtual page to use the module. The globals and the computed `_snapshot` work on any template you author.

---

## Tips

- Tune the depth for the virtual page with the object form: `baseline(settings, { navigator: { template: true, inspectorDepth: 4 } })`. The boolean shorthand keeps the default depth of 4.
- Pair `_ctx()` with `_inspect` on any page for targeted debugging. You do not need the virtual page for that.
- The virtual page renders a large snapshot. Keep it off in production. The default already does, but check your environment if it shows up unexpectedly.
- `_snapshot.contentMap` being `null` is not a bug; it is the lifecycle (the navigator template renders before the content map is ready). Read `_snapshot` from any ordinary page to see it populated.

---

### Example: inspect on any page

You can drop this in any layout or page to render a quick snapshot:

{% raw %}

```nunjucks
{% for key, value in _runtime() %}
	<details>
		<summary><strong>{{ key }}</strong></summary>
		{% if value | isString %}
			<pre>{{ value | safe }}</pre>
		{% else %}
			<pre>{{ value | _inspect({ depth: 2 }) }}</pre>
		{% endif %}
	</details>
{% endfor %}
```

{% endraw %}

---

## Peer deps

None.

---

## See also

- [[globals | Globals]] for `_runtime`, `_ctx`, and `_snapshot` field shapes.
- [[filters | Filters]] for `_inspect`, `_json`, `_keys`.
- [[page-context | Page context]] for what `_snapshot.pageContext` contains.
- [[internals | Internals]] for the runtime stores `_snapshot` reads.
- The other modules, all introspectable through `_snapshot` and `_runtime`: [[assets]], [[head]], [[multilang]], [[sitemap]].
- [[debugging-navigator | Tutorial: debugging the navigator]]
