Asset Fingerprinting

Asset fingerprinting appends a content hash to CSS and JS filenames during accent build, producing immutable URLs that CDNs and browsers can cache indefinitely. When the file content changes, the hash changes, and browsers automatically fetch the new version.

Quick Start

  1. Enable fingerprinting in config.yaml:
build:
  fingerprint:
    enabled: true
  1. Use the | fingerprint filter in your templates:
{% for css in theme.assets.css %}
<link rel="stylesheet" href="/{{ ('theme/assets/' ~ css) | fingerprint }}">
{% endfor %}
  1. Build your site:
accent build --output ./public --base-url https://example.com

The output will contain both the original and fingerprinted files:

public/theme/assets/css/
  main.css                  # Original (kept for compatibility)
  main.64aee5ca8b.css       # Fingerprinted copy

How It Works

During accent build, after theme assets are copied and Sass/SCSS styles are compiled:

  1. The build walks output/theme/assets/ and matches files against the include/exclude patterns.
  2. For each matched file, it computes the SHA-256 hash of the file contents.
  3. It copies the file with a fingerprinted name: {stem}.{hash}.{ext}.
  4. A manifest maps original paths to fingerprinted paths.
  5. The | fingerprint template filter resolves paths via this manifest during page rendering.

Original files are kept alongside fingerprinted copies so that external links and bookmarks continue to work.

Template Filter

Basic Usage

The | fingerprint filter takes an asset path and returns the fingerprinted equivalent:

<link rel="stylesheet" href="/{{ 'theme/assets/css/style.css' | fingerprint }}">
{# Renders: /theme/assets/css/style.a1b2c3d4e5.css #}

<script src="/{{ 'theme/assets/js/app.js' | fingerprint }}"></script>
{# Renders: /theme/assets/js/app.deadbeef01.js #}

If the path is not in the manifest (e.g., the file was excluded or fingerprinting is disabled), the filter returns the path unchanged. This means templates work correctly in both fingerprinted and non-fingerprinted builds.

Subresource Integrity (SRI)

Pass integrity=true to get an object with .url and .integrity attributes:

{% set css = 'theme/assets/css/style.css' | fingerprint(integrity=true) %}
<link rel="stylesheet"
      href="/{{ css.url }}"
      integrity="{{ css.integrity }}"
      crossorigin="anonymous">

The .integrity value is a base64-encoded hash in SRI format (e.g., sha256-abc123...), suitable for the HTML integrity attribute. Browsers will verify the file contents match the hash before applying the stylesheet or executing the script.

Serve Mode

In accent serve mode, the | fingerprint filter is a no-op: it returns the original path unchanged. This is correct because serve mode compiles styles on-the-fly and serves assets from disk without renaming.

Configuration

All settings are under build.fingerprint in config.yaml:

build:
  fingerprint:
    enabled: true           # Default: false (opt-in)
    algorithm: sha256       # sha256, sha384, or sha512
    length: 10              # Hex characters in the filename hash
    include:                # Glob patterns to fingerprint
      - "**/*.css"
      - "**/*.js"
    exclude:                # Glob patterns to skip
      - "**/*.map"

Settings Reference

SettingDefaultDescription
enabledfalseEnable asset fingerprinting. Opt-in to avoid breaking existing themes.
algorithmsha256Hash algorithm: sha256, sha384, or sha512.
length10Number of hex characters from the hash to use in filenames.
include["**/*.css", "**/*.js"]Glob patterns for files to fingerprint.
exclude["**/*.map"]Glob patterns for files to skip.

Including Additional File Types

To fingerprint fonts and images as well:

build:
  fingerprint:
    enabled: true
    include:
      - "**/*.css"
      - "**/*.js"
      - "**/*.woff2"
      - "**/*.svg"

CDN Cache Headers

When fingerprinted assets are deployed behind a CDN, set long-lived cache headers:

Cache-Control: public, max-age=31536000, immutable

This tells browsers and CDNs to cache the file for one year without revalidation. Since the filename changes when the content changes, stale copies are never served.

Accent CMS already sets immutable cache headers for CSS/JS assets in accent serve --production . For static deployments, configure these headers in your hosting platform:

  • Cloudflare Pages: Automatic for static assets
  • Netlify: Add a _headers file with rules for theme/assets/*
  • nginx: location /theme/assets/ { expires 1y; add_header Cache-Control "public, immutable"; }

Edition Availability

Asset fingerprinting requires no license key.