PhoenixPress
SEO and discoverability for Phoenix: sitemaps, robots.txt, RSS feeds, and llms.txt.
Compile-time, declarative, and served via a single Plug. Zero runtime overhead per request.
Installation
Add phoenix_press to your list of dependencies in mix.exs:
def deps do
[
{:phoenix_press, "~> 0.2.0"}
]
endUsage
1. Define your modules
Sitemap
defmodule MyAppWeb.Press.Sitemap do
use PhoenixPress.Sitemap, base_url: "https://example.com"
add "/", changefreq: :weekly, priority: 1.0
add "/blog", changefreq: :weekly, priority: 0.8
for post <- MyApp.Blog.all_posts() do
add "/blog/#{post.id}", changefreq: :monthly, lastmod: post.date
end
endRobots
defmodule MyAppWeb.Press.Robots do
use PhoenixPress.Robots, base_url: "https://example.com"
sitemap "/sitemap.xml"
allow "/"
disallow "/dashboard"
endRSS Feed
defmodule MyAppWeb.Press.Feed do
use PhoenixPress.Feed,
title: "My Blog",
description: "Latest posts",
base_url: "https://example.com"
for post <- MyApp.Blog.all_posts() do
entry post.title,
link: "/blog/#{post.id}",
description: post.description,
pub_date: post.date,
author: post.author
end
endllms.txt
defmodule MyAppWeb.Press.LlmsTxt do
use PhoenixPress.LlmsTxt,
title: "My App",
description: "A platform for managing widgets."
section "Docs"
link "/docs/getting-started", "Getting Started", "How to set up the project"
link "/docs/api", "API Reference", "Full API documentation"
section "Optional"
link "/blog", "Blog", "Latest updates"
end2. Add the Plug to your endpoint
Add it before your router:
plug PhoenixPress.Plug,
sitemap: MyAppWeb.Press.Sitemap,
robots: MyAppWeb.Press.Robots,
feed: MyAppWeb.Press.Feed,
llms_txt: MyAppWeb.Press.LlmsTxtAny key can be omitted if you don't need that feature.
3. That's it
Your app now serves:
GET /sitemap.xmlwithContent-Type: text/xmlGET /robots.txtwithContent-Type: text/plainGET /feed.xmlwithContent-Type: application/rss+xmlGET /llms.txtwithContent-Type: text/plain
All responses include Cache-Control: public, max-age=3600.
How it works
PhoenixPress generates XML/text at compile time using Elixir macros. When a request hits your endpoint, the Plug serves pre-built strings with zero runtime computation.
This means:
- No database queries per request
- No XML building per request
- No template rendering per request
To update content, recompile the module (or use mix compile --force).
License
MIT - see LICENSE for details.