This guide walks you through installing Scriban, writing your first template, and rendering output from C#.
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.
Tip: A signed variant is also available as
Scriban.Signed.
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.
Template.Parse compiles the template string into an internal AST (Abstract Syntax Tree).template.Render evaluates the AST with the given model and produces a string.Name) are automatically exposed as lowercase/snake_case variables (name). See Member renamer to customize this.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€
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.
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>
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)
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
{{ if user.is_admin }}
<p>Welcome, admin!</p>
{{ else }}
<p>Welcome, {{ user.name }}!</p>
{{ end }}
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.
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.
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.
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:
<PropertyGroup>
<PackageScribanIncludeSource>true</PackageScribanIncludeSource>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Scriban" Version="6.5.0" IncludeAssets="Build"/>
</ItemGroup>
Note: In source-embedding mode, all Scriban types become
internal.
TemplateContext, ScriptObject, custom functions, and advanced scenarios.