Open-source project
open2b/scriggo avatar
open2b/scriggo

Scriggo puts a Go interpreter and a template engine in one library

The world’s most powerful template engine and Go embeddable interpreter

577 stars29 forksGoBSD-3-Clause

At a glance

What is it?
Scriggo is a pure Go embeddable interpreter that also acts as a template engine with Go as the scripting language, supporting inheritance, macros, partials, contextual autoescaping and native Markdown. It suits a Go application that wants to run user or tenant supplied templates and code in process, and it is a library rather than a hosted runtime.
Who is it for?
Adopt Scriggo when your Go application must execute templates or scripts supplied by users, tenants or configuration, and you want the scripting language to be Go rather than a second language. Skip it if you only need a static template renderer, since the interpreter is the heavier part of the dependency.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 161 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One library does two jobs, and the interpreter is the harder half

Scriggo is described as a Go embeddable interpreter and a template engine in the same package, and the feature list makes the emphasis clear. It is a fast, very fast embeddable pure Go language interpreter, a modern and powerful template engine with Go as the scripting language, with native support for Markdown in templates, secure by default with no access to packages unless explicitly enabled, and easy to embed and to interop with any Go application. The repository layout backs this up. There are separate top level files for the two halves, programs.go and templates.go, with a matching ast/ directory, an internal/ directory, and distinct builtin/ and native/ packages that supply the functions and declarations you can hand to the interpreter. A cmd/ directory and a playground/ directory sit alongside them, with highlighters/ for the template syntax and test/ plus several top level test files for the suite. The result is one dependency that covers a template engine and a sandboxed code runtime rather than two separate projects with a boundary between them.

Running a Go program from a file system in memory

The programs API is shown in one short example, and the shape matters. The source of the program is a byte slice held in the host application, it is placed into a scriggo.Files file system, the program is built with scriggo.Build, and it is then run. The whole example is this:

go
    fsys := scriggo.Files{"main.go": src}

    // Build the program.
    program, err := scriggo.Build(fsys, nil)
    if err != nil {
        panic(err)
    }

The point of the design is that the program never touches a real directory. The file system is a map of names to contents supplied by the caller, so the code being run is a string your application already has, and the build step compiles it before execution rather than interpreting it line by line. That also means errors surface as a build error, with a value you can inspect, instead of a partial run. The nil second argument is the options value, and passing nil is the simplest possible configuration, which is a reasonable default for a library whose selling point is embedding.

Templates use Go syntax with a template tag layer on top

In templates, Scriggo supports inheritance, macros, partials, imports and contextual autoescaping, and most of all it uses the Go language as the template scripting language. The example in the README is a compact illustration of the whole feature set:

html
{% extends "layout.html" %}
{% import "banners.html" %}
{% macro Body %}
    <ul>
      {% for product in products %}
      <li><a href="{{ product.URL }}">{{ product.Name }}</a></li>
      {% end %}
    </ul>
    {{ render "pagination.html" }}
    {{ Banner() }}
{% end %}

The structure is the familiar one. A template extends a layout, imports another template, defines a macro, loops over a collection, renders a partial and calls the imported macro. What is different from a typical template language is the expression language inside the tags, which is Go. That means a template author can write real control flow with real types rather than a restricted set of filters, and a host application can pass structured values into the template rather than pre-flattened strings. The autoescaping is contextual, so a value interpolated into an HTML attribute or into a script block is escaped for that context rather than for HTML in general.

The template file format is decided by the extension, not by the engine

Scriggo template files can be written in plain text, HTML, Markdown, CSS, JavaScript and JSON, and native support for Markdown in templates is a listed feature. The reason the engine can accept all of those is that the template is text and the template tags are a small syntactic layer over it, so the same tag vocabulary works in a Markdown document or a stylesheet as in an HTML page. For a Markdown template the engine has to know how to escape and how to interpret the surrounding document, which is where the Markdown support in the feature list comes from. The dependency list explains how much of that is standard library work: goldmark at v1.7.16 is the Markdown parser, fsnotify at v1.9.0 is the file watcher, and golang.org/x/tools is pulled in. The go.mod is otherwise small, with the module requiring Go 1.25.0, which tells you the project tracks recent Go releases rather than pinning itself to an old toolchain.

Security is the design constraint, and the default is closed

The feature list states it in one line, secure by default, no access to packages unless explicitly enabled. That is the single most important property of the library for anyone embedding it, because the code being run is supplied by a user, a tenant or a configuration file rather than by you. Nothing is reachable until you name it, which means the host application decides the whole surface, both the packages and the functions. The mechanism for that is visible in the templates example, where a build options value carries Globals as a native.Declarations map that binds a variable and a function by name into the template's scope, using the builtin package for the standard functions. The same pattern applies to programs, where the options value governs what the interpreted code can reach. The cost of that safety is that a template author cannot import anything without the host agreeing to it, so the deployment question is really a question about your own configuration surface.

Where Scriggo is the wrong choice

Three situations argue against it. The first is a project that only needs to render a template. Scriggo's value comes from the two halves being one library, but if you are not running code, you are paying for an interpreter you never use, and a Go template package or a text or template implementation does the job with less to understand. The second is a case where the code being executed must reach into the host in ways the sandbox model makes awkward. Sandboxing that is safe by default means every capability has to be granted explicitly, and a template that wants to do something the host did not anticipate simply cannot, which is correct behaviour and also a source of friction in a system where the template author and the host author are the same team. The third is an environment where running untrusted code in your own process is not acceptable at all, because Scriggo embeds the interpreter into your binary and shares its address space, so a bug in the interpreter or in the bindings of a native function is a bug in your application. The realistic alternative for that case is to run the code in a separate process or a sandbox with a narrow protocol, which gives up the in-process performance but contains the blast radius. Scriggo is a good fit precisely where the trade is worth making, a hosting platform that wants tenant templates without paying for a container per request.

Editorial conclusion

Adopt Scriggo when your Go application must execute templates or scripts supplied by users, tenants or configuration, and you want the scripting language to be Go rather than a second language. Skip it if you only need a static template renderer, since the interpreter is the heavier part of the dependency. Verify first which packages and builtins your templates need, because Scriggo grants no access to packages unless they are explicitly enabled, and check the compatibility notes for the Go version your templates are written against before shipping them.

Frequently asked questions

What is Scriggo?

It is a pure Go embeddable language interpreter and a template engine in one library, with Go as the template scripting language. The feature list describes it as fast, secure by default with no access to packages unless explicitly enabled, and easy to embed and interop with any Go application.

How do you run a Go program from inside a Go application?

Put the program source into a scriggo.Files file system, build it with scriggo.Build, and run it with the built program. The example in the README uses scriggo.Files{"main.go": src} and the program source is held as a byte slice in the host application, so nothing is read from a real directory.

Which template features does Scriggo support?

Inheritance, macros, partials, imports and contextual autoescaping, with Go as the scripting language. Template files can be written in plain text, HTML, Markdown, CSS, JavaScript and JSON, and Markdown is supported natively in templates.

How does Scriggo control what templates and programs can access?

There is no access to packages unless it is explicitly enabled, and the host grants capabilities through build options, as in the template example where native.Declarations binds a global variable and a builtin function by name into the template scope.

Is Scriggo still maintained?

The repository is not archived and the last push was on 2026-05-15, with releases v0.61.1 from 2026-03-13, v0.61.0 from 2026-03-04 and v0.60.0 from 2025-02-17. The licence is BSD-3-Clause, the module requires Go 1.25.0, and the project links a get started guide, documentation and a discussions page on the Scriggo site.

Official sources

  1. License: BSD-3-Clause
  2. open2b/scriggo on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/open2b-scriggo.svg)](https://hysenlabs.com/projects/open2b-scriggo)

Was this useful?