Pencil comes with a simple templating engine. Templates allow us to build web pages dynamically using Haskell code. Every blog post, for example, can share a common HTML template.

Pencil templates are regular HTML and Markdown (and other formats that Pencil supports) files that contain a preamble or directives.


Preambles are environment variable declarations inside your source files. A file may only have one preamble, and they must be declared at the top of the file. A preamble is YAML wrapped in an HTML comment. An example Markdown file with a preamble:

postTitle: "Why I Love Python"
date: 2010-01-30
  - python

I learned Java first. So when I found out about Python,
it was *love at first sight*.

In the above example, Pencil will intelligently parse the date value as a VDateTime. See toDateTime, which describes the date formats that Pencil will try to coerce into a VDateTime.


Directives allow you to render variables. They are surrounded by ${...}.


The simplest directive is the variable directive.

Hello ${name}!

The above template will render the value of the variable name, which is expected to be in the environment at render. If the variable is not found, the final render will literally include ${name}.

If block

The if directive allows us to render content based off the existence of a variable in the current environment.

  Hello ${name}!

In this case, we now make sure that name is available before rendering.

For loop

The for directive allows for looping over arrays. This is useful for things like rendering a list of blog post titles, linking each line to the actual blog post.

  <li><a href="${this.url}">${postTitle}</a> - ${date}</li>

posts must either be a collection node in the Structure, or a VEnvList variable. The example will render each post’s title, publish date, and will link it to this.url. Note that inside the for block, the scope changes to each post’s environment. So ${postTitle} will render each post’s title.

this.url is a special variable that is automatically inserted for you inside a loaded Page. It points to the page’s destination file path.


The partial directive injects another template file into the current file. The directives inside the partial are rendered in the same environmental context as the partial directive.

Think of partials as just copy-and-pasting snippet from one file to another. Unlike Structures, partials cannot define environment variables.

In the example below, the first partial is rendered with the current environment. The partial inside the for loop receives the same environment as any other snippet inside the loop, and thus has access to the environment inside each post.



If you want a literal “${name}” to be rendered, you need to escape the dollar sign by doubling it. So in the example below, Pencil will not parse it as a directive, but will render “${name}” instead:


This very source file uses escapes.