Creating Documentation for Clojure Projects with Fabricate


What you'll learn in this tutorial:

How to use Fabricate alongside your own code to document your project.

What you'll need to get started:

If your project already uses deps.edn and tools.deps you won't need to make any configuration changes apart from adding an alias. If you use lein or boot, you'll need to do a bit more setup. Lein and boot support are covered in separate guides.

What you'll have when you're done:

Some published documentation, hosted with your project, that you can automatically update when your project changes.

How this tutorial works

We'll be doing all the setup we need to do from the Clojure REPL. As long as you can customize how you start your REPL, you can follow the tutorial regardless of which editor or operating system you use.


  1. Add an alias for Fabricate

    You can add Fabricate as a tool to your project without adding it as a dependency.
  2. Create folders for input documents and output HTML

    Fabricate needs dedicated folders for its content.
  3. Create your first page template: an introduction to your library

    Plain text isn't a bad place to start describing your library.
  4. Generate a HTML page from the first template

    Use Fabricate to see your writing in action.

Step 1: Add an alias for Fabricate

In your Clojure project's folder, you will have a file called deps.edn. This file contains data used to define information about your project, like the libraries it depends upon, functions that can be used from the Clojure command-line-interface, and where the project's source code and resources can be found.

This file is just an EDN map, defining in plain text an associative array much like Clojure's own hash maps. If you've used JSON before, you can think of EDN like Clojure's version of JSON. The important part is this file maps from certain keys to values - you can add Fabricate to the project by updating the :aliases key with a new key. You might already have aliases defined for your project, in which case you'll add another one for Fabricate. If you don't, then you can just add an :aliases key with the same information.

If you already have aliases defined
:aliases {
:test {:extra-paths ["test"]
   :extra-deps org.clojure/test.check {:mvn/version "1.1.0"}}
:fabricate {:extra-deps site.fabricate/fabricate {:git/url "https://github.com/fabricate-site/fabricate/" :sha "7fb30c0ead0c03ef0cc4c0133a2329752e0db37b"}}}

If your project doesn't have aliases defined yet

:aliases {:fabricate {:extra-deps site.fabricate/fabricate {:git/url "https://github.com/fabricate-site/fabricate/" :sha "7fb30c0ead0c03ef0cc4c0133a2329752e0db37b"}}}

Once you have this alias, you can test it by launching your Clojure REPL with it:

clojure -A:fabricate -X:clojure.main/main

You'll use this REPL for the rest of the tutorial.

Step 2: Create folders for input documents and output HTML

Run the following commands in your REPL:

(require '[clojure.java.io :as io])(io/make-parents "./pages/intro.html.fab")(io/make-parents "./docs/")

Make sure the files and folders got created:

(.exists (io/file "./pages/intro.html.fab"))(let [f (io/file "./docs/")]
(and (.exists f) (.isDirectory f)))

The results for both of those commands should be true.

Step 3: Create your first page template: an introduction to your library

You might already have some text in a README file somewhere; that's a great starting point. If you don't, take a few minutes to think about the purpose of your code and how to communicate the purpose of that code to someone unfamiliar with it. Try to empathize with someone who might know a bit about Clojure, but knows nothing at all about your library and might be confused by it.

Now you're ready to write. Open the file you created in your editor. Here's a basic structure you can get started with:

✳(ns my-library.docs.intro)🔚

✳(def metadata {:title "Intro to my library"})🔚

✳=[:h1 (:title metadata)] 🔚

This document gives an overview of the library.

The first three lines are Fabricate blocks, which contain Clojure code. They start with the ✳ emoji and end with the 🔚 emoji. Usually they contain only one expression each. The last line is plain text. This is a short snippet, but it contains a few important ideas about Fabricate, so it's worth going through it line-by-line and seeing why each of these lines matters to the final page.

Line 1: Each page is a namespace

✳(ns my-library.docs.intro)🔚

In Fabricate, pages are organized and kept separate from one another by using the same method used to organize ordinary Clojure code: namespaces. You can require libraries, define variables, and do anything you'd do in an ordinary Clojure file in a Fabricate file. Just like an ordinary Clojure file, it's sensible to begin a Fabricate file with a namespace declaration.

For more context on how Fabricate uses the file you're writing in to produce a page, you can see the reference docs "anatomy of a Fabricate page template" and "the Fabricate reading process".

Line 2: One variable is special: metadata

✳(def metadata {:title "Intro to my library"})🔚

The metadata variable tells Fabricate about the page itself: what its title is, whether it should define any custom CSS, or load any JavaScript. The most visible use of this variable is to set the HTML document <title> tag using the :title keyword, so the web browser can give the page a title.

This variable is one of the few that you have to pay special attention to in order to use Fabricate correctly. If you ignore or mess with this variable, things might break!

Line 3: Use = to produce output

✳=[:h1 (:title metadata)] 🔚

This is where Fabricate first produces the contents of the HTML page; by including = after the ✳ emoji, the input file is telling Fabricate to include the result in the page - in this case, a header with the title defined in the metadata variable.

The first two Fabricate expressions in the example code don't produce anything in the output. These are functions that are usually run for their side-effects: declaring the namespace of a page for the first line, and defining a variable by binding the metadata symbol to the hash-map: {:title "Intro to my library"}.

This expression is how Fabricate lets you use all of HTML inline, with the full power of Clojure to create and mold it.

Line 4: Your own writing

This document gives an overview of the library.

Beyond this, it's up to you! Fabricate gives you some tools to help you along, but doesn't impose much of a structure on you. You can define the page you're writing, and the functions you use to help you write, however you see fit.

You should change this line to reflect what your library can do for its users, and what might make it unique.

Step 4: Generate a HTML page from the first template

Run Fabricate's publish! function from the site.fabricate.prototype.write namespace.

You can do this from your REPL, as before:

(require '[site.fabricate.prototype.write :as write])(write/publish! {:files ["./pages/intro.html.fab"]})

You should see some output in your REPL about the page getting read, parsed, and evaluated. Don't worry too much about that for the time being. Check to see if your page is there by opening the file in your web browser!