View Source Changelog

3.0.0-rc3 - 2026-05-30

Added

  • First-party pagination support for inertia_scroll/2. Pass a Scrivener.Page struct or a Flop {records, %Flop.Meta{}} tuple directly and the entries are placed under the :wrapper key (default "data") with pagination metadata extracted automatically. Extensible to other libraries via the Inertia.Paginated protocol, whose to_scroll/1 returns a metadata map that optionally carries the page's :entries. Also adds a :transform option for serializing each entry before it is rendered, and a :meta option (a function whose returned map is placed under a "meta" key in the prop, alongside the entries) for surfacing extra pagination data to the page.
  • Add a :csp_nonce_assign_key config option. When set, the library reads a Content-Security-Policy nonce from the given connection assign and applies it to the <script> tag used to bootstrap the page data.
  • The :match_on option on inertia_merge/2, inertia_prepend/2, and inertia_deep_merge/2 now accepts a list of keys (in addition to a single key) for matching on multiple fields, producing one matchPropsOn entry per key.
  • Add an on_error: :ignore option to inertia_defer/2,3 for graceful failure of deferred props. When a rescued deferred prop's resolver fails during a partial reload, the prop is omitted, its path is reported in the rescuedProps page metadata, and the failure is logged and emitted as a [:inertia, :deferred_prop, :rescue] telemetry event (#75).

Changed

  • (Breaking) inertia_scroll/2 now always shapes the prop value as %{<wrapper> => entries}. Previously a %{data:, meta:} map was passed through verbatim; now only the entries under the wrapper key are kept, and any other top-level keys (including meta and any sibling fields like total_count) are dropped from the prop. Pagination metadata is surfaced via scrollProps instead — read pagination state from there.
  • (Breaking) Renamed the inertia_scroll/2 :metadata option (added in 2.6.0) to :scroll_metadata, to distinguish it from the new :meta option (which adds display data to the prop value). :scroll_metadata still produces the scrollProps the client component uses.
  • (Breaking) ecto is now an optional dependency. The Ecto.Changeset error serializer is only available when Ecto is present. Apps that pass changesets to assign_errors and don't already depend on Ecto should add {:ecto, "~> 3.10"} (most Phoenix apps already do). Bare error maps work without Ecto.
  • (Breaking) nodejs is now an optional dependency. It's only needed by the default Node.js SSR adapter, so apps using SSR with the default adapter should add {:nodejs, "~> 3.0"}. Apps that don't use SSR (or use a custom :ssr_adapter) no longer pull it in.
  • (Breaking) Raised minimum versions: Elixir >= 1.15.0 and phoenix_html ~> 4.0.

Removed

  • (Breaking) Removed the Inertia.ScrollMetadata protocol (added in 2.6.0). Pagination extensibility is now provided by the single Inertia.Paginated protocol — implement to_scroll/1 (which returns a metadata map, optionally carrying :entries) instead of to_scroll_metadata/1.

Fixed

  • Emit matchPropsOn as a list of "path.field" strings (e.g. ["users.id"]) instead of a %{path => field} map. The Inertia.js client expects an array and calls Array.prototype.find on it, so the previous map shape caused a client-side error when merging props with a match_on key.

3.0.0-rc2 - 2026-05-27

Added

  • Add a pluggable SSR adapter system. Server-side rendering is now performed through an Inertia.SSR.Adapter behaviour, so you can plug in an alternative JavaScript runtime (Bun, a Vite dev server, etc.) in place of the default Node.js process pool by passing a module via the :ssr_adapter option to Inertia.SSR. The default Inertia.SSR.NodeJSAdapter preserves the existing behavior (#44).
  • Add an :esm option to Inertia.SSR for using an ECMAScript Module SSR entrypoint. ESM is also auto-detected from a .mjs module extension (#44).
  • The inertia.install task now produces a complete, buildable setup for Svelte and Vue, not just React. Because Svelte and Vue single-file components must be compiled by an esbuild plugin — which the esbuild Hex package's CLI can't load — the installer drives esbuild from Node (assets/esbuild.config.js) via esbuild-svelte / unplugin-vue, generates the framework's Inertia entry point, and installs the client packages.
  • inertia.install now scaffolds a starter page (Home.jsx / Home.vue / Home.svelte) in place of an empty .gitkeep, so mix assets.build succeeds immediately after install.
  • Add step-by-step front-end setup guides for React, Svelte, and Vue, each covering both client-side and server-side rendering with esbuild and backed by runnable example apps under examples/.

Changed

  • The inertia.install task's React setup now adds npm install to the assets.setup alias, so client dependencies are restored on a fresh checkout or CI build.
  • The README no longer centers its client-side and SSR instructions on React. Framework-specific setup (including SSR) now lives in the per-framework guides, while the README covers the shared, framework-agnostic pieces.

Fixed

  • The root layout generated by inertia.install now loads the JS bundle from /assets/js/app.js, matching esbuild's output directory (previously /assets/app.js, which did not exist).

3.0.0-rc1 - 2026-05-18

Added

  • Add nested prop type support with a single recursive resolver. Prop type wrappers (inertia_defer, inertia_merge, inertia_deep_merge, inertia_optional, inertia_once, inertia_scroll) now work at any nesting depth, including inside closures. For example, inertia_defer inside a closure now correctly generates deferredProps metadata with dot-notation paths (e.g., auth.permissions).
  • Add assign_shared_prop/3 and inertia_share/1 to mark props as shared, exposing their keys in the sharedProps page metadata for the Inertia v3 protocol (#69).
  • Add preserve_fragment/1 and preserve_fragment/2 functions to instruct the client-side to preserve the URL fragment across server-side redirects (#68).
  • Add inertia_prepend/1 and inertia_prepend/2 for prepending (instead of appending) data during client-side merges. Prepend props appear in both mergeProps and prependProps in the page response. Scroll props also respect the X-Inertia-Infinite-Scroll-Merge-Intent: prepend header (#67).
  • Add match_on: option to inertia_merge/2, inertia_prepend/2, and inertia_deep_merge/2 for client-side deduplication of merged items. Match keys are included in matchPropsOn page metadata (#67).
  • Add ssr_exclude_paths config option to disable SSR for specific paths. Supports string prefixes and ~r// regex patterns (#67).
  • Add inertia_flash/1, inertia_page/1, inertia_deferred_props/1, inertia_merge_props/1, inertia_scroll_props/1, and inertia_once_props/1 test helpers in Inertia.Testing (#67).

Changed

  • Breaking: Flash data is now a top-level key in the Inertia page object (usePage().flash) instead of being nested inside props (usePage().props.flash). This aligns with the Inertia.js frontend conventions and the Laravel adapter (#67).
  • Breaking: The <title> tag marker attribute has been renamed from inertia to data-inertia. If you use the provided <.inertia_title> component, no action is required. If you render the title tag yourself in a custom root layout, update the marker attribute.
  • Breaking: The initial page payload is now rendered as a <script type="application/json"> tag instead of a data-page attribute on the container <div>. This matches the only mode supported by Inertia.js v3 (#66).
  • Set the Vary: X-Inertia response header on all requests (not just Inertia JSON responses), so HTTP caches can properly differentiate responses (#67).
  • Remove axios from the Igniter installer template, since Inertia.js v3 ships with a built-in HTTP client (#66).

Removed

  • Breaking: Remove inertia_lazy/1 (deprecated since v2.0.0). Use inertia_optional/1 instead (#66).

Fixed

  • Persist clearHistory across redirects via the session, matching the existing behavior of preserve_fragment. Previously, clear_history(conn) was lost on redirect (#67).
  • Handle redirects containing URL hash fragments by returning 409 with X-Inertia-Redirect header, so the client can perform a full navigation that preserves the fragment (#67).
  • Redirect Inertia requests that receive a 200 with an empty body back to the referer (or /), instead of rendering a blank page (#67).
  • Include "reset": true in scroll prop metadata when the scroll data path is in the X-Inertia-Reset header (#67).

2.6.2

Fixed

  • Fix CSR fallback crash when SSR returns non-string error (#73).

2.6.1

Fixed

  • Fix onSuccess not being called when errorBag is set and there are no validation errors (#72).

2.6.0

Added

  • Add inertia_scroll/2 function to support infinite scroll pagination. Automatically configures merge behavior and extracts pagination metadata for the client-side InfiniteScroll component. Includes Inertia.ScrollMetadata protocol for extensible pagination library support (#63).
  • Add inertia_once/2 function to support once props, which are cached on the client-side and reused across page navigations. Supports fresh, until, and as options for controlling refresh behavior, expiration, and custom keys (#62).
  • Create an assets/js/pages directory in the Igniter install task and fix the documentation (#57).

Fixed

  • Properly camelize keys in deferredProps metadata when camelize_props is enabled.

2.5.1

Fixed

  • Treat Igniter as an optional dependency in the mix inertia.install task definition. Previously, compilation would fail if Igniter was not installed.

2.5.0

Added

2.4.0

Added

  • Add inertia_errors/1 test helper to fetch Inertia errors (#43).

2.3.0

Added

  • Add a force_inertia_redirect plug function to instruct the client-side to always perform a full browser redirect when a redirect response is sent (#35).

Changed

2.2.0

Added

Fixed

  • Ensure prop keys are compared in the proper casing (for partial reloads) when camelize_props is enabled.
  • Fix prop resolution for deferred/optional props.

2.1.0

Fixed

  • Include new Inertia v2 attributes in the initial page object (mergeProps, deferredProps, encryptHistory, clearHistory).
  • Mark internal component functions in Inertia.HTML as private.

2.0.0

Added

  • Add support new Inertia.js v2.0.0.
    • Add encrypt_history function to instruct the client-side to encrypt the history entry.
    • Add clear_history function to instruct the client-side to clear history.
    • Add inertia_optional function, to replace the now-deprecated inertia_lazy function.
    • Add inertia_merge function to instruct the client-side to merge the prop value with existing data.
    • Add inertia_defer function to instruct the client-side to fetch the prop value immediately after initial page load.
  • Add helpers for testing Inertia-based controller responses via the Inertia.Testing module.
  • Add a camelize_props global config option and a camelize_props function (to use on a per-request basis) to automatically convert prop keys from snake case to camel case.
  • Accept an ssr option on the render_inertia function.

Changed

  • Update Phoenix LiveView to v1.0.
  • The errors serializer (for Ecto.Changeset structs) has been adjusted to better align with the behavior in the Laravel adapter in cases when there are multiple validation errors for a single field.

Old behavior for errors serializer

Previously, the serializer would include each error under a separate key, with a [0] index suffix, like this:

{
  "name[0]": "is too long",
  "name[1]": "is not real"
}

While this retains maximal information about all the errors for a field, in practice it's difficult to target the right error records for display in the UI.

New behavior for errors serializer

Now, the serializer simply takes the first error message and returns it under the field name, without any added suffix:

{
  "name": "is too long"
}

Fixed

  • Allow for external redirects from PUT / PATCH / DELETE requests (#22)
  • Camelize prop names inside lists (e.g. assign_prop(:items, [%{item_name: "..."}])).

Deprecated

  • The inertia_lazy/1 function has been deprecated in favor of inertia_optional/1

0.10.0

Bug Fixes

0.9.0

Bug Fixes

  • Fix improper elimination of nested props when using only partials

0.8.0

Features

  • Support unicode props (by using the binary flag on Node function calls)

0.7.0

Bug Fixes

  • Fix exception when assigning structs as prop values (like DateTime)

0.6.0

Bug Fixes

  • Prevent overly greedy empty object elimination (#14)

0.5.0

  • Assign errors via an assign_errors helper (#10)
  • Preserve assigned errors across redirects (#10)
  • Set up external redirects properly for Inertia requests (#11)
  • Pass CSRF tokens via cookies (#12)
  • Forward flash contents across forced refreshes (#13)
  • Automatically pass Phoenix flash data via the flash prop

0.4.0

  • Support for partial reloads (#6)
  • Support lazy data evaluation (#7)

0.3.0

  • Add raise_on_ssr_failure configuration

0.2.0

  • Add SSR support
  • Add <.inertia_head> component for rendering head elements provided by SSR

0.1.0

  • Initial release