Template API

This document describes Stencils Swift API, and not the Swift template language.


An environment contains shared configuration such as custom filters and tags along with template loaders.

let environment = Environment()

You can optionally provide a loader or extensions when creating an environment:

let environment = Environment(loader: ..., extensions: [...])

Rendering a Template

Environment provides convinience methods to render a template either from a string or a template loader.

let template = "Hello {{ name }}"
let context = ["name": "Kyle"]
let rendered = environment.renderTemplate(string: template, context: context)

Rendering a template from the configured loader:

let context = ["name": "Kyle"]
let rendered = environment.renderTemplate(name: "example.html", context: context)

Loading a Template

Environment provides an API to load a template from the configured loader.

let template = try environment.loadTemplate(name: "example.html")


Loaders are responsible for loading templates from a resource such as the file system.

Stencil provides a FileSytemLoader which allows you to load a template directly from the file system.


Loads templates from the file system. This loader can find templates in folders on the file system.

FileSystemLoader(paths: ["./templates"])
FileSystemLoader(bundle: [Bundle.main])


Loads templates from a dictionary.

DictionaryLoader(templates: ["index.html": "Hello World"])

Custom Loaders

Loader is a protocol, so you can implement your own compatible loaders. You will need to implement a loadTemplate method to load the template, throwing a TemplateDoesNotExist when the template is not found.

class ExampleMemoryLoader: Loader {
  func loadTemplate(name: String, environment: Environment) throws -> Template {
    if name == "index.html" {
      return Template(templateString: "Hello", environment: environment)

    throw TemplateDoesNotExist(name: name, loader: self)


A Context is a structure containing any templates you would like to use in a template. It’s somewhat like a dictionary, however you can push and pop to scope variables. So that means that when iterating over a for loop, you can push a new scope into the context to store any variables local to the scope.

You would normally only access the Context within a custom template tag or filter.


You can use subscripting to get and set values from the context.

context["key"] = value
let value = context["key"]


A Context is a stack. You can push a new level onto the Context so that modifications can easily be poped off. This is useful for isolating mutations into scope of a template tag. Such as {% if %} and {% for %} tags.

context.push(["name": "example"]) {
    // context contains name which is `example`.

// name is popped off the context after the duration of the closure.


Using flatten() method you can get whole Context stack as one dictionary including all variables.

let dictionary = context.flatten()