PhoenixAssetPipeline

Asset pipeline for Phoenix and Phoenix LiveView. It builds and caches application assets, minifies CSS/HTML classes, generates image and SVG variants, compresses static files, and serves everything from one manifest.

Requirements

Installation

def deps do
[{:phoenix_asset_pipeline, "~> 2.0"}]
end

Prepare module-scope classes before Elixir and build the manifest after the application compiler:

def project do
[
compilers:
[:phoenix_live_view, :phoenix_asset_pipeline_prepare] ++
Mix.compilers() ++
[:phoenix_asset_pipeline]
]
end

Configure the endpoint and HEEx engine:

manifest_mode =
case config_env() do
:dev -> :cached
:test -> :cached
:prod -> :precompiled
end
config :phoenix, template_engines: [heex: PhoenixAssetPipeline.HTML.Engine]
config :phoenix_asset_pipeline,
bun_version: "1.3.14",
endpoint: MyAppWeb.Endpoint,
manifest_mode: manifest_mode,
otp_app: :my_app

Start the pipeline before the endpoint:

children = [
PhoenixAssetPipeline,
MyAppWeb.Endpoint
]

HTML

Use the macros in the application's HTML surface:

def html do
quote do
use PhoenixAssetPipeline.HTML.Macros
import PhoenixAssetPipeline.Components
import PhoenixAssetPipeline.Helpers
end
end

Render manifest-backed assets:

<html data-d={asset_digest()}>
<head>
{script("app", async: true, crossorigin: true)}
{style("app")}
</head>
<body>{@inner_content}</body>
</html>

Serve static files before the router:

plug PhoenixAssetPipeline.Plug, :put_private_phoenix_assigns
plug PhoenixAssetPipeline.Plug.Static, only: MyAppWeb.static_paths()
plug MyAppWeb.Router

Classes

Calls from functions and HEEx templates resolve through the current manifest at runtime. Module attributes and component defaults embed stable minified literals prepared before Elixir compilation; production builds allocate them deterministically.

@container {:div, class: class("h-full")}
def button(assigns) do
~H"""
<button class={class(["button", {"enabled", @enabled}])}>...</button>
"""
end

The prepare and final compilers share the same mapping, so module values, runtime values, manifest entries, and CSS selectors remain consistent without a second Elixir compilation.

Assets

Default inputs:

Bun installs application-side dependencies when the package or lockfile changes. Production builds require assets/bun.lock and install with --frozen-lockfile. Image variants use vix/libvips. Brotli, gzip, deflate, and Zstandard representations are stored only when they are smaller than the original.

Common options:

config :phoenix_asset_pipeline,
already_compressed_extensions: ~w(.avif .png .webp),
assets_dir: "assets",
static_dir: "priv/static"

already_compressed_extensions, assets_dir, bun_version, manifest_mode, otp_app, and static_dir are compile-time settings. bun_version must be an exact semantic version and otp_app must match the application name from mix.exs. manifest_mode defaults to :cached; production builds must set it to :precompiled.

Files matching already_compressed_extensions are served with Cache-Control: no-transform so the HTTP server does not compress them again dynamically.

SVG sprites

Use svg_sprites to select SVG files outside assets/svg/sprites. Paths are relative to the project root, and names selects files by basename without requiring literal references in application code:

config :phoenix_asset_pipeline,
svg_sprites: [
%{
file: "flags.svg",
src: "deps/flag_icons/flags/4x3",
names: ~w(ca jp us),
metadata_file: "deps/flag_icons/LICENSE"
}
]

Internal SVG IDs are namespaced by default so references from different source files cannot collide. Set namespace_ids: false only when every selected SVG is known to contain no internal IDs. When metadata_file is set, its XML-escaped text is inserted as one root <metadata> element after optimization. Changes to the metadata file invalidate the SVG cache and trigger development rebuilds.

Build

# Development
mix phx.server
# Production
MIX_ENV=prod mix release
# Manual manifest rebuild
mix phoenix_asset_pipeline.manifest

The development watcher rebuilds changed assets and broadcasts LiveReload events. Production compilation generates PhoenixAssetPipeline.Manifest.Precompiled; separate asset build/deploy tasks are not required.

License

PhoenixAssetPipeline is released under the MIT License. See LICENSE.