Search documentation

Find a page in the Andurel docs.

Pages and Visits

Every Inertia screen is one Renderer.Page call. The renderer decides whether to return the Templ root document or a JSON page object from the incoming headers. Controllers do not branch on X-Inertia themselves.

Page builder

 1func (c Products) Index(etx *echo.Context) error {
 2    products, err := c.products.List(etx.Request().Context())
 3    if err != nil {
 4        return err
 5    }
 6
 7    return c.renderer.Page(etx, "Products/Index", inertia.Props{
 8        "products": toProductResources(products),
 9    }).Render()
10}

Page returns a *PageBuilder. Chain options, then call Render:

Method Effect
SSR() Opt this initial document into server-side rendering
Status(code) HTTP status, default 200
ValidationErrors(map[string]string) Protected props.errors, with named bags when requested
HistoryEncryption(bool) Sets encryptHistory metadata; the client encrypts history
HistoryClear() Sets clearHistory
PreserveFragment() Sets preserveFragment across a redirect
Flash(value) Sets the top-level flash field for this response

Render resolves shared props, evaluates page props against the current request, encodes the v3 page object, and writes either JSON or HTML.

Component names are adapter paths, not Go types. Generated React pages live at resources/js/Pages/Products/Index.tsx and resolve from:

1import.meta.glob('./Pages/**/*.tsx', { eager: true })

The string "Products/Index" must match that file. A missing module fails in the browser, not at Go compile time. Treat the component name as part of the HTTP contract.

Initial and client visits

ParseRequest recognizes an Inertia visit only when X-Inertia is true.

An initial visit has no Inertia header. Render writes views.Root with:

  • validated page JSON in PageScript
  • an empty mount node from AppMount
  • Vite tags in RootData.ViteHead and ViteBody
  • SSR markup instead of the script and mount when .SSR() succeeds

A client visit receives application/json with X-Inertia: true. The official adapter swaps the page component. Both responses append X-Inertia to Vary without replacing existing values.

The JSON page always includes:

1{
2  "component": "Products/Index",
3  "props": { "errors": {} },
4  "url": "/products",
5  "version": "/assets/dist/vite/*"
6}

url is the request URI, including query string. Empty conditional fields are omitted: merge lists, deferred groups, once metadata, scroll metadata, history flags, and flash.

Error pages are ordinary pages with a non-200 status:

1return c.renderer.Page(etx, "Errors/NotFound", inertia.Props{}).
2    Status(http.StatusNotFound).
3    Render()

Request headers

The middleware parses this state once per request:

Header Field Meaning
X-Inertia Inertia Client visit when true
X-Inertia-Version Version Asset version for GET mismatch reloads
X-Inertia-Partial-Component PartialComponent Component the only/except lists apply to
X-Inertia-Partial-Data Only Comma-separated paths to include
X-Inertia-Partial-Except Except Comma-separated paths to omit
X-Inertia-Reset Reset Merge paths to replace instead of merge
X-Inertia-Error-Bag ErrorBag Named bag for props.errors
X-Inertia-Infinite-Scroll-Merge-Intent MergeIntent append or prepend
X-Inertia-Except-Once-Props ExceptOnceProps Once keys the client still holds
Purpose Purpose prefetch disables fragment-redirect rewriting

Lists are trimmed, empty items discarded, and duplicates removed. An invalid merge intent is a protocol error.

Partial filtering applies only when PartialComponent equals the rendered component. A visit to Products/Show with partial data for Products/Index is a full evaluation. Nested paths match in both directions: selecting product keeps product.name; selecting product.name keeps the parent object structure. only is applied before except.

Prefetch and history

Request.IsPrefetch() is true when Purpose is prefetch. Prefetch visits still receive page JSON, but fragment redirects stay ordinary 3xx responses so the client can follow them without a control-response dance.

HistoryEncryption, HistoryClear, and PreserveFragment are metadata. The Go adapter does not encrypt browser history. Use them when the official client should encrypt, clear, or keep a URL fragment.

Application usage

Use one Page call for GET screens, validation redisplay, and error pages. After a successful write, prefer Redirect or Location instead of rendering the next page from the mutating request. See Shared Data and Redirects.

Keep payload construction next to the controller or in a small resource mapper. Generated scaffolds use inertia.FromStruct with ProductIndexProps / ProductItemProps. Hand-written pages can use inertia.Props or FromStruct; both JSON-encode the same way.

1return c.renderer.Page(
2    etx,
3    "Products/Show",
4    inertia.FromStruct(ProductItemProps{Item: newProductData(product)}),
5).Render()

The first visit and later visits stay the same Go code. If a page needs SSR, add .SSR() to that builder only. See SSR.