Skip to content

Embedding Boilerplate

Boilerplate is published as a Go module and can be driven directly from another program. This page covers two embedding paths: importing the Go packages, and running the WebAssembly build from a browser or Node.js host.

Import the packages you need under github.com/gruntwork-io/boilerplate/.... The two entry points used most often are templates.ProcessTemplateWithContext for end-to-end rendering and render.RenderTemplateFromString for one-off string rendering.

Boilerplate emits diagnostic output through the pkg/logging package. The logger is passed explicitly into every public API as the first parameter (or right after context.Context when present, by convention named l), so library callers control writer and level on a per-call basis without touching any global state.

import (
"context"
"os"
"github.com/gruntwork-io/boilerplate/options"
"github.com/gruntwork-io/boilerplate/pkg/logging"
"github.com/gruntwork-io/boilerplate/templates"
"github.com/gruntwork-io/boilerplate/variables"
)
// Match CLI defaults: Info level, written to os.Stdout, with the "[boilerplate] " prefix and a
// stdlib timestamp.
l := logging.New(os.Stdout, logging.LevelInfo)
opts := &options.BoilerplateOptions{ /* ... */ }
_, err := templates.ProcessTemplateWithContext(context.Background(), l, opts, opts, &variables.Dependency{})

The package exposes:

SymbolPurpose
New(io.Writer, Level) LoggerConstruct a logger. Panics on a nil writer.
Discard() LoggerA logger that drops every record. Useful in tests or when boilerplate should stay silent.
LoggerInterface with Debugf / Infof / Warnf / Errorf. Implement it directly to forward records into your own structured logger.
LevelSeverity, with LevelDebug, LevelInfo, LevelWarn, LevelError.

The returned Logger is immutable. To change writer or level, construct a new one. Each level method emits exactly one log record per call, so a writer set on New receives one Write per record and may split on writes without re-buffering.

Levels are ordered LevelDebug < LevelInfo < LevelWarn < LevelError. At LevelInfo, boilerplate stays mostly quiet: per-file activity, variable resolution, and shell-execution narration are emitted at LevelDebug. Warnings (declined shell prompts, missing config files, checksum fallbacks) and errors (failed cleanup, glob failures) still surface.

Implement logging.Logger directly against your destination logger to bypass the text format entirely.

import "log/slog"
type slogAdapter struct{ dst *slog.Logger }
func (a *slogAdapter) Debugf(format string, args ...any) { a.dst.Debug(fmt.Sprintf(format, args...)) }
func (a *slogAdapter) Infof(format string, args ...any) { a.dst.Info(fmt.Sprintf(format, args...)) }
func (a *slogAdapter) Warnf(format string, args ...any) { a.dst.Warn(fmt.Sprintf(format, args...)) }
func (a *slogAdapter) Errorf(format string, args ...any) { a.dst.Error(fmt.Sprintf(format, args...)) }
l := &slogAdapter{dst: app.Logger}
_, err := templates.ProcessTemplateWithContext(ctx, l, opts, opts, &variables.Dependency{})

A direct Logger implementation is the cleanest path; New is the right choice when you want boilerplate’s exact text format on a writer of your choosing.

The repository ships a WebAssembly build of the rendering engine under cmd/wasm. It exposes a single global function, boilerplateRenderTemplate(templateStr, varsJSON), suitable for both browsers and Node.js. Shell helpers and interactive prompts are disabled in the WASM build, and config loading is set to ignore missing files.

From the repository root:

Terminal window
make wasm

That target compiles the WASM binary, compresses it with brotli, and copies Go’s wasm_exec.js runtime into examples/wasm/:

FileDescription
boilerplate.wasmUncompressed WASM binary
boilerplate.wasm.brBrotli-compressed binary
wasm_exec.jsGo WASM runtime support, copied from GOROOT

You will need a recent Go toolchain (see .mise.toml) and brotli available on PATH.

Try it: the editor below renders a Go template with the variables you provide, all client-side via the WASM build. The first render downloads the binary (cached by your browser thereafter).

The demo above is the WASM binary attached to the latest GitHub Release, served from the docs site. To run it in your own page, load wasm_exec.js, instantiate the WASM module, and call the global function. A complete runnable example lives in examples/wasm/browser/.

<script src="wasm_exec.js"></script>
<script>
const go = new Go();
WebAssembly.instantiateStreaming(fetch("boilerplate.wasm"), go.importObject).then((res) => {
go.run(res.instance);
const out = boilerplateRenderTemplate("Hello {{ .Name }}", JSON.stringify({ Name: "world" }));
console.log(out);
});
</script>

boilerplateRenderTemplate returns the rendered string on success, or a JavaScript Error if parsing the variables JSON fails or the template fails to render.

Node can load the same artifact through wasm_exec.js. See examples/wasm/node/ for a working script. The function signature is identical to the browser case.

  • Shell helpers (shell template function): always returns the disabled placeholder.
  • Interactive prompts: variables must be supplied through the varsJSON argument.
  • Remote template downloads via go-getter: only inline template strings are supported.
  • File-system writes: the function returns the rendered string; persisting it is the host’s responsibility.

If you need any of these, drive boilerplate from a Go process instead and use the library API described above.