Templating with Handlebars

Sometimes static configuration files and templates are not enough to solve the real-life problems we might face. To help overcome those trickier challenges and avoid tedious and error-prone repeating of configuration, Takomo supports dynamic templating with Handlebars. All standard Handlebars features are available, which means you can use loops, if-conditions, partial includes, helpers, variables to streamline your configuration.

Stack and stack group configuration files are always processed as dynamic Handlebars templates. By default, stack template files in the templates directory are not treated as dynamic Handlebars templates, but you can enable it by using .hbs file extension.

Partials

Each file in the partials directory or its subdirectories can be used as a Handlebars partial.

Example

If the partials directory contains a file named my-partial.hbs, you can include it as a partial in a configuration file like so:

{{> my-partial.hbs }}

Helpers

Custom Handlebars helpers can be registered by adding .js files to the helpers directory. These files must be valid JavaScript files and export two properties: name and fn. The former is the name for the helper, and the latter is the actual helper function.

Example

If the helpers directory contains a file named to-upper-case.js with following contents:

helpers/to-upper-case.js
module.exports = {
name: "to-upper-case",
fn: (str) => str.toUpperCase(),
};

Then, it could be used in a template file like so:

Resources:
User:
Type: AWS::IAM::User
Properties:
UserName: {{ to-upper-case 'Roger Moore' }}

And the final template would look like this:

Resources:
User:
Type: AWS::IAM::User
Properties:
UserName: ROGER MOORE

Variables from Command Line

You can pass variables from command line using --var and --var-file options. Both options can be used multiple times. Variables are exposed via var variable.

Simple Named Variables

Use --var option to pass a single named variable from the command line.

Example: Named Variable

Provide a single variable named myVariable with value hello:

--var myVariable=hello

This variable can be used in configuration like so:

Resources:
LogGroup:
Type: AWS::Logs::LogGroup
LogGroupName: {{ var.myVariable }}

Variables from Files

Use --var-file option to load variables from a file. If the file extension is .json or .yml, the file is first parsed into an object which is then stored to a variable. If the file extension is something else, the contents are just read into a variable.

The variable name can be omitted for .yml and .json files as long as the file contents can be deserialized to an object. The deserialized object is then stored to the top-level of variables.

Example: Read File Contents to a Variable

If the project directory contains a file named commit.txt, we can read its contents into a variable named commitHash like so:

--var-file commitHash=commit.txt

Example: Deserialize File Contents to a Variable

Say, we have a file /home/variables.yml with valid YAML contents:

/home/variables.yml
name: James
age: 55
permissions:
- create
- delete
- update

We can deserialize its contents to a variable named myVariable like so:

--var-file person=/home/variables.yml

And then use the variable in the configuration like so:

parameters:
UserName: {{ var.person.name }}
UserAge: {{ var.person.age }}

Example: Deserialize File Contents to a Top-Level of Variables

Say, we have a file properties.json with valid JSON contents:

properties.json
{
"color: "red",
"foo": {
"bar": true
}
}

We can deserialize its contents to top-level of variables:

--var-file person=/home/variables.yml

And then use the variables in the configuration like so:

parameters:
Color: {{ var.color }}
FooBarEnabled: {{ var.foo.bar }}

Loading Order and Merging of Variables

Variables from files are loaded first in the order they are defined, and then the named variables also in the definition order. Variables defined later will override previously loaded variables with the same name. Complex variables are merged recursively.

Example: Overriding Variables

Say, we have a JSON file that defines some basic settings:

base.json
{
"color": "blue",
"width": 100,
"settings": {
"debug": true
}
}

We also have another file that contains environment-specific settings:

prod.json
{
"settings": {
"debug": false
}
}

We can load both settings files and also override and extend the loaded configuration using named variables:

--var-file base.json --var-file prod.json --var color=yellow --var height=200

The final variables object would look like this:

{
"color": "yellow",
"width": 100,
"height": 200,
"settings": {
"debug": false
}
}

Environment Variables

All system environment variables are exposed via the env variable.

Example

Printing the HOME environment variable somewhere in the configuration:

Home dir is {{ env.HOME }}

Variables Available in Files

Different files have their own available variables.

Stack Group Configuration

The following variables are available in stack group configuration files.

KeyTypeDescription
varobjectVariables from the command line.
envobjectEnvironment variables.
contextobjectAn object containing context variables.
context.projectDirstringCurrent project directory.
stackGroupobjectAn object representing the current stack group.
stackGroup.pathstringPath of the stack group.
stackGroup.pathSegmentsstring[]Path of the stack group split into an array using / as a separator.
stackGroup.namestringName of the stack group.

Stack Configuration

The following variables are available in stack configuration files.

KeyTypeDescription
varobjectVariables from the command line.
envobjectEnvironment variables.
contextobjectAn object containing context variables.
context.projectDirstringCurrent project directory.
stackGroupobjectAn object representing the stack group where the stack belongs to.
stackGroup.pathstringPath of the stack group.
stackGroup.pathSegmentsstring[]Path of the stack group split into an array using / as a separator.
stackGroup.namestringName of the stack group.
stackGroup.projectstringProject of the stack group.
stackGroup.regionsstringRegions of the stack group.
stackGroup.commandRolestringCommand role of the stack group.
stackGroup.capabilitiesstring[]Capabilities of the stack group.
stackGroup.isRootbooleanIs the stack group the root.
stackGroup.templateBucketobjectTemplate bucket configuration of the stack group.
stackGroup.templateBucket.namestringName of the template bucket.
stackGroup.templateBucket.keyPrefixstringKey prefix of the template bucket.
stackGroup.timeoutobjectTimeout configuration of the stack group.
stackGroup.timeout.createnumberCreate timeout in seconds.
stackGroup.timeout.updatenumberUpdate timeout in seconds.
stackGroup.dataobjectData object of the stack group.
stackGroup.tagsobjectStack tags of the stack group.
stackGroup.accountIdsstring[]Account ids of the stack group.
stackobjectAn object representing the stack.
stack.pathstringPath of the stack without the region specified.
stack.pathSegmentsstring[]Path of the stack without the region specified split into an array using / as a separator.
stack.configFileobjectAn object representing configuration file of the stack.
stack.configFile.namestringName of the stack configuration file without the file extension.
stack.configFile.basenamestringName of the stack configuration file including the file extension
stack.configFile.filePathstringFile path of the stack configuration file relative to stack directory.
stack.configFile.dirPathstringFile path to the directory containing the stack configuration file relative to stack directory.

CloudFormation Template

The following variables are available in CloudFormation template files with .hbs file extension.

KeyTypeDescription
varobjectVariables from the command line.
envobjectEnvironment variables.
contextobjectAn object containing context variables.
context.projectDirstringCurrent project directory.
hooksobjectAn object containing values returned by hooks
stackobjectAn object representing the current stack
stack.pathstringPath of the stack.
stack.pathSegmentsstring[]Path of the stack split into an array using / as a separator.
stack.projectstringProject of the stack.
stack.namestringName of the stack.
stack.regionstringRegion of the stack.
stack.commandRolestringCommand role of the stack.
stack.templatestringTemplate of the stack.
stack.templateBucketobjectTemplate bucket configuration of the stack.
stack.templateBucket.namestringName of the template bucket.
stack.templateBucket.keyPrefixstringKey prefix of the template bucket.
stack.timeoutobjectTimeout configuration of the stack.
stack.timeout.createnumberCreate timeout in seconds.
stack.timeout.updatenumberUpdate timeout in seconds.
stack.dataobjectData object of the stack.
stack.tagsobjectStack tags of the stack.
stack.accountIdsstring[]Account ids of the stack.
stack.dependsstring[]Dependencies of the stack.
stack.configFileobjectAn object representing configuration file of the stack.
stack.configFile.namestringName of the stack configuration file without the file extension.
stack.configFile.basenamestringName of the stack configuration file including the file extension
stack.configFile.filePathstringFile path of the stack configuration file relative to stack directory.
stack.configFile.dirPathstringFile path to the directory containing the stack configuration file relative to stack directory.