Configuration Reference
All configuration options for PhoenixPrerender
Prerendered under the /docs scope. Generated file: docs/terms/index.html
Application Configuration
All options live under the
:phoenix_prerender
application key:
config :phoenix_prerender,
enabled: false,
output_path: "priv/static/prerendered",
url_style: :dir_index,
cache_control: "public, max-age=300",
strict_paths: true,
concurrency: System.schedulers_online(),
bots_only: false,
base_url: "https://example.com",
pubsub: nil
| Option | Default | Description |
|---|---|---|
| enabled | false | Whether the serving plug is active |
| output_path | "priv/static/prerendered" | Directory for generated HTML files |
| url_style | :dir_index | :dir_index (about/index.html) or :file (about.html) |
| cache_control | "public, max-age=300" | Cache-Control header for served pages |
| strict_paths | true | Only serve paths listed in manifest.json |
| bots_only | false | Global override: serve all prerendered pages to bots only. Prefer per-route metadata instead. |
| concurrency | schedulers_online | Parallel rendering tasks during generation |
| base_url | "https://example.com" | Base URL for sitemap.xml generation |
| pubsub | nil | PubSub server for distributed cache invalidation |
Per-Route Metadata
Inside a prerender do
block,
dead views get
prerender: true
injected automatically. LiveView routes pass through unchanged — use explicit metadata
to control prerendering:
| Metadata | Behavior |
|---|---|
| %{prerender: true} | Served to all clients (default for dead views in prerender block) |
| %{prerender: :bots_only} | Prerendered HTML served to search engine crawlers only; browsers get the live app |
| %{prerender: :always} | Served to everyone with a fresh session and CSRF token (requires session_options) |
| %{isr: true} | Enable per-route ISR; triggers background regeneration when stale |
prerender do
get "/about", PageController, :about # prerender: true (auto)
live "/changelog", ChangelogLive # not prerendered
live "/status", StatusLive, :index,
metadata: %{prerender: :bots_only} # SEO only
live "/dashboard", DashboardLive, :index,
metadata: %{prerender: :always, isr: true} # everyone + ISR
end
URL Styles
| URL Path | :dir_index | :file |
|---|---|---|
| / | index.html | index.html |
| /about | about/index.html | about.html |
| /docs/terms | docs/terms/index.html | docs/terms.html |
Plug Options
Options passed directly to the plug override application config:
# endpoint.ex
@session_options [store: :cookie, key: "_app_key", signing_salt: "..."]
plug PhoenixPrerender.Plug,
endpoint: MyAppWeb.Endpoint, # required for ISR
session_options: @session_options, # required for :always routes
output_path: "priv/static/prerendered",
url_style: :dir_index,
cache_control: "public, max-age=3600",
strict_paths: true,
enabled: true
session_options
enables the CSRF token swap for
prerender: :always
routes. Without it, :always routes are served without a fresh session,
which will break LiveView's WebSocket connection.
ISR Configuration
ISR is opt-in per route via metadata. Add the PageCache and Regenerator to your supervision tree, and pass the endpoint to the plug:
# application.ex
children = [
PhoenixPrerender.PageCache,
{PhoenixPrerender.Regenerator, endpoint: MyAppWeb.Endpoint}
]
# endpoint.ex
plug PhoenixPrerender.Plug,
endpoint: MyAppWeb.Endpoint,
session_options: @session_options
# config/prod.exs
config :phoenix_prerender,
enabled: true,
revalidate: 300 # seconds before a page is stale
# router.ex — opt in per route
prerender do
live "/status", StatusLive, :index,
metadata: %{prerender: :always, isr: true}
end
<.prerendered> Component
For LiveView pages with prerender: :always,
use the <.prerendered>
component to freeze values at prerender time. LiveView will not patch these elements after hydration.
import PhoenixPrerender.Components
def mount(_params, _session, socket) do
# Only compute at prerender time (disconnected)
generated_at =
if connected?(socket),
do: "",
else: DateTime.utc_now() |> Calendar.strftime(...)
{:ok, assign(socket, generated_at: generated_at)}
end
def render(assigns) do
~H"""
<.prerendered id="gen-time" tag="p" class="font-mono">
{@generated_at}
</.prerendered>
"""
end
Attributes: id
(required), tag
(default: "span"), class
(optional).
See the /status
page for a live demo.