Introduction
Go templates provide a powerful way to generate dynamic content, whether for text-based output or rendering HTML pages. They are part of the standard library, making them efficient, secure, and easy to integrate into any Go application. With a simple yet flexible syntax, Go templates allow you to embed data, create reusable layouts, and structure content effectively. In this guide, we'll explore how to use templates, pass data, manage layouts, and solve common rendering challenges with practical examples.
Overview
In Go, there are two built-in packages for templating: text/template and html/template. The text/template package is used for generating plain text output, while html/template is specifically designed for rendering structured HTML. Both share the same syntax and features.
What You’ll Learn
- Basic syntax and how Go templates work
- Loading and rendering templates from the filesystem
- Using dynamic data in templates
- Implementing layouts and reusable components
- Building a simple Go server to render templates
Basics of Go Templates
A template in Go is a text file with placeholders that are replaced dynamically when rendered. These placeholders are written using {{ ... }} syntax.
Simple Example
// template
tmpl := "hey {{ .Word }}"
t, err := template.New("example").Parse(tmpl)
if err != nil {
log.Fatal(err)
}
err = t.Execute(os.Stdout, map[string]any{Word: "there"})
if err != nil {
log.Fatal(err)
}This will print out "hey there" in your terminal. While this works, it's not an ideal scenario.
Keeping templates as separate files makes them easier to manage, reuse, and update without modifying the Go code.
Loading Templates from Filesystem
Create a file called example.tmpl inside templates, i.e. templates/example.tmpl.
contents of example.tmpl
hello {{ .Word }}The placeholder "Word" will be replaced with whatever we pass in as data while executing this template.
// Make sure imports are correct.
import (
"os"
"log"
"text/template"
)
tmpls := template.Must(template.ParseGlob("templates/*.tmpl"))
err := tmpls.ExecuteTemplate(os.Stdout, "example.tmpl", map[string]any{"Word": "world"})
if err != nil {
log.Fatal(err)
}The above code loads all the files with .tmpl extension, so that we can execute any template.
Working with HTML Templates
Go templates shine for those who want to build a website and render HTML pages easily.
Loading HTML Templates from Filesystem
The process is very similiar to the previous example with only changes being, the extension and import.
// Make sure imports are correct.
import (
"os"
"log"
"html/template" // this changed
)
tmpls := template.Must(template.ParseGlob("templates/*.html")) // extension changed
err := tmpls.ExecuteTemplate(os.Stdout, "example.html", map[string]any{"Word": "world"})
if err != nil {
log.Fatal(err)
}Rendering a HTML Template in Browser
We'll be creating a simple http server to render a page with templates.
contents of home.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{ .Title }}</title>
</head>
<body>
Hey, There!
</body>
</html>func handleGetHome(w http.ResponseWriter, r *http.Request) {
tmpls.ExecuteTemplate(w, "home.html", map[string]any{"Title":"Home Page"})
}
http.HandleFunc("/", handleGetHome)
http.ListenAndServe(":3000", nil)Now, visit http://localhost:3000, you'll see the html being rendered.
Using Loops and Conditionals in Go Templates
Go templates support basic control structures like loops and conditionals, making it easy to handle dynamic content.
Looping with range
Use range to iterate over slices, maps, etc.
template:
<ul>
{{ range .Items }}
<li>{{ . }}</li>
{{ else }}
<li>No items found.</li>
{{ end }}
</ul>go code:
data := map[string]any{
"Items": []string{"Go", "Python", "Rust"},
}
tmpls.ExecuteTemplate(w, "example.html", data)Using Conditionals (if, else)
Example: Checking for a Value
{{ if .IsLoggedIn }}
<p>Welcome back, {{ .Username }}!</p>
{{ else }}
<p>Please log in.</p>
{{ end }}Using Custom Functions in Go Templates
Go allows defining custom functions and passing them to templates using a FuncMap. This is useful for formatting data, modifying strings, or adding extra logic inside templates.
template:
<p>Original: {{ .Name }}</p>
<p>FirstName: {{ getFirstName .Name }}</p>go code:
// Define custom functions
funcs := template.FuncMap{
"getFirstName": func(name string) string {
return strings.Split(name, " ")[0]
},
}
tmpls := template.Must(template.New("").Funcs(funcs).ParseGlob("templates/*.html"))Using Components in Go Templates
In Go templates, components (also called partials) help reuse smaller templates inside larger ones. This avoids code duplication and makes templates more modular.
Example: Reusing a Header Component
📂 Folder Structure
/templates
├── header.html
├── page.htmlcontents header.html
<header>
<h1>{{ .Title }}</h1>
</header>contents page.html
{{ template "header.html" }}
<p>Welcome to the page</p>Using Layouts in Go Templates
When building web pages, we usually want to reuse a layout for multiple pages to reduce code duplication, but it's very hard to do so with templates.
How Layouts Work in Go
Unlike some templating engines that use {{ block }} and {{ define }}, we’ll use a custom function to inject a template inside a layout dynamically. This gives us more control and flexibility over rendering.
Defining Custom Function for Layouts
We’ll define a function (embed) that renders a given template inside a layout. This allows us to reuse a single layout file across multiple pages.
contents Layout.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{ .Title }}</title>
</head>
<body>
{{ embed .Page . }} <!-- Embed the page content here -->
</body>
</html>contents of Page.html
<h1>Welcome to {{ .Title }}</h1>
<p>This is a dynamic page using a layout.</p>Registering embed function
tmpl := template.New("")
funcs := template.FuncMap{
"embed": func(name string, data any) template.HTML {
var out strings.Builder
if err := tmpl.ExecuteTemplate(&out, name, data); err != nil {
log.Println(err)
}
return template.HTML(out.String())
},
}
tmpls := template.Must(tmpl.Funcs(funcs).ParseGlob("templates/*.html"))Usage
func handler(w http.ResponseWriter, r *http.Request) {
// This is the layout name which we're gonna use.
tmpls.ExecuteTemplate(w, "Layout.html", map[string]any{
"Page": "Page.html", // This is the page name
"Title": "Example Page",
})
}Full Example here.
Resources
If you want to dive deeper into Go templates, here are some useful links:
- Go Template Syntax Reference: HashiCorp Go Template Guide
- Build Web Applications with Go Templates: Gospur – CLI Tool
If you're planning to use Go templates in a real web application, Gospur provides a more structured approach to working with them.
Conclusion
Go templates provide a simple yet powerful way to generate dynamic content, whether for rendering HTML pages in a web app or formatting text output. With features like loops, conditionals, custom functions, and layouts, they offer flexibility while keeping things lightweight. By structuring templates well and using functions like embed shown above, you can create modular and maintainable templates for your Go projects.
