Skip to content

@withstudiocms/template-lang

StudioCMS comes with its own custom template language that is similar in syntax to popular templating languages like Handlebars^ or Liquid^. This template language allows you to create dynamic and reusable templates in different parts of the StudioCMS dashboard, such as in the Mail Templates system, or in custom plugins that you may develop.

@withstudiocms/template-lang is a simple MIT Licensed TypeScript ESM template language for HTML emails, similar to Handlebars but focused on simplicity and database data integration.

  • Simple {{variable}} syntax for variable interpolation
  • Support for nested properties with dot notation ({{user.name}})
  • TypeScript with full ESM support
  • Strict mode for error handling
  • Designed specifically for email templates and DB data
  • Zero dependencies

Perfect for:

  • HTML email templates
  • Dynamic content generation from database data
  • Simple templating needs without complex logic
  • ESM-first TypeScript projects

For those interested in using the StudioCMS template language in their projects, you can install using your preferred package manager:

Terminal window
npm i @withstudiocms/template-lang

Similar to other templating languages, StudioCMS’s template language uses double curly braces {{ }} to denote variables that should be replaced with actual data when the template is rendered.

Unlike some other templating languages, StudioCMS’s template language focuses on simplicity and does not include complex logic or control structures. It is primarily designed for straightforward variable interpolation.

<h1>Hello {{user.firstName}} {{user.lastName}}!</h1>
<p>Your order #{{order.id}} total is ${{order.total}}</p>
<p>Shipping to: {{user.address.street}}, {{user.address.city}}</p>
basic-usage.ts
import
class TemplateEngine

Main template engine class that provides a simple API for template rendering

TemplateEngine
from '@withstudiocms/template-lang';
const
const engine: TemplateEngine
engine
= new
new TemplateEngine(options?: TemplateOptions): TemplateEngine

Main template engine class that provides a simple API for template rendering

TemplateEngine
();
const
const template: "Hello {{name}}! Welcome to {{company.name}}."
template
= "Hello {{name}}! Welcome to {{company.name}}.";
const
const data: {
name: string;
company: {
name: string;
};
}
data
= {
name: string
name
: "John Doe",
company: {
name: string;
}
company
: {
name: string
name
: "Acme Corp"
}
};
const
const result: string
result
=
const engine: TemplateEngine
engine
.
TemplateEngine.render(template: string, data: TemplateData): string

Render a template string with data

@paramtemplate The template string containing {{variable}} placeholders

@paramdata The data context for variable replacement

@returnsThe rendered template string

render
(
const template: "Hello {{name}}! Welcome to {{company.name}}."
template
,
const data: {
name: string;
company: {
name: string;
};
}
data
);
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
(
const result: string
result
); // "Hello John Doe! Welcome to Acme Corp."
email-template.ts
import
class TemplateEngine

Main template engine class that provides a simple API for template rendering

TemplateEngine
from '@withstudiocms/template-lang';
const
const engine: TemplateEngine
engine
= new
new TemplateEngine(options?: TemplateOptions): TemplateEngine

Main template engine class that provides a simple API for template rendering

TemplateEngine
();
const
const emailTemplate: "\n<!DOCTYPE html>\n<html>\n<head>\n <title>{{subject}}</title>\n</head>\n<body>\n <h1>Hello {{user.name}}!</h1>\n <p>Your order #{{order.id}} has been confirmed.</p>\n <p>Total: {{order.total}}</p>\n</body>\n</html>\n"
emailTemplate
= `
<!DOCTYPE html>
<html>
<head>
<title>{{subject}}</title>
</head>
<body>
<h1>Hello {{user.name}}!</h1>
<p>Your order #{{order.id}} has been confirmed.</p>
<p>Total: {{order.total}}</p>
</body>
</html>
`;
const
const data: {
subject: string;
user: {
name: string;
};
order: {
id: string;
total: string;
};
}
data
= {
subject: string
subject
: "Order Confirmation",
user: {
name: string;
}
user
: {
name: string
name
: "John Doe" },
order: {
id: string;
total: string;
}
order
: {
id: string
id
: "12345",
total: string
total
: "99.99" }
};
const
const html: string
html
=
const engine: TemplateEngine
engine
.
TemplateEngine.render(template: string, data: TemplateData): string

Render a template string with data

@paramtemplate The template string containing {{variable}} placeholders

@paramdata The data context for variable replacement

@returnsThe rendered template string

render
(
const emailTemplate: "\n<!DOCTYPE html>\n<html>\n<head>\n <title>{{subject}}</title>\n</head>\n<body>\n <h1>Hello {{user.name}}!</h1>\n <p>Your order #{{order.id}} has been confirmed.</p>\n <p>Total: {{order.total}}</p>\n</body>\n</html>\n"
emailTemplate
,
const data: {
subject: string;
user: {
name: string;
};
order: {
id: string;
total: string;
};
}
data
);
strict-mode.ts
import
class TemplateEngine

Main template engine class that provides a simple API for template rendering

TemplateEngine
from '@withstudiocms/template-lang';
const
const strictEngine: TemplateEngine
strictEngine
= new
new TemplateEngine(options?: TemplateOptions): TemplateEngine

Main template engine class that provides a simple API for template rendering

TemplateEngine
({
TemplateOptions.strict?: boolean

Whether to throw an error when a variable is not found in the data

@defaultfalse

strict
: true });
// This will throw an error if 'missingVar' is not in data
try {
const
const result: string
result
=
const strictEngine: TemplateEngine
strictEngine
.
TemplateEngine.render(template: string, data: TemplateData): string

Render a template string with data

@paramtemplate The template string containing {{variable}} placeholders

@paramdata The data context for variable replacement

@returnsThe rendered template string

render
("Hello {{missingVar}}!", {});
} catch (
var error: unknown
error
) {
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
("Variable not found:", (
var error: unknown
error
as
interface Error
Error
).
Error.message: string
message
);
}
default-values.ts
import
class TemplateEngine

Main template engine class that provides a simple API for template rendering

TemplateEngine
from '@withstudiocms/template-lang';
const
const engine: TemplateEngine
engine
= new
new TemplateEngine(options?: TemplateOptions): TemplateEngine

Main template engine class that provides a simple API for template rendering

TemplateEngine
({
TemplateOptions.defaultValue?: string

Default value to use when a variable is not found and strict is false

@default''

defaultValue
: "[NOT SET]" });
const
const result: string
result
=
const engine: TemplateEngine
engine
.
TemplateEngine.render(template: string, data: TemplateData): string

Render a template string with data

@paramtemplate The template string containing {{variable}} placeholders

@paramdata The data context for variable replacement

@returnsThe rendered template string

render
("Hello {{name}}!", {});
// Result: "Hello [NOT SET]!"
template-compilation.ts
import
class TemplateEngine

Main template engine class that provides a simple API for template rendering

TemplateEngine
from '@withstudiocms/template-lang';
const
const engine: TemplateEngine
engine
= new
new TemplateEngine(options?: TemplateOptions): TemplateEngine

Main template engine class that provides a simple API for template rendering

TemplateEngine
();
// Compile once, use multiple times
const
const compiled: (data: TemplateData) => string
compiled
=
const engine: TemplateEngine
engine
.
TemplateEngine.compile(template: string): (data: TemplateData) => string

Create a template function that can be reused with different data

@paramtemplate The template string

@returnsA function that takes data and returns rendered template

compile
("Hello {{name}}!");
const
const result1: string
result1
=
const compiled: (data: TemplateData) => string
compiled
({
name: string
name
: "Alice" });
const
const result2: string
result2
=
const compiled: (data: TemplateData) => string
compiled
({
name: string
name
: "Bob" });
new TemplateEngine(options?: TemplateOptions)

render(template: string, data: TemplateData): string Renders a template with the provided data.

compile(template: string): (data: TemplateData) => string Compiles a template into a reusable function.

hasVariables(template: string): boolean Checks if a template contains any variables.

getVariables(template: string): string[] Returns an array of all variable names in the template.

setOptions(options: Partial<TemplateOptions>): void Updates the engine options.

interface TemplateOptions {
strict?: boolean; // Throw error on missing variables (default: false)
defaultValue?: string; // Default value for missing variables (default: '')
}