Razor view engine for go



Build Status Go Report Card gopherbadger-tag-do-not-edit 996.icu LICENSE

gorazor is the Go port of the razor view engine originated from asp.net in 2011. In summary, gorazor is:

  • Extremely Fast. Templates are converted into Go code and then compiled with optimizations.
  • Concise syntax, no delimiter like <?, <%, or {{.
  • Able to mix go code in view template
    • Insert code block to import & call arbitrary go modules & functions
    • Flow controls are just Go, no need to learn another mini-language
  • Code generation approach
    • No reflection overhead
    • Go compiler validation for free
  • Strong type view model
  • Embedding templates support
  • Layout/Section support

Extremely Fast

gorazor is about 20X times faster than html/template when using standard strings.Builder for template writing.

When using quicktemplate's ByteBuffer and unsafeStrToBytes method to for template writing, gorazor's performance is comparable to quicktemplate, if not faster.

Benchmark results:

$ go test -bench='Benchmark(Razor|RazorQuick|Quick|HTML)Template' -benchmem github.com/valyala/quicktemplate/tests github.com/sipin/gorazor/tests
goos: windows
goarch: amd64
pkg: github.com/valyala/quicktemplate/tests
BenchmarkQuickTemplate1-8       50000000                35.6 ns/op             0 B/op          0 allocs/op
BenchmarkQuickTemplate10-8      10000000               152 ns/op               0 B/op          0 allocs/op
BenchmarkQuickTemplate100-8      1000000              1460 ns/op               0 B/op          0 allocs/op
BenchmarkHTMLTemplate1-8         2000000               712 ns/op             608 B/op         21 allocs/op
BenchmarkHTMLTemplate10-8         500000              3586 ns/op            2834 B/op        111 allocs/op
BenchmarkHTMLTemplate100-8         50000             35180 ns/op           28055 B/op       1146 allocs/op
ok      github.com/valyala/quicktemplate/tests  11.360s
goos: windows
goarch: amd64
pkg: github.com/sipin/gorazor/tests
BenchmarkRazorTemplate1-8                       30000000                49.8 ns/op           224 B/op          3 allocs/op
BenchmarkRazorTemplate10-8                      10000000               122 ns/op             480 B/op          4 allocs/op
BenchmarkRazorTemplate100-8                      2000000               931 ns/op            4064 B/op          7 allocs/op
BenchmarkRazorQuickTemplate1-8                  100000000               19.9 ns/op             0 B/op          0 allocs/op
BenchmarkRazorQuickTemplate10-8                 20000000                82.5 ns/op             0 B/op          0 allocs/op
BenchmarkRazorQuickTemplate100-8                 2000000               767 ns/op               0 B/op          0 allocs/op
BenchmarkRazorQuickTemplateOriginal1-8          100000000               17.4 ns/op             0 B/op          0 allocs/op
BenchmarkRazorQuickTemplateOriginal10-8         20000000                68.8 ns/op             0 B/op          0 allocs/op
BenchmarkRazorQuickTemplateOriginal100-8         2000000               656 ns/op               0 B/op          0 allocs/op
ok      github.com/sipin/gorazor/tests  19.921s
  • BenchmarkRazorQuickTemplate's manually modified ensure exact output as quicktemplate for comparism.
  • BenchmarkRazorQuickTemplateOriginal are gorazor's default code-gen, which produce less white-space, thus faster.


gorazor supports go 1.10 and above, for go version below 1.10, you may use gorazor classic version.

go 1.12 are recommended for better compiler optimization.


go get github.com/sipin/gorazor


  • Process folder: gorazor template_folder output_folder
  • Process file: gorazor template_file output_file


[Examples] gives examples using layout / helper etc.

When using layout, you may need to set -prefix parameter, like:

git clone https://github.com/sipin/gorazor/
cd gorazor
go build

# -prefix parameter here tells gorazor the current folder is the base path for github.com/sipin/gorazor
# So that, when importing "github.com/sipin/gorazor/examples/tpl/layout" in example/tpl/home.gohtml
# gorazor will know how to find the layout/helper files
./gorazor -prefix github.com/sipin/gorazor ./examples/tpl ./examples/tpl
go run example/main.go



  • @variable to insert string variable into html template
    • variable could be wrapped by arbitrary go functions
    • variable inserted will be automatically escaped
<div>Hello @user.Name</div>
<div>Hello @strings.ToUpper(req.CurrentUser.Name)</div>

Use raw to skip escaping:


Only use raw when you are 100% sure what you are doing, please always be aware of XSS attack.

Flow Control

@if .... {

@if .... {
} else {

@for .... {


	switch .... {
	case ....:
	case 2:

Please use example for reference.

Code block

Arbitrary go code could be used in templates, like creating a new variable.

	username := u.Name
	if u.Email != "" {
		username += "(" + u.Email + ")"
<div class="welcome">
<h4>Hello @username</h4>

It's recommended to keep clean separation of code & view. Please consider move logic into your code before creating a code block in a template.


The first code block in template is strictly for declaration:

  • imports
  • model type
  • layout


	import  (
		"kp/models"   //import `"kp/models"` package
		"tpl/layout"  //import tpl/layout namespace

	layout := layout.Base //Use layout package's **Base func** for layout
	var user *models.User //1st template param
	var blog *models.Blog //2nd template param

first code block must be at the beginning of the template, i.e. before any html.

Any other codes inside the first code block will be ignored.

import must be wrapped in (), import "package_name" is not yet supported.

The variables declared in first code block will be the models of the template, i.e. the parameters of generated function.

If your template doesn't need any model input, then just leave it blank.

Helper / Include other template

As gorazor compiles templates to go function, embedding another template is just calling the generated function, like any other go function.

However, if the templates are designed to be embedded, they must be under helper namespace, i.e. put them in helper sub-folder.

So, using a helper template is similar to:

@if msg != "" {

gorazor won't HTML escape the output of helper.XXX.

Please use example for reference.

Layout & Section

The syntax for declaring layout is a bit tricky, in the example mentioned above:

	import  (

	layout := layout.Base //Use layout package's **base func** for layout

"tpl/layout" is the layout package namespace, and the layout variable refers to "layout.Base" func, which should be generated by tpl/layout/base.gohtml.

Must use layout as the variable name

Package / Variable convention

  • The namespace/folder name for layout templates must be layout
    • gorazor relies on this to determine if a template is for layout
  • The template variable name also must be layout

A layout file tpl/layout/base.gohtml may look like:

	var body string
	var sidebar string
	var footer string
	var title string
	var css string
	var js string

<!DOCTYPE html>
	<meta charset="utf-8" />
    <div class="container">@body</div>
    <div class="sidebar">@sidebar</div>
    <div class="footer">@footer</div>

It's just a usual gorazor template, but:

  • First param must be var body string (As it's always required, maybe we could remove it in future?)
  • All params must be string, each param is considered as a section, the variable name is the section name.
  • Under layout package, i.e. within "layout" folder.
    • Optionally, use isLayout := true to declare a template as layout

A template using such layout tpl/index.gohtml may look like:

	import (

	layout := layout.Base

@section footer {
	<div>Copyright 2014</div>

<h2>Welcome to homepage</h2>

It's also possible to use import alias:

	import (
		share "tpl/layout"

	layout := share.Base

With the page, the page content will be treated as the body section in the layout.

The other section content need to be wrapped with

@section SectionName {

The template doesn't need to specify all sections defined in the layout. If a section is not specified, it will be considered as "".

Thus, it's possible for the layout to define default section content in such manner:

	var body string
	var sidebar string

    <div class="container">@body</div>
    @if sidebar == "" {
    <div class="sidebar">I'm the default side bar</div>
	} else {
    <div class="sidebar">@sidebar</div>
  • A layout should be able to use another layout, it's just function call.


  • Template folder name will be used as package name in generated code
  • Template file name must has the extension name .gohtml
  • Template strip of .gohtml extension name will be used as the function name in generated code, with first letter Capitalized.
    • So that the function will be accessible to other modules. (I hate GO about this.)
  • Helper templates must has the package name helper, i.e. in helper folder.
  • Layout templates must has the package name layout, i.e. in layout folder.


Here is a simple example of gorazor templates and the corresponding generated codes.


IDE / Editor support?

Sublime Text 2/3

  • Syntax highlight Search & install gorazor via Package Control.
  • Context aware auto-completion, you may need to manually modify GoSublime package, bascially replace gscomplete.py in with this and gslint.py with this


web-mode supports Razor template engine, so add this into your Emacs config file:

(require 'web-mode)
(add-hook 'web-mode-hook  'my-web-mode-hook)
(add-to-list 'auto-mode-alist '("\\.html?\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.gohtml\\'" . web-mode))
(add-to-list 'auto-mode-alist '("\\.js\\'" . web-mode))
(setq web-mode-engines-alist '(("razor" . "\\.gohtml\\'")))


The very first version of gorazor is a hack of razor's port in javascript: vash, thus requires node's to run.

gorazor has been though several rounds of refactoring, and it has completely rewritten in pure Go. Nonetheless, THANK YOU @kirbysayshi for Vash! Without Vash, gorazor may never start.


LICENSE? Well, WTFPL and 996.icu.



  • Should it preserve newline and whitespace?

    Should it preserve newline and whitespace?


    But it generates:

    <ul><li> Felix Sun 0 </li><li> Felix Sun 1 </li><li> Felix Sun 2 </li><li> Felix Sun 3 </li><li> Felix Sun 4 </li><li> Felix Sun 5 </li><li> Felix Sun 6 </li><li> Felix Sun 7 </li><li> Felix Sun 8 </li><li> Felix Sun 9 </li><li> Felix Sun 10 </li><li> Felix Sun 11 </li><li> Felix Sun 12 </li><li> Felix Sun 13 </li><li> Felix Sun 14 </li><li> Felix Sun 15 </li><li> Felix Sun 16 </li><li> Felix Sun 17 </li><li> Felix Sun 18 </li><li> Felix Sun 19 </li><li> Felix Sun 20 </li><li> Felix Sun 21 </li><li> Felix Sun 22 </li><li> Felix Sun 23 </li><li> Felix Sun 24 </li><li> Felix Sun 25 </li><li> Felix Sun 26 </li><li> Felix Sun 27 </li><li> Felix Sun 28 </li><li> Felix Sun 29 </li>
    opened by sunfmin 11
  • sections from layout seem to be required

    sections from layout seem to be required

    If I have a layout:

        var body string
        var js string
    hello @js

    And in another template do not use

    @section js {

    I get a not enough arguments in call to layout.App`` because the compiled template is callingreturn layout.App(_buffer.String())```

    The docs state that the layout sections are optional, so is this a bug or am I reading the docs incorrectly? Thanks for an awesome library!

    opened by troyk 9
  • Request: Add

    Request: Add "Line Directives"

    Great project! This makes it easy to move from ASP.NET MVC to GO. One request I have is to add Go's undocumented "line directives" to the generated code so Go’s error reporting can reference your original source:

    //line index.ego:1
    func RenderIndex(w io.Writer, widgets []*Widget) error {
    //line index.ego:2
        _, _ = fmt.Fprintf(w, "\n\n<html>\n<body>\n  <h1>Widgets for Sale!</h1>\n\n  <ul>\n    ")
    //line index.ego:8
        for _, widget := range widgets {
    //line index.ego:9
            _, _ = fmt.Fprintf(w, "\n      <li>")
    //line index.ego:9
            _, _ = fmt.Fprintf(w, "%v", widget.Name)
    //line index.ego:9
            _, _ = fmt.Fprintf(w, " for $")
    //line index.ego:9
            _, _ = fmt.Fprintf(w, "%v", widget.Price)
    //line index.ego:9
            _, _ = fmt.Fprintf(w, "</li>\n    ")
    //line index.ego:10
    //line index.ego:11
        _, _ = fmt.Fprintf(w, "\n  </ul>\n</body>\n</html>\n")
        return nil

    The above code is from an article on the EGO templating engine.

    opened by nkev 5
  • GoRazor panic on a strange case

    GoRazor panic on a strange case

    case reference: https://gist.github.com/Wuvist/7f22c2f3e2348e7b8479

    Panic out put

    panic: UNMATCHED!
    goroutine 16 [running]:
    runtime.panic(0x121f80, 0x2082d8460)
        /usr/local/go/src/pkg/runtime/panic.c:279 +0xf5
    github.com/sipin/gorazor/gorazor.(*Parser).handleMKP(0x208398320, 0x2083702ac, 0x6, 0x197e90, 0xe, 0x11, 0xe, 0x1)
        /Users/wuvist/Dropbox/sipin/zfw_code/src/github.com/sipin/gorazor/gorazor/parser.go:354 +0x800
    github.com/sipin/gorazor/gorazor.(*Parser).Run(0x208398320, 0x0, 0x0)
        /Users/wuvist/Dropbox/sipin/zfw_code/src/github.com/sipin/gorazor/gorazor/parser.go:541 +0x272
    github.com/sipin/gorazor/gorazor.run(0x7fff5fbffb08, 0x3a, 0x2082e4c30, 0x0, 0x0, 0x0)
        /Users/wuvist/Dropbox/sipin/zfw_code/src/github.com/sipin/gorazor/gorazor/gogen.go:330 +0x620
    github.com/sipin/gorazor/gorazor.Generate(0x7fff5fbffb08, 0x3a, 0x2082e4c30, 0x0, 0x0, 0x0, 0x0)
        /Users/wuvist/Dropbox/sipin/zfw_code/src/github.com/sipin/gorazor/gorazor/gogen.go:356 +0x64
    github.com/sipin/gorazor/gorazor.GenFile(0x7fff5fbffb08, 0x3a, 0x7fff5fbffb43, 0x3a, 0x2082e4c30, 0x0, 0x0)
        /Users/wuvist/Dropbox/sipin/zfw_code/src/github.com/sipin/gorazor/gorazor/gogen.go:383 +0x502
        /Users/wuvist/Dropbox/sipin/zfw_code/src/github.com/sipin/gorazor/gorazor.go:44 +0x637
    goroutine 17 [runnable]:
    goroutine 18 [runnable]:
    goroutine 19 [runnable]:
    opened by Wuvist 5
  • 请教gorazor模板几个基本问题: 网页的错误页面

    请教gorazor模板几个基本问题: 网页的错误页面

    一般网站在发生内部错误的时候会统一跳转到一个错误页面。所以会有一个统一的入口和实现。用 go native template 实现的伪代码: basepage.go

      package base
      func Error(errcode int, errmsg string) {
            data.User = currentUser
            data.HasNewMessage = false
            data.SomeOtherBussinesData = xxx
            gotemplate.Render("error.tpl", data)

    这个思路在很多模板系统是流行的解决方法,能统一处理所有页面处理时出错 渲染 Error Page

    用gorazor按这个思路做不了,比如伪代码类似 gorazor_basepage.go

      package base
      import "gorazor_gentpl"
      func Error(errcode int, errmsg string) {
            data.User = currentUser
            data.HasNewMessage = false
            data.SomeOtherBussinesData = xxx

    gorazor_gentpl 这里面的代码有 import 了 base 里的不少东西。

    问题的本质: go native tempate 非代码运行,虽然tpl引用了base,但 base 内再 call tpl 没问题。但gorazor是代码运行就有package 相互 import 的问题。


    1. 将 Error 做的很简单,不用 模板系统。 这种改动有点本末倒置,让用户体验服从框架。
    2. 将 Error 的模板引用到的东西再抽成一个 package,base 也 import 这个package 这个思路貌似可行,但是 package 是目录级别的,得要考虑同目录下go文件的 import,牵扯有点多,而且这会导致后面很多代码都提心吊胆。

    不知道 gorazor 如何解决这个问题的

    opened by smithfox 4
  • please provide a working

    please provide a working "tpl" example for beginner

    Here is the compilation error. [[email protected] test]$ gorazor tpl tpl.out Processing dir: tpl tpl.out Processing: tpl/helper/footer.gohtml --> /home/tjyang/gocode/src/test/tpl.out/helper/footer.go Processing: tpl/helper/header.gohtml --> /home/tjyang/gocode/src/test/tpl.out/helper/header.go Processing: tpl/helper/msg.gohtml --> /home/tjyang/gocode/src/test/tpl.out/helper/msg.go Processing: tpl/home.gohtml --> /home/tjyang/gocode/src/test/tpl.out/home.go Processing: tpl/layout/base.gohtml --> /home/tjyang/gocode/src/test/tpl.out/layout/base.go [[email protected] test]$ cd tpl.out/ [[email protected] tpl.out]$ go build -x home.go WORK=/tmp/go-build837451497 home.go:6:2: cannot find package "kp/models" in any of: /usr/lib64/golang/src/pkg/kp/models (from $GOROOT) /home/tjyang/gocode/src/kp/models (from $GOPATH) home.go:7:2: cannot find package "tpl/helper" in any of: /usr/lib64/golang/src/pkg/tpl/helper (from $GOROOT) /home/tjyang/gocode/src/tpl/helper (from $GOPATH) home.go:8:2: cannot find package "tpl/layout" in any of: /usr/lib64/golang/src/pkg/tpl/layout (from $GOROOT) /home/tjyang/gocode/src/tpl/layout (from $GOPATH) [[email protected] tpl.out]$

    opened by tjyang 4
  • Import models from main package

    Import models from main package


    I'm sorry for the silly question, but is it possible to declare model variables from main package? If yes, how could I call it?

    The problem is, I want to send an interface with a map like Content{var, var, var, map} but in the end get "undefined map" error

    Also, might be a good idea to add examples of models to examples, I'm missing the model code from your example packages :(


    opened by vadimyer 3
  • string return value

    string return value

    Is there a reason the return value on template functions is string instead of just bytes.Buffer? I understand it's more eye readable but it requires two transformations to write to ResponseWriter.

    1. The buffer is transformed to a string inside the template
    return _buffer.String()
    1. Then the string is transformed to a []byte in a handler
        func index(w http.ResponseWriter, r *http.Request) {

    Wouldn't this be more efficient

    opened by mgutz 3
  • Plain string

    Plain string "for" caused generated can't compiled code


        var l *Locale

    Will generate:

    package test
    import (
    func S(l *Locale) string {
    var _buffer bytes.Buffer
    return _buffer.String()

    which can't compile because:

    FelixMBPR:Desktop sunfmin$ gorazor test/ test/
    Processing dir: test/ test/
    Processing: test/s.gohtml --> /Users/sunfmin/Desktop/test/s.go
    /Users/sunfmin/Desktop/test/s.go:10:49: missing ',' before newline in argument list
    gofmt:  exit status 2
    opened by sunfmin 3
  • I can't seem to get the packages right.

    I can't seem to get the packages right.

    Today gorazor command sources files from 'tpl' and create a new folder 'gen' with files packaged as 'tpl'.

    Is this correct? Shouldn't the generated code be packaged as the same output folder?


    opened by marcalc 2
  • 请教gorazor模板几个基本问题: 基于变量多选一的逻辑

    请教gorazor模板几个基本问题: 基于变量多选一的逻辑

    衡量一个模板是否好用,复用是一个非常重要的指标,非 Hello World 所能反映出来的,必须在深入使用,才能体会。 我想请教几个问题,想问问 gorazor 是什么解决的。

    我都是基于 golang template 来说的.

    1. 在模板中基于变量多选一的逻辑
          <option value="-1">all</option>
          <option value="4"  {{if eq .item.Value 4}}  selected="selected"{{end}}>a</option>
          <option value="9"  {{if eq .item.Value 9}}  selected="selected"{{end}}>b</option>
          <option value="11" {{if eq .item.Value 11}} selected="selected"{{end}}>c</option>
          <option value="3"  {{if eq .item.Value 3}}  selected="selected"{{end}}>d</option>

    这样的代码既丑陋又低效,gorazor 能解决吗?

    opened by smithfox 2
  • 参考nuxt.js做服务器端渲染框架?




    既然是服务器端渲染,何必还要靠js呢?不如直接go实现?gorazor本质就是干这个事的啊! 相比nuxt,go做服务器端渲染至少有这些优势:1.更简单,无需学习vue一套东西,学习成本低。2.更高效,go的运行效率肯定比js高。3.更清爽,用go写代码,无疑爽多了。4.更好调试。


    opened by codinl 1
Amber is an elegant templating engine for Go Programming Language, inspired from HAML and Jade

amber Notice While Amber is perfectly fine and stable to use, I've been working on a direct Pug.js port for Go. It is somewhat hacky at the moment but

Ekin Koc 893 Sep 13, 2022
Simple and fast template engine for Go

fasttemplate Simple and fast template engine for Go. Fasttemplate performs only a single task - it substitutes template placeholders with user-defined

Aliaksandr Valialkin 630 Sep 16, 2022
Article spinning and spintax/spinning syntax engine written in Go, useful for A/B, testing pieces of text/articles and creating more natural conversations

GoSpin Article spinning and spintax/spinning syntax engine written in Go, useful for A/B, testing pieces of text/articles and creating more natural co

Miles Croxford 39 Aug 7, 2022
A handy, fast and powerful go template engine.

Hero Hero is a handy, fast and powerful go template engine, which pre-compiles the html templates to go code. It has been used in production environme

Lime 1.5k Sep 15, 2022
Jet template engine

Jet Template Engine for Go Jet is a template engine developed to be easy to use, powerful, dynamic, yet secure and very fast. simple and familiar synt

null 955 Sep 21, 2022
A complete Liquid template engine in Go

Liquid Template Parser liquid is a pure Go implementation of Shopify Liquid templates. It was developed for use in the Gojekyll port of the Jekyll sta

Oliver Steele 172 Sep 16, 2022
Fast, powerful, yet easy to use template engine for Go. Optimized for speed, zero memory allocations in hot paths. Up to 20x faster than html/template

quicktemplate A fast, powerful, yet easy to use template engine for Go. Inspired by the Mako templates philosophy. Features Extremely fast. Templates

Aliaksandr Valialkin 2.6k Sep 27, 2022
gtpl is a template engine for glang

gtpl 使用必读 gtpl is a HTML template engine for golang gtpl 是一个 go 语言模板引擎,它能以极快的速度进行模板语法分析。相比 go 语言官方库 html/template,gtpl 的语法有着简练、灵活、易用的特点。

null 5 Jan 23, 2022
The world’s most powerful template engine and Go embeddable interpreter.

The world’s most powerful template engine and Go embeddable interpreter

Open2b 357 Sep 21, 2022
This my project template for making fiber with SSR taste by empowered mustache engine.

SSR-FIBER-TEMPLATE This my project template for making fiber with SSR taste by empowered mustache engine. Folder Hierarchy Name Description configs Co

▲ 2 May 9, 2022
Toothpaste is a simple templating engine for Go web applications, inspired by Blade/Twig

A simple HTML templating engine in Go inspired by Twig. Currently supports Variables, Escaping, If statements, Templating and Functional variables.

Mats 3 Jul 24, 2022
View reddit memes and posts from ur terminal with golang and webscraping

goddit View reddit memes and posts from your terminal with golang and webscraping Installation run the following commands on your terminal to install

Swapnadeep Som 11 Feb 22, 2021
Interact with Chromium-based browsers' debug port to view open tabs, installed extensions, and cookies

WhiteChocolateMacademiaNut Description Interacts with Chromium-based browsers' debug port to view open tabs, installed extensions, and cookies. Tested

Justin Bui 90 Sep 20, 2022
View the script files in the original Resident Evil 2 / Biohazard 2 as pseudocode

Resident Evil 2 Script Viewer About You can view the script files in the original Resident Evil 2 / Biohazard 2 as pseudocode next to the original byt

Samuel Yuan 14 Jan 20, 2022
Pi-hole data right from your terminal. Live updating view, query history extraction and more!

Pi-CLI Pi-CLI is a command line program used to view data from a Pi-Hole instance directly in your terminal.

Reece Mercer 41 Apr 26, 2022
view stonks from the terminal

stonks view stonks from the terminal Preview Why? Why not >:D Installation Requirements Golang 1.16 $ git clone https://github.com/nerdthatnoonelikes/

Raghav 6 Jun 19, 2022
Example of how to achieve pixel perfect shadows in a 2D view

Lights and Shadows Example of how to achieve pixel perfect shadows in a 2D view. The sample is based on the following sources: 2D Pixel Perfect Shadow

Defold 12 Mar 29, 2022
View historical Docker Hub image pull charts for all public Docker Images.

dockerstats.com ⚠️ Due to recent changes to Docker Hub APIs (rate limits) and new business model, dockerstats.com can no longer collect image statisti

hackerman 45 May 19, 2022
View Wikiloc.com trails in Google Earth

Wikiloc Google Earth layer View Wikiloc.com trails in Google Earth. Tiny http server written in Go that fetch trails from wikiloc.com to compose KML u

Jonathan Mataloni 14 Aug 22, 2022