Astral's long-term goal is to become an Elixir-native static site and hybrid site framework with Astro-class site features, while keeping Volt focused on frontend assets, bundling, dev server primitives, and HMR.

Architecture principles

  • Volt stays Vite-like. Volt owns JavaScript/TypeScript/CSS compilation, bundling, imported assets, embedded modules, dev server primitives, and HMR.
  • Astral owns site semantics. Astral owns pages, routes, content collections, layouts, frontmatter, feeds, sitemaps, metadata, islands, and deployment adapters.
  • Elixir-first configuration. Site config is real Elixir returning structs, not global app env or JavaScript object clones.
  • HEEx-first templates. .astral uses Phoenix/HEEx semantics instead of inventing a JSX-like component language.
  • Parser-backed processing. Use real parsers for Markdown, HEEx-like templates, HTML-like markup, JavaScript/TypeScript, CSS, and frontmatter.
  • Value before abstraction. Add hooks and APIs when they unlock user-facing capabilities.

Shipped foundation

v0.1.0 — Initial static site generator

  • Static HTML and Markdown build pipeline.
  • Elixir astral.config.exs site DSL.
  • MDEx-backed Markdown and YAML frontmatter support.
  • EEx layouts with page, metadata, route, and site assigns.
  • Per-page layout selection and layout disabling.
  • Public static file copying.
  • Plug/Bandit development server composed with Volt.
  • mix astral.dev, mix astral.build, mix astral.new, and mix astral.install.
  • Astral.asset_path/2 for Volt-managed layout assets.
  • Runnable examples/basic starter site.

v0.1.1 — Content, plugins, and .astral templates

  • HEEx-first .astral pages, layouts, and local components.
  • Elixir setup blocks in .astral templates.
  • Parser-backed .astral <style> and <script> extraction through Volt embedded modules.
  • Local component discovery from components/**/*.astral.
  • Content collections.
  • Collection schemas and validation with JSONSpec-style typespec maps and Zoi.
  • Collection entry routes from permalink patterns.
  • Collection query helpers such as entries/2, published/1, sort_by_date/2, and tags/1.
  • Route patterns with Plug/Phoenix-style :param and *glob segments.
  • Pagination primitives and collection pagination plugin.
  • Plugin foundation modeled after Volt: behaviour, runner, tuple options, ordering, generated routes, route rendering, page transforms, and lifecycle hooks.
  • Feed and sitemap plugins.
  • Markdown heading anchors and heading metadata for table-of-contents layouts.
  • XM extracted as a standalone XML DSL package used by feed/sitemap plugins.
  • User guides, cheatsheets, and a Volt-style README.

Near-term priority: dynamic content routes

Initial collection-backed dynamic file routes landed on master after v0.1.1. The next priority is rounding them into a complete dynamic content route story with diagnostics, examples, and non-collection enumeration if needed.

Target file shapes:

pages/blog/[slug].astral
pages/blog/[slug].md
pages/docs/[...path].md
pages/tags/[tag]/[...page].astral

Route equivalents:

/blog/:slug
/docs/*path
/tags/:tag/*page

Dynamic file routes integrate with collections without making tags/categories a core taxonomy abstraction. A common blog detail page is expressible as a user-owned route template backed by collection data:

content/posts/hello.md
pages/blog/[slug].astral

The page template owns the HTML while Astral provides the matching entry and route params.

Design goals

  • Keep route syntax Elixir/Phoenix-like at the API level: :slug and *path.
  • Use bracket filenames only as file-route sugar.
  • Avoid : and * in filenames for Windows and shell portability.
  • Support .md, .html, and .astral pages.
  • Make collection-backed dynamic routes feel like ordinary page rendering.
  • Keep tags/categories userland.
  • Preserve generated route plugins for feeds, sitemaps, pagination, and custom files.

Likely work

  • Parser-backed file-route conversion from [slug] / [...path] filenames to Astral.Route.Pattern. (Initial support landed on master after v0.1.1.)
  • Route params in page/layout assigns as string-keyed @params. (Initial support landed on master after v0.1.1.)
  • Collection matching for route params, initially by route pattern. (Initial support landed on master after v0.1.1.)
  • Decide how get_static_paths-style enumeration should look in Elixir, if needed for non-collection dynamic pages.
  • Add dev/build diagnostics for dynamic routes with missing params or unmatched entries.
  • Add richer example site pages.

Next milestones

v0.2 — Dynamic content routes

Goal: make Astral a practical blog/docs framework with user-owned dynamic templates.

  • Dynamic file routes for .md, .html, and .astral. (Initial collection-backed support landed on master after v0.1.1.)
  • Collection-backed detail routes such as pages/blog/[slug].astral. (Initial support landed on master after v0.1.1.)
  • Route params available in pages and layouts. (Initial support landed on master after v0.1.1.)
  • Dynamic route diagnostics.
  • Userland tag pages documented with dynamic routes and pagination.
  • Frontmatter defaults.
  • Non-collection dynamic route enumeration, if a clear Elixir API emerges.
  • More complete content collection guide examples.

v0.3 — Metadata and document head

Goal: make production pages easier to build without ad hoc layout code.

  • Page metadata helpers.
  • Canonical URL helpers.
  • Open Graph and Twitter card helpers.
  • Feed/sitemap discovery links.
  • Per-route <head> contribution from pages, layouts, and plugins.
  • Plugin hook for head entries, likely head/2 or equivalent.

v0.4 — Starter templates and product polish

Goal: make Astral easy to try for real sites.

  • mix astral.new --template blog.
  • mix astral.new --template docs.
  • mix astral.new --template marketing.
  • Search integration for docs/blog templates.
  • Syntax highlighting defaults.
  • Related posts examples.
  • Redirects.
  • Stronger deployment docs for common static hosts.

v0.5 — Islands MVP

Goal: deliver Astro's biggest differentiator in an Elixir/Volt-native way.

  • Island declarations in .astral/HEEx templates.
  • Initial hydration modes:
    • client:load
    • client:idle
    • client:visible
  • Island manifest generation.
  • Prop serialization.
  • Volt entries for island client boot code.
  • One framework adapter first, then expand.

Candidate API direction:

<.island component="Counter" client="visible" props={%{count: 0}} />

v0.6 — Framework adapters and richer islands

  • React islands.
  • Vue islands.
  • Svelte islands.
  • Solid islands.
  • client:media and client:only hydration modes.
  • Route-level and component-level code splitting.
  • Island dev diagnostics.

v0.7 — Hybrid/runtime modes

Goal: move beyond static-only without making Volt responsible for site semantics.

  • Static output mode remains default.
  • Plug runtime adapter.
  • Phoenix integration adapter.
  • Hybrid prerender plus dynamic routes.
  • Runtime route manifest.

v1.0 — Stable Astro-class foundation

  • Stable config DSL.
  • Stable content collection API.
  • Stable plugin API.
  • Stable .astral template API.
  • Stable island API.
  • Strong HexDocs and examples.
  • Dogfooded docs site built with Astral.
  • Production deployment guides for common static hosts.