Skip to main content
GitHub
elixir

Custom paths for static assets in a Phoenix app

2024-10-26 in Particles

TIL you can use multiple Static plugs to serve static files at custom paths in an Elixir / Phoenix app.

I used this to specify the path at which my sitemap files are served without affecting any other static assets.

In a project created with mix phx.new, the Endpoint module sets out a initial plug pipeline that all requests go through. (It ends with plug YourAppWeb.Router, passing the request off to your app’s Phoenix Router module, which decides which pipeline it should go through next.)

Requests pass through Plug.Static early on; if the request path matches a path in the app’s priv/static/ directory, it serves the file directly.

Here’s mine:

  plug Plug.Static,
    at: "/",
    from: :clutterstack,
    only: ClutterstackWeb.static_paths()

By default, everything in priv/static/ is served at a URL that reflects the file’s path relative to that directory. The only: YourAppWeb.static_paths() option narrows that down to a list of folders and files.

The :only option also saves unnecessary file system reads: the request URI is checked against this list first, so if the requested path isn’t included, there’s no need to check inside priv/static/ for the presence of the file.

For fun, let’s just look at where that list is defined. Here’s static_paths from my clutterstack_web.ex file:

  def static_paths, do: ~w(assets fonts images favicon.ico robots.txt)

(The ~w sigil converts space-separated words into a list of strings.)

So priv/static/robots.txt gets served at /sitemap.xml and images at, e.g. /images/whatever.jpg.

I have also have sitemap files inside priv/static/sitemaps/. If I include sitemaps in the above :only option, these files will be served at /sitemaps/sitemapfile.xml. I’d prefer to use the root path where indexers look by default: https://clutterstack.com/sitemap.xml.

So I added another static plug to endpoint.ex just for sitemaps:

  plug Plug.Static,
    at: "/",
    from: {:clutterstack, "priv/static/sitemaps/"}

Bob’s your uncle; all my sitemap files are served at the root path.

This wasn’t the only solution to making my sitemap easy for robots to find; you can also specify a non-default location of a sitemap file in robots.txt (developers.google.com).