Getting started | Scriban
This guide walks you through installing Scriban, writing your first template, and rendering output from C#.
Installation
Scriban is available as a NuGet package. Add it to your project with:
dotnet add package Scriban
Scriban targets .NET Standard 2.0+, so it works with .NET 6, .NET 7, .NET 8, .NET 9, .NET 10, .NET Framework 4.7.2+, and more.
Your first template
Scriban templates mix plain text with code blocks enclosed in {{ and }}:
using Scriban;
var template = Template.Parse("Hello {{ name }}!");
var result = template.Render(new { Name = "World" });
Console.WriteLine(result);
// Output: Hello World!
That's it - three lines to parse, render, and output a template.
How it works
Template.Parsecompiles the template string into an internal AST (Abstract Syntax Tree).template.Renderevaluates the AST with the given model and produces a string.- Properties on the model (like
Name) are automatically exposed as lowercase/snake_case variables (name). See Member renamer to customize this.
Passing data to templates
Anonymous objects
The simplest way to pass data:
var template = Template.Parse("{{ product.name }} costs {{ product.price }}€");
var result = template.Render(new {
Product = new { Name = "Widget", Price = 9.99 }
});
// Output: Widget costs 9.99€
Dictionaries via ScriptObject
For dynamic data, use ScriptObject:
using Scriban;
using Scriban.Runtime;
var template = Template.Parse("Hello {{ name }}, you are {{ age }} years old.");
var scriptObject = new ScriptObject();
scriptObject["name"] = "Alice";
scriptObject["age"] = 30;
var context = new TemplateContext();
context.PushGlobal(scriptObject);
var result = template.Render(context);
// Output: Hello Alice, you are 30 years old.
Using loops and conditions
Scriban supports full control flow:
<ul>
{{ for product in products }}
<li>{{ product.name }} - {{ product.price }}€</li>
{{ end }}
</ul>
var template = Template.Parse(@"<ul>
{{ for product in products }}
<li>{{ product.name }} - {{ product.price }}€</li>
{{ end }}
</ul>");
var result = template.Render(new {
Products = new[] {
new { Name = "Apple", Price = 1.20 },
new { Name = "Banana", Price = 0.80 },
new { Name = "Cherry", Price = 2.50 }
}
});
Output:
<ul>
<li>Apple - 1.2€</li>
<li>Banana - 0.8€</li>
<li>Cherry - 2.5€</li>
</ul>
Using built-in functions
Scriban comes with a rich set of built-in functions for strings, arrays, dates, math, and more. Use the pipe operator | to apply them:
{{ "hello world" | string.capitalize }}
Output: Hello world
{{ [3, 1, 4, 1, 5] | array.sort | array.join ", " }}
Output: 1, 1, 3, 4, 5
{{ date.now | date.to_string '%Y-%m-%d' }}
Output: 2026-02-20 (current date)
Pipes and chaining
You can chain multiple functions with pipes, just like Unix shell commands:
{{ "hello beautiful world" | string.split ' ' | array.reverse | array.join ' ' }}
Output: world beautiful hello
Conditionals
{{ if user.is_admin }}
<p>Welcome, admin!</p>
{{ else }}
<p>Welcome, {{ user.name }}!</p>
{{ end }}
Liquid compatibility
If you are coming from Liquid, Scriban can parse Liquid templates directly:
var template = Template.ParseLiquid("Hello {{ name }}!");
var result = template.Render(new { Name = "World" });
// Output: Hello World!
See the Liquid support guide for the full mapping between Liquid and Scriban syntax.
Async rendering
Scriban fully supports async/await:
var template = Template.Parse("Hello {{ name }}!");
var result = await template.RenderAsync(new { Name = "World" });
This is useful in web applications where you want non-blocking template rendering.
Error handling
Always check for parsing errors before rendering:
var template = Template.Parse("Hello {{ name }");
if (template.HasErrors)
{
foreach (var message in template.Messages)
{
Console.WriteLine(message);
}
}
else
{
var result = template.Render(new { Name = "World" });
Console.WriteLine(result);
}
Scriban provides precise error messages with line and column numbers.
Source embedding
Starting with Scriban 3.2.1+, you can embed Scriban sources directly into your project instead of referencing the NuGet package as a library. This is useful in contexts where NuGet references are not convenient (e.g., Roslyn Source Generators).
To enable source embedding, make sure your project compiles the embedded sources with C# 9 or later and nullable annotations enabled:
<PropertyGroup>
<PackageScribanIncludeSource>true</PackageScribanIncludeSource>
<LangVersion>9.0</LangVersion>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Scriban" Version="6.5.0" IncludeAssets="Build"/>
</ItemGroup>
What's next?
- Language reference - Learn all the syntax: variables, expressions, loops, functions, and more.
- Built-in functions - Explore the full list of string, array, date, math, and other functions.
- Runtime API - Dive deeper into
TemplateContext,ScriptObject, custom functions, and advanced scenarios. - Liquid support - Migrate from Liquid or use Liquid templates with Scriban.