Templar supports loading templates from external sources like GitHub repositories. This enables sharing template libraries across projects while maintaining explicit dependency management and reproducible builds.
┌─────────────────────────────────────────────────────────────────────────────┐
│ Your Project │
│ │
│ templates/ │
│ ├── pages/ │
│ │ └── dashboard.html ──► {{# namespace "EL" "@goapplib/..." #}} │
│ └── components/ │
│ └── custom.html │
│ │
│ templar.yaml ──► sources: │
│ goapplib: │
│ url: github.com/panyam/goapplib │
│ path: templates │
│ ref: v1.2.0 │
│ │
│ templar_modules/ ──► Vendored dependencies (after templar get) │
│ └── github.com/ │
│ └── panyam/ │
│ └── goapplib/ │
│ └── templates/ │
│ └── EntityListing.html │
└─────────────────────────────────────────────────────────────────────────────┘
Create a templar.yaml in your project root:
# Define external template sources
sources:
goapplib:
url: github.com/panyam/goapplib
path: templates # Subdirectory within repo
ref: v1.2.0 # Tag, branch, or commit hash
shared:
url: github.com/myorg/shared-templates
ref: main
# Where vendored templates are stored
vendor_dir: ./templar_modules
# Template search paths (in order)
search_paths:
- ./templates # Local templates first
- ./templar_modules # Then vendored dependenciestemplar getThis downloads all configured sources to templar_modules/:
templar_modules/
├── github.com/
│ ├── panyam/
│ │ └── goapplib/
│ │ └── templates/
│ │ ├── EntityListing.html
│ │ └── components/
│ │ └── Grid.html
│ └── myorg/
│ └── shared-templates/
│ └── ...
└── templar.lock # Lock file with exact versions
Reference external templates with the @sourcename prefix:
{{# namespace "EL" "@goapplib/components/EntityListing.html" #}}
{{# include "@shared/layouts/base.html" #}}
{{ define "MyPage" }}
{{ template "EL:EntityListing" .Items }}
{{ end }}┌─────────────────────────────────────────────────────────────────────────────┐
│ Reference Syntax │
│ │
│ ┌────────────────────────┬─────────────────────────────────────────────┐ │
│ │ Syntax │ Resolution │ │
│ ├────────────────────────┼─────────────────────────────────────────────┤ │
│ │ "@goapplib/foo.html" │ Vendored: templar_modules/.../foo.html │ │
│ │ "./components/bar.html"│ Relative to current template │ │
│ │ "layouts/base.html" │ Searched in search_paths order │ │
│ └────────────────────────┴─────────────────────────────────────────────┘ │
│ │
│ The @ prefix maps to a configured source in templar.yaml │
└─────────────────────────────────────────────────────────────────────────────┘
With this configuration:
sources:
goapplib:
url: github.com/panyam/goapplib
path: templates
ref: v1.2.0This template reference:
{{# namespace "EL" "@goapplib/components/EntityListing.html" #}}Resolves to:
./templar_modules/github.com/panyam/goapplib/templates/components/EntityListing.html
# Create templar.yaml in current directory
templar init
# Overwrite existing configuration
templar init --forceThis creates a minimal templar.yaml with sensible defaults and a templates/ directory.
# Fetch all configured sources
templar get
# Update to latest versions matching refs
templar get --update
# Fetch only a specific source
templar get @goapplib
# Verify local files match lock file
templar get --verify
# Show what would be fetched (dry run)
templar get --dry-run# Show configured sources and their status
templar sources
# Output:
# SOURCE URL REF STATUS
# goapplib github.com/panyam/goapplib v1.2.0 ✓ vendored (abc123)
# shared github.com/myorg/shared-templates main ✗ not fetched# External template sources
sources:
# Source name (used with @ prefix in templates)
goapplib:
# Repository URL (GitHub shorthand supported)
url: github.com/panyam/goapplib
# Subdirectory within repo containing templates (optional)
path: templates
# Git ref: tag, branch, or commit hash
ref: v1.2.0
# Another source example
company-templates:
url: github.com/mycompany/templates
ref: main
# Directory for vendored templates (default: ./templar_modules)
vendor_dir: ./templar_modules
# Template search paths (in order of priority)
search_paths:
- ./templates # Check local first
- ./templar_modules # Then check vendored
# Optional: Require lock file for reproducible builds
require_lock: trueAuto-generated lock file with exact versions:
# AUTO-GENERATED - Do not edit manually
# Run 'templar get' to regenerate
version: 1
sources:
goapplib:
url: github.com/panyam/goapplib
ref: v1.2.0
resolved_commit: abc123def456789...
fetched_at: 2024-12-08T10:30:00Z
shared:
url: github.com/myorg/shared-templates
ref: main
resolved_commit: def456abc789012...
fetched_at: 2024-12-08T10:30:05ZCheck vendored templates into version control for reproducible builds:
┌─────────────────────────────────────────────────────────────────────────────┐
│ Development │
│ │
│ 1. templar get # Fetch dependencies │
│ 2. git add templar_modules/ # Check in vendored files │
│ 3. git add templar.lock # Check in lock file │
│ 4. git commit │
│ │
├─────────────────────────────────────────────────────────────────────────────┤
│ Production │
│ │
│ 1. git clone / pull # Get code + vendored templates │
│ 2. go build # Build app │
│ 3. ./app # Run - no network needed │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Pros:
- Reproducible builds without network access
- See template changes in diffs during code review
- No external service dependencies during build
Cons:
- Larger repository size
- Potential merge conflicts when updating
Check in only the lock file, fetch during build:
┌─────────────────────────────────────────────────────────────────────────────┐
│ Development │
│ │
│ 1. templar get # Fetch dependencies │
│ 2. git add templar.lock # Only check in lock file │
│ 3. echo "templar_modules/" >> .gitignore │
│ 4. git commit │
│ │
├─────────────────────────────────────────────────────────────────────────────┤
│ CI / Production Build │
│ │
│ 1. git clone / pull │
│ 2. templar get # Fetch using lock file │
│ 3. go build │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Pros:
- Smaller repository
- No merge conflicts on vendored files
Cons:
- Requires network during build
- Depends on external service availability
Generate vendored files in CI, cache or artifact them:
# .github/workflows/build.yml
jobs:
build:
steps:
- uses: actions/checkout@v4
- name: Cache templar modules
uses: actions/cache@v4
with:
path: templar_modules
key: templar-${{ hashFiles('templar.lock') }}
- name: Fetch templates
run: templar get --verify || templar get
- name: Build
run: go build ./...┌─────────────────────────────────────────────────────────────────────────────┐
│ Concept │ Go Modules │ Templar Vendoring │
├───────────────────────┼─────────────────────┼───────────────────────────────┤
│ Config file │ go.mod │ templar.yaml │
│ Lock file │ go.sum │ templar.lock │
│ Fetch command │ go mod download │ templar get │
│ Update command │ go get -u │ templar get --update │
│ Vendor command │ go mod vendor │ (automatic with get) │
│ Vendor directory │ vendor/ │ templar_modules/ │
│ Reference syntax │ import "pkg/..." │ @source/path/... │
└─────────────────────────────────────────────────────────────────────────────┘
myapp/
├── templar.yaml
├── templar.lock
├── templates/
│ ├── pages/
│ │ └── product-list.html
│ └── base.html
└── templar_modules/
└── github.com/
└── example/
└── uikit/
└── templates/
└── components/
└── card.html
sources:
uikit:
url: github.com/example/uikit
path: templates
ref: v1.0.0
vendor_dir: ./templar_modules
search_paths:
- ./templates
- ./templar_modules{{# include "base.html" #}}
{{# namespace "UI" "@uikit/components/card.html" #}}
{{/* Custom product card preview - shows product image */}}
{{ define "productPreview" }}
{{ if .ImageUrl }}
<img src="{{ .ImageUrl }}" alt="{{ .Name }}" class="w-full h-32 object-cover">
{{ else }}
<div class="w-full h-32 bg-gray-200 flex items-center justify-center">
<span class="text-gray-400">No image</span>
</div>
{{ end }}
{{ end }}
{{/* Extend Card to use product-specific preview */}}
{{# extend "UI:Card" "ProductCard"
"UI:CardPreview" "productPreview" #}}
{{# extend "UI:CardGrid" "ProductGrid"
"UI:Card" "ProductCard" #}}
{{ define "content" }}
<main class="max-w-7xl mx-auto px-4 py-8">
<h1>Products</h1>
{{ template "ProductGrid" .Products }}
</main>
{{ end }}
{{ define "ProductListPage" }}
{{ template "base" . }}
{{ end }}package main
import (
"github.com/panyam/templar"
)
func main() {
// Create SourceLoader with configuration
config := &templar.VendorConfig{
Sources: map[string]templar.SourceConfig{
"uikit": {
URL: "github.com/example/uikit",
Path: "templates",
Ref: "v1.0.0",
},
},
VendorDir: "./templar_modules",
SearchPaths: []string{"./templates"},
}
group := templar.NewTemplateGroup()
group.Loader = templar.NewSourceLoader(config)
// Load template - @uikit references resolve automatically
tmpl := group.MustLoad("pages/product-list.html", "")
// Render
group.RenderHtmlTemplate(w, tmpl[0], "ProductListPage", data, nil)
}If vendored files aren't checked in, fetch them before building:
git clone myrepo
cd myrepo
templar get # Fetch dependencies
go build ./...Even if you check in templar_modules/, the lock file ensures:
- Exact commit hashes are recorded
templar get --verifycan validate local files- Reproducible fetches if re-vendoring is needed
# Avoid (unstable):
sources:
lib:
url: github.com/example/lib
ref: main # May change unexpectedly
# Prefer (stable):
sources:
lib:
url: github.com/example/lib
ref: v1.2.3 # Specific version
# or
ref: abc123def # Specific commit{{/* WRONG - looks in search_paths */}}
{{# namespace "EL" "goapplib/components/EntityListing.html" #}}
{{/* CORRECT - looks up source "goapplib" */}}
{{# namespace "EL" "@goapplib/components/EntityListing.html" #}}sources:
GoAppLib: # This name...
url: ...{{/* Must match exactly */}}
{{# namespace "EL" "@GoAppLib/..." #}} {{/* Correct */}}
{{# namespace "EL" "@goapplib/..." #}} {{/* Wrong - case mismatch */}}# See how a template path resolves
templar debug --trace templates/pages/WorldListingPage.html
# Output shows resolution chain:
# @goapplib/components/EntityListing.html
# → source: goapplib
# → url: github.com/panyam/goapplib
# → path: templates
# → resolved: templar_modules/github.com/panyam/goapplib/templates/components/EntityListing.html# Check if local files match lock file
templar get --verify
# Output:
# ✓ goapplib: matches lock (abc123def)
# ✗ shared: modified locally (expected def456, found ghi789)templar get --dry-run
# Output:
# Would fetch:
# goapplib: github.com/panyam/goapplib@v1.2.0 → templar_modules/...
# shared: github.com/myorg/shared@main → templar_modules/...When using templar as a library in another tool, all file names and generated content are customizable via ToolInfo. The WithNames, WithDefaults, and For function variants accept a ToolInfo to override templar's defaults. See the Integration Guide for details.