A cache busting static file middleware for the clack web framework.

Upstream URL


Matt Novenstern




Build Status Coverage StatusQuicklisp

The static asset middleware is for handling versioned static assets. That means that, when the assets of your webapp change, it will be referred to by a different filename, allowing a browser to instantly know that it needs to download a new file. Assets are served with the maximum cache time headers set so browsers will never ask for them again.

It comes with the clack-static-asset-djula-helpers package which extends the djula templating language to allow inserting cache busted urls for your files easily.


Use by wrapping your clack app in clack-static-asset-middleware:*clack-static-asset-middleware*.

(funcall clack-static-asset-middleware:*clack-static-asset-middleware*
		      :root (asdf:system-relative-pathname :webapp #p"static/")
		      :path "static/")

It can be configured by specifying:

  • path: the path on your app that you want your assets to be served from. That is{path}/images/some-sheep_12..532.png.
  • root: The root directory that your assets reside in on the filesystem.
  • cache-buster-function: A function of two arguments (pathname cache-string) that generates an appropriate, cache-busted name for a file. The default creates filenames like images/some-sheep_12421345423fea543265cf43226512a6.png.
  • cache-unbuster-function: A function that takes a cache-busted url and resolves it to the un-busted filename.
  • filter-function: A function that identifies files that should not be served but are in the root directory anyway. It acceps a pathname and return a boolean where t means 'do not serve' and nil means the file is good to serve. By default, it blocks files beginnig with a ., which would be hidden on a UNIX filesystem.

Once you have done that, you can call busted-uri-for-path to convert a relative path on your system into an appropriate cache busted url suitable for inserting into templating and showing your friends. There is a helper package for accessing this functionality within the Djula templating language below.

Real-World Usage

This middleware is not optimized to serve files. It should not be particularly slow, but it was not designed to be your CDN. In real-world situations, you should consider putting a CDN or nginx proxy in front of your app for best performance. I have not done this, yet, but it's probably something I should work on.

Ideally, you might set this up behind an nginx reverse proxy and let it handle un-busting your URLs like so:

server {
  # ...

  location ~* ^/<YOUR PATH HERE>/(\w+)/([^/]+)_\d+\.(js|css|png|jpg|jpeg|gif|ico)$ {
    alias <YOUR ROOT HERE>/$1/$2.$3;
    add_header Vary Accept-Encoding;
    expires max;

  # ...

Example taken from the blog of Ben Ripkens.


clack-static-asset-middleware is not yet in quicklisp, so clone it into your quicklisp local-projects directory. Then, run

(ql:quickload :clack-static-asset-middleware)

or refer to it in your system definition

(asdf:defsystem my-great-webapp
    :depends-on (#:clack-static-asset-middleware)

Template Helpers

Right now, there is a helper package, clack-static-asset-djula-helpers, which provides extensions to the Djula templating language for inserting busted URLs into templates. Once you've loaded the system, there will be two new djula tags available.

  • asset-path: Inserts a busted url to the given path.
    <img src="{% asset-path "images/gustywinds.jpg" %}" /> => <img src="/static/images/gustywinds_423534...a3.jpg" />
  • stylesheet-tag: Inserts a busted url conveniently inside a stylesheet tag.
    {% stylesheet-tag "styles/cool.css" %} => <link rel="stylesheet" href="/static/styles/cool_a05b6...878f.css">



Copyright (c) 2016 Matt Novenstern (


Licensed under the MIT License.

Dependencies (9)

  • alexandria
  • cl-ppcre
  • djula
  • ironclad
  • lack
  • local-time
  • prove
  • trivial-mimes
  • uiop

Dependents (0)

    • GitHub
    • Quicklisp