Swiftpack.co - Package - stencilproject/Stencil


Build Status

Stencil is a simple and powerful template language for Swift. It provides a syntax similar to Django and Mustache. If you're familiar with these, you will feel right at home with Stencil.


There are {{ articles.count }} articles.

  {% for article in articles %}
    <li>{{ article.title }} by {{ article.author }}</li>
  {% endfor %}
import Stencil

struct Article {
  let title: String
  let author: String

let context = [
  "articles": [
    Article(title: "Migrating from OCUnit to XCTest", author: "Kyle Fuller"),
    Article(title: "Memory Management with ARC", author: "Kyle Fuller"),

let environment = Environment(loader: FileSystemLoader(paths: ["templates/"]))
let rendered = try environment.renderTemplate(name: "article_list.html", context: context)



Stencil follows the same philosophy of Django:

If you have a background in programming, or if you’re used to languages which mix programming code directly into HTML, you’ll want to bear in mind that the Django template system is not simply Python embedded into HTML. This is by design: the template system is meant to express presentation, not program logic.

The User Guide

Resources for Stencil template authors to write Stencil templates:

Resources to help you integrate Stencil into a Swift project:

Projects that use Stencil

Sourcery, SwiftGen, Kitura, Weaver, Genesis


Stencil is licensed under the BSD license. See LICENSE for more info.


Stars: 1891


0.14.0 - 2020-08-17 18:45:21


  • Drop support for Swift < 4.2. For Swift 4 support, you should use Stencil 0.13.1.
    David Jennes #294


  • Added support for dynamic filter using filter filter. With that you can define a variable with a name of filter , i.e. myfilter = "uppercase" and then use it to invoke this filter with {{ string|filter:myfilter }}.
    Ilya Puchka #203



Bug Fixes

  • Fixed using parenthesis in boolean expressions, they now can be used without spaces around them.
    Ilya Puchka #254
  • Throw syntax error on empty variable tags ({{ }}) instead fatalError.
    Ilya Puchka #263

Internal Changes

- 2020-08-16 17:46:47

Bug Fixes

  • Fixed a bug in Stencil 0.13 where tags without spaces were incorrectly parsed.
    David Jennes #252

0.13.0 - 2018-09-25 23:15:38



  • You can now use parentheses in boolean expressions to change operator precedence.
    Ilya Puchka #165
  • Added method to add boolean filters with their negative counterparts.
    Ilya Puchka #160
  • Now you can conditionally render variables with {{ variable if condition }}, which is a shorthand for {% if condition %}{{ variable }}{% endif %}. You can also use else like {{ variable1 if condition else variable2 }}, which is a shorthand for {% if condition %}{{ variable1 }}{% else %}{{ variable2 }}{% endif %}
    Ilya Puchka #243
  • Now you can access string characters by index or get string length the same was as if it was an array, i.e. {{ 'string'.first }}, {{ 'string'.last }}, {{ 'string'.1 }}, {{ 'string'.count }}.
    Ilya Puchka #245

Bug Fixes

  • Fixed the performance issues introduced in Stencil 0.12 with the error log improvements.
    Ilya Puchka #230
  • Now accessing undefined keys in NSObject does not cause runtime crash and instead renders empty string.
    Ilya Puchka #234
  • for tag: When iterating over a dictionary the keys will now always be sorted (in an ascending order) to ensure consistent output generation.
    David Jennes #240

Internal Changes

0.12.1 - 2018-08-30 11:52:51

Internal Changes

  • Updated the PathKit dependency to 0.9.0 in CocoaPods, to be in line with SPM.
    David Jennes #227

0.12.0 - 2018-08-26 21:39:10


  • Added an optional second parameter to the include tag for passing a sub context to the included file.
    Yonas Kolb #214
  • Variables now support the subscript notation. For example, if you have a variable key = "name", and an object item = ["name": "John"], then {{ item[key] }} will evaluate to "John".
    David Jennes #215
  • Adds support for using spaces in filter expression.
    Ilya Puchka #178
  • Improvements in error reporting.
    Ilya Puchka #167

Bug Fixes

0.11.0 - 2018-04-05 01:39:51


  • Added support for resolving superclass properties for not-NSObject subclasses
  • The {% for %} tag can now iterate over tuples, structures and classes via their stored properties.
  • Added split filter
  • Allow default string filters to be applied to arrays
  • Similar filters are suggested when unknown filter is used
  • Added indent filter
  • Allow using new lines inside tags
  • Added support for iterating arrays of tuples
  • Added support for ranges in if-in expression
  • Added property forloop.length to get number of items in the loop
  • Now you can construct ranges for loops using a...b syntax, i.e. for i in 1...array.count

Bug Fixes

  • Fixed rendering {{ block.super }} with several levels of inheritance
  • Fixed checking dictionary values for nil in default filter
  • Fixed comparing string variables with string literals, in Swift 4 string literals became Substring and thus couldn't be directly compared to strings.
  • Integer literals now resolve into Int values, not Float
  • Fixed accessing properties of optional properties via reflection
  • No longer render optional values in arrays as Optional(..)
  • Fixed subscription tuples by value index, i.e. {{ tuple.0 }}

0.10.1 - 2017-11-17 18:43:11


  • Add support for Xcode 9.1.

0.10.0 - 2017-10-28 20:39:25


  • Adds counter0 to for loop context allowing you to get the current index of the for loop 0 indexed.
  • Introduces a new DictionaryLoader for loading templates from a Swift Dictionary.
  • Added in expression in if tag for strings and arrays of hashable types
  • You can now access the amount of items in a dictionary using the count property.

Bug Fixes

  • Fixes a potential crash when using the {% for %} template tag with the incorrect amount of arguments.
  • Fixes a potential crash when using incomplete tokens in a template for example, {%%} or {{}}.
  • Fixes evaluating nil properties as true

0.9.0 - 2017-04-18 23:12:39


  • for block now can contain where expression to filter array items. For example {% for item in items where item > 1 %} is now supported.

  • if blocks may now contain else if (elif) conditions.

    {% if one or two and not three %}
      one or two but not three
    {% elif four %}
    {% else %}
      not one, two, or four
    {% endif %}
  • for block now allows you to iterate over array of tuples or dictionaries.

    {% for key, value in thing %}
      <li>{{ key }}: {{ value }}</li>
    {% endfor %}

Bug Fixes

  • You can now use literal filter arguments which contain quotes. #98

- 2017-02-18 12:45:26


  • It is no longer possible to create Context objects. Instead, you can pass a dictionary directly to a Templates render method.

    - try template.render(Context(dictionary: ["name": "Kyle"]))
    + try template.render(["name": "Kyle"])
  • Template loader are no longer passed into a Context, instead you will need to pass the Loader to an Environment and create a template from the Environment.

    let loader = FileSystemLoader(paths: ["templates/"])
    - let template = loader.loadTemplate(name: "index.html")
    - try template.render(Context(dictionary: ["loader": loader]))
    + let environment = Environment(loader: loader)
    + try environment.renderTemplate(name: "index.html")
  • Loaders will now throw a TemplateDoesNotExist error when a template is not found.

  • Namespace has been removed and replaced by extensions. You can create an extension including any custom template tags and filters. A collection of extensions can be passed to an Environment.


  • Environment is a new way to load templates. You can configure an environment with custom template filters, tags and loaders and then create a template from an environment.

    Environment also provides a convenience method to render a template directly.

  • FileSystemLoader will now ensure that template paths are within the base path. Any template names that try to escape the base path will raise a SuspiciousFileOperation error.

  • New {% filter %} tag allowing you to perform a filter across the contents of a block.

    {% filter lowercase %}
      This Text Will Be Lowercased.
    {% endfilter %}
  • You can now use {{ block.super }} to render a super block from another {% block %}.

  • Environment allows you to provide a custom Template subclass, allowing new template to use a specific subclass.

  • If expressions may now contain filters on variables. For example {% if name|uppercase == "TEST" %} is now supported.


  • Template initialisers have been deprecated in favour of using a template loader such as FileSystemLoader inside an Environment.

  • The use of whitespace inside variable filter expression is now deprecated.

    - {{ name | uppercase }}
    + {{ name|uppercase }}

Bug Fixes

  • Restores compatibility with ARM based platforms such as iOS. Stencil 0.7 introduced compilation errors due to using the Float80 type which is not available.

0.7.1 - 2016-11-30 17:14:14

Bug Fixes

  • Fixes an issue where using {% if %} statements which use operators would throw a syntax error.

- 2016-11-29 12:28:45

New documentation website: https://stencil.fuller.li


  • TemplateLoader has been renamed to FileSystemLoader. The loadTemplate(s) methods are now throwing and now take labels for the name and names arguments.
  • Many internal classes are no longer public. Some APIs were previously accessible due to earlier versions of Swift requiring the types to be public to be able to test. Now we have access to @testable these can correctly be private.
  • {% ifnot %} tag is now deprecated, please use {% if not %} instead.


  • Variable lookup now supports introspection of Swift types. You can now lookup values of Swift structures and classes inside a Context.

  • If tags can now use prefix and infix operators such as not, and, or, ==, !=, >, >=, < and <=.

      {% if one or two and not three %}
  • You may now register custom template filters which make use of arguments.

  • There is now a default filter.

    Hello {{ name|default:"World" }}
  • There is now a join filter.

    {{ value|join:", " }}
  • {% for %} tag now supports filters.

    {% for user in non_admins|default:admins %}
      {{ user }}
    {% endfor %}

Bug Fixes

  • Variables ({{ variable.5 }}) that reference an array index at an unknown index will now resolve to nil instead of causing a crash. #72
  • Templates can now extend templates that extend other templates. #60
  • If comparisons will now treat 0 and below numbers as negative.

0.6.0 - 2016-09-13 19:29:34


  • Adds support for Swift 3.0.

0.6.0-beta.1 - 2016-04-04 20:44:55


  • Namespaces are now included in contexts so that template tags can make use of the namespace and pass it down to subsequent temples.

- 2016-02-26 21:51:37

Bug Fixes

  • Fixes issues resolving variables on Linux.

0.5.1 - 2015-12-08 18:10:43

Bug Fixes
  • Fixes an issue where the SPM dependency on PathKit wouldn't have Linux support.

0.5.0 - 2015-12-08 16:15:54

Breaking Change
  • This version moves filters and tags to "namespaces", please consult the README for more information.
  • Stencil can now be used with the Swift Package Manager (SPM).
  • Stencil now support Linux.

- 2015-10-30 19:36:57

  • This version of Stencil introduces template filters, allowing you to transform a variable.

    {{ variable|uppercase }}

- 2015-10-26 15:18:22

Initial release.

- 2015-10-26 15:18:06

  • Adds support for running Stencil from Objective-C.

- 2015-10-26 15:16:11

This release adds support for Swift 1.2.

  • Adds the following template tags used for inheritance:
    • {% include "foo.html" %}
    • {% extends "base.html" %}

- 2015-10-26 15:07:33

This release adds Swift 2.0 support along with changing the complete API so that instead of returning a Result-like type, we will either throw or return the appropriate value.