Base Project 
This section will walk you through building a nearly-empty stenciled project and teach you how blocks work. While the sample project here is very Golang-centric, stencil can be used for any language!
Step 0: Prerequisites 
This tutorial requires the following things installed on your machine:
- Git - Used by the 
stencilCLI, this is always required. - mise - This is not required usually, but the module we'll look at does require it.
 
Step 1: Install Stencil 
If you don't already have stencil installed, follow the documentation to install it.
Step 2: Create a stencil.yaml 
First start by creating a new directory for your application, this should generally match whatever the name for your application is going to be. We'll go with helloworld here.
mkdir helloworldA stencil.yaml is integral to running stencil. It defines the modules you're consuming and the arguments to pass to them.
Start with creating a basic stencil.yaml:
name: helloworld
arguments: {}
# Below is a list of modules to use for this application
# It should follow the following format:
# - name: <moduleImportPath>
#   version: "optional-version-to-pin-to"
modules: []Now run stencil, you should have... nothing! That's expected because we didn't define any modules yet.
helloworld ❯ stencil
INFO stencil 0.9.0
INFO Fetching dependencies
INFO Loading native extensions
INFO Rendering templates
INFO Writing template(s) to disk
INFO Running post-run command(s)
helloworld ❯ ls -alh
drwxr-xr-x 2 jaredallard jaredallard 4.0K Aug 29 19:51 .
drwxr-xr-x 8 jaredallard jaredallard 4.0K Aug 29 19:49 ..
-rw-r--r-- 1 jaredallard jaredallard   37 Aug 29 19:51 stencil.lock
-rw-r--r-- 1 jaredallard jaredallard   43 Aug 29 19:50 stencil.yamlNOTE
You'll notice there's a stencil.lock file here.
version: 0.9.0
modules: []
files: []This will keep track of what files were created by stencil and what created them, as well as the last ran version of your modules. This file is very important!
Step 3: Import a Module 
Now that we've created our first stencil application, you're going to want to import a module! Let's import the stencil-golang module. This module is for creating a Go service or CLI, but don't worry, you don't need to know Go for this example!
First, let's take a look at parameters exposed through stencil-golang. This can be done by looking at the manifest.yaml provided by it.
The full manifest can be found
name: github.com/rgst-io/stencil-golang
---
arguments:
  org:
    description: The Github organization to use for the project
    required: true
  library: <snip>
  copyrightHolder: <snip>
  license: <snip>
  commands: <snip>We can see that the org argument is required and that it should be the Github organization that our repository will live under. For now, since we're not pushing this anywhere, it can be anything. So, let's go with rgst-io.
name: helloworld
arguments:
  org: rgst-io
modules:
  - name: github.com/rgst-io/stencil-golangNow if we run stencil we'll see that we have some files!
helloworld ❯ stencil
INFO stencil 0.9.0
INFO Fetching dependencies
INFO  -> github.com/rgst-io/stencil-golang v1.0.0 (b81af6111ff23879d56faa735c428dc2e8ff45b5)
INFO Loading native extensions
INFO Rendering templates
INFO Writing template(s) to disk
INFO   -> Created LICENSE
INFO   -> Created .goreleaser.yaml
INFO   -> Created cmd/helloworld/helloworld.go
INFO   -> Created CONTRIBUTING.md
INFO   -> Created .github/workflows/release.yaml
INFO   -> Created .github/workflows/tests.yaml
INFO   -> Created .vscode/settings.json
INFO   -> Created .mise.toml
INFO   -> Created .github/scripts/get-next-version.sh
INFO   -> Created .github/settings.yml
INFO   -> Created .cliff.toml
INFO   -> Created .mise/tasks/changelog-release
INFO   -> Created package.json
INFO   -> Created .vscode/extensions.json
INFO   -> Created go.mod
INFO   -> Created .editorconfig
INFO   -> Created .gitignore
INFO   -> Created .vscode/common.code-snippets
INFO Running post-run command(s)
...
# Note: If you see an error about bun/prettier, simply run
# 'bun install' and re-run stencil. Sorry about that!
helloworld ❯ ls -alh
drwxr-xr-x 6 jaredallard jaredallard 4.0K Aug 29 19:58 .
drwxr-xr-x 8 jaredallard jaredallard 4.0K Aug 29 19:49 ..
-rw-r--r-- 1 jaredallard jaredallard 4.3K Aug 29 19:58 .cliff.toml
-rw-r--r-- 1 jaredallard jaredallard  185 Aug 29 19:58 .editorconfig
drwxr-xr-x 4 jaredallard jaredallard 4.0K Aug 29 19:58 .github
-rw-r--r-- 1 jaredallard jaredallard  583 Aug 29 19:58 .gitignore
-rw-r--r-- 1 jaredallard jaredallard 1.1K Aug 29 19:58 .goreleaser.yaml
drwxr-xr-x 3 jaredallard jaredallard 4.0K Aug 29 19:58 .mise
-rw-r--r-- 1 jaredallard jaredallard 1.3K Aug 29 19:58 .mise.toml
drwxr-xr-x 2 jaredallard jaredallard 4.0K Aug 29 19:58 .vscode
-rw-r--r-- 1 jaredallard jaredallard  217 Aug 29 19:58 CONTRIBUTING.md
-rw-r--r-- 1 jaredallard jaredallard  35K Aug 29 19:58 LICENSE
drwxr-xr-x 3 jaredallard jaredallard 4.0K Aug 29 19:58 cmd
-rw-r--r-- 1 jaredallard jaredallard   46 Aug 29 19:58 go.mod
-rw-r--r-- 1 jaredallard jaredallard  130 Aug 29 19:58 package.json
-rw-r--r-- 1 jaredallard jaredallard 2.4K Aug 29 19:58 stencil.lock
-rw-r--r-- 1 jaredallard jaredallard   96 Aug 29 19:58 stencil.yamlGreat, now we have all of these files! What stencil did was completely generate this application for us as well as integrate with mise to set up our toolchain.
Step 4: Modifying a Block 
One of the key features in stencil is the notion of "blocks". Modules expose a block where they want developers to modify the code. Let's look at the stencil-golang module to see what blocks are available.
Let's look at .goreleaser.yaml. This is a system for creating and releasing Go binaries. Opening the file, we can see something like this:
---
builds:
  - main: ./cmd/helloworld
    flags:
      - -trimpath
    ldflags:
      - -s
      - -w
      ## <<Stencil::Block(helloworldLdflags)>>
      ## <</Stencil::Block>>A normal customization that Go application do is add ldflags, which are linker-time modifications to variables. This is normally done with something like a version string.
Here, we could add our own version string injection inside of the block.
---
builds:
  - main: ./cmd/helloworld
    flags:
      - -trimpath
    ldflags:
      - -s
      - -w
      ## <<Stencil::Block(helloworldLdflags)>>
      - -X main.Version="myVersion"
      ## <</Stencil::Block>>Now, if you re-run stencil, you'll see that it updated the file, but did not change the contents. This is the "block" functionality that makes up the core of stencil. This allows you to generate your files, but most importantly keep them updated.
Reflection 
In all, we've created a stencil.yaml, added a module to it, ran stencil, and then modified the contents within a block. That's it! We've imported a base module and created some files, all without doing much of anything on our side. Hopefully that shows you the power of stencil.
For more resources be sure to dive into how to create a module to get insight on how to create a module.
