How to Use HTML Templates with Custom Delimiters in Gin

You can change Gin’s default template delimiters by calling Engine.Delims(left, right) before loading templates, which updates the engine’s internal delims field and applies the new delimiters to all subsequent LoadHTMLGlob, LoadHTMLFiles, or LoadHTMLFS calls.

Gin’s templating subsystem is built on Go’s standard html/template package, which defaults to the standard {{ and }} delimiters. When building applications that use JavaScript frameworks like Vue or Angular—which often conflict with these markers—you can configure custom delimiters globally for the entire router as implemented in the gin-gonic/gin source code.

Setting Global Delimiters

Call Engine.Delims(left, right) immediately after creating your router instance and before loading any template files. This method stores the custom delimiter pair in the engine’s delims field, which defaults to render.Delims{Left: "{{", Right: "}}"}`` according to the source in [gin.go`](https://github.com/gin-gonic/gin/blob/main/gin.go) L223.

The implementation in gin.go L58-L62 simply assigns the provided strings to the engine’s configuration:

r := gin.Default()
r.Delims("{[{", "}]}")  // Change delimiters globally
r.LoadHTMLGlob("templates/*.tmpl")

Once set, these delimiters persist for the lifetime of the engine instance and automatically propagate to every template parsing operation.

Loading Templates with Custom Delimiters

Gin applies the stored delimiter configuration during the template parsing phase. Whether you load templates via glob patterns, specific file lists, or embedded filesystems, the engine forwards your custom delimiters to the underlying html/template parser.

LoadHTMLGlob

When using LoadHTMLGlob, Gin creates a new template instance and immediately applies the custom delimiters before parsing the glob pattern. The implementation in gin.go L70-L76 executes:

template.New("").Delims(left, right).ParseGlob(pattern)

LoadHTMLFiles

For explicit file lists, the LoadHTMLFiles method in gin.go L86-L94 passes the engine’s stored delimiter values to ParseFiles:

template.New("").Delims(engine.delims.Left, engine.delims.Right).ParseFiles(files...)

LoadHTMLFS

When loading from an embedded filesystem (Go 1.16+), LoadHTMLFS in gin.go L98-L106 applies the same delimiter configuration:

template.New("").Delims(engine.delims.Left, engine.delims.Right).ParseFS(...)

Rendering Templates

After loading templates with custom delimiters, render them normally using c.HTML(). The parser has already internalized your delimiter configuration, so template files should use the new markers exclusively.

r.GET("/hello/:name", func(c *gin.Context) {
    c.HTML(http.StatusOK, "hello.tmpl", gin.H{
        "Name": c.Param("name"),
    })
})

Debug Mode Behavior

In development mode (gin.IsDebugging() returns true), Gin uses the render.HTMLDebug renderer, which stores the delimiter configuration alongside template source information. As implemented in render/html.go L75-L80, this renderer parses template files on each request using your custom delimiters, ensuring changes are reflected without server restarts.

Complete Working Example

The following example demonstrates a full implementation using {[{ and }]} as custom delimiters to avoid conflicts with frontend frameworks.

main.go:

package main

import (
	"net/http"

	"github.com/gin-gonic/gin"
)

func main() {
	// Create router with default middleware
	r := gin.Default()

	// Set custom delimiters before loading templates
	r.Delims("{[{", "}]}")

	// Load templates that use the new delimiters
	r.LoadHTMLGlob("templates/*.tmpl")

	// Define handler
	r.GET("/hello/:name", func(c *gin.Context) {
		c.HTML(http.StatusOK, "hello.tmpl", gin.H{
			"Name": c.Param("name"),
		})
	})

	r.Run(":8080")
}

templates/hello.tmpl:

<h1>Hello {[{ .Name }]}!</h1>

Visiting http://localhost:8080/hello/gin outputs:

<h1>Hello gin!</h1>

Summary

  • Call Engine.Delims(left, right) before loading templates to set global delimiters in gin.go.
  • All loading methods (LoadHTMLGlob, LoadHTMLFiles, LoadHTMLFS) automatically forward your custom delimiters to the html/template parser.
  • Template files must use your custom delimiters (e.g., {[{ .Var }]} instead of {{ .Var }}).
  • Debug mode re-parses templates with your delimiters on every request for rapid development.

Frequently Asked Questions

Can I set different delimiters for individual templates instead of globally?

No, the gin-gonic/gin engine stores delimiters in a single delims field at the router level as defined in gin.go L223. All templates loaded through that engine instance share the same delimiter configuration. To use different delimiters for specific templates, you must create separate Engine instances or manually parse templates outside of Gin’s built-in loader.

What delimiter characters are valid in Gin?

Gin accepts any string values for left and right delimiters through Engine.Delims(), passing them directly to Go’s html/template.Delims() method. Valid delimiters must not contain whitespace and should be distinct from content in your templates. Common alternatives include {[{ and }]} for Vue.js compatibility, or <% and %> for ERB-style syntax.

Do custom delimiters affect JSON or XML rendering in Gin?

No, delimiter configuration only affects the HTML template rendering system. The Delims field is used exclusively by the HTML rendering logic in render/html.go and methods like LoadHTMLGlob. JSON, XML, and other response formats rendered via c.JSON() or c.XML() operate independently of template delimiter settings.

Why does my template show literal delimiter text instead of rendered values?

This occurs when the delimiters in your template files do not match the delimiters set via Engine.Delims(). Ensure you call r.Delims() before r.LoadHTMLGlob() or other loading methods, and verify that your .tmpl files use the exact left and right strings you specified. In debug mode, Gin re-parses templates on each request, so mismatches are easier to spot without server restarts.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →