Minimal site

import Astral.Config

layouts do
  default "default.html"
end

Common paths

root "."
outdir "dist"
pages "pages"
public "public"
components "components"

Layouts

layouts do
  default "default.html"
end

Use a .astral layout:

layouts do
  default "site.astral"
end

Assets

assets do
  entry "app.ts"
  url_prefix "/assets"
  hash true
end

Reference asset entries from layouts with Astral.asset_path/2. In development this points at Volt's dev server; in static builds it resolves through the emitted manifest.

Browser environment variables

config :volt, env_prefix: ["VOLT_", "PUBLIC_"]

Variables matching env_prefix are exposed to browser assets through import.meta.env. Keep secrets outside exposed prefixes.

Dynamic file routes

pages/blog/[slug].astral   -> /blog/:slug
pages/docs/[...path].md    -> /docs/*path

Read route params from templates and layouts with atom keys:

<%= @params.slug %>

Declare arbitrary dynamic .astral paths with the path/1 setup helper:

---
paths = [path tag: "elixir", assigns: %{title: "Elixir"}]
---
<h1>{@title}</h1>

Static generated routes

get "/robots.txt", content_type: "text/plain" do
  "User-agent: *\nAllow: /\n"
end

Multilingual static routes

Use localized folders and site-owned link helpers today:

pages/about.md     -> /about/
pages/es/about.md  -> /es/about/

First-class i18n routing config, fallbacks, domains, and browser-language middleware are not implemented yet.

Use plug only for config-generated route middleware:

plug MySite.GeneratedHeaders, cache: "public, max-age=3600"

Content collections

collection :posts, "content/posts" do
  permalink "/blog/:slug/"
  layout "post.html"

  schema do
    field :title, :string, required: true
    field :date, :date, required: true
    field :draft, :boolean, default: false
    field :tags, {:array, :string}, default: []
  end
end

Site metadata

Keep SEO and document metadata in layouts or components:

<head>
  <.base_head title={@page.title || "My Site"} route={@route} />
</head>

Pass deployment URLs to feed, sitemap, or head components where they are needed.

Plugins

plugin Astral.Plugin.Feed,
  site_url: "https://example.com",
  title: "My Blog",
  author: "Me",
  collection: :posts

plugin Astral.Plugin.Sitemap,
  site_url: "https://example.com"