Question
How can I import and use both Go template packages, text/template and html/template, in the same source file? Both packages use the package name template, so importing them normally causes a redeclaration error.
For example, how should this code be written correctly?
import (
"net/http"
"text/template"
"html/template"
)
func handlerHTML(w http.ResponseWriter, r *http.Request) {
tHTML, err := html.template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
tText, err := text.template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
}
Short Answer
In Go, an imported package is referenced by its declared package name, not necessarily by the final part of its import path. Since both html/template and text/template are named template, they conflict in one import block. You can solve this by assigning explicit import aliases, such as htmltemplate and texttemplate, then using those aliases in code.
Concept
Go imports packages into a file-level namespace. After importing a package, you access exported names with a package qualifier:
packageName.ExportedName
Usually, the qualifier is the package's declared name. For example, the package at net/http declares itself as http, so you write:
http.Handler
However, both of these standard-library packages declare the name template:
text/templatehtml/template
Therefore, this is ambiguous and invalid:
import (
"text/template"
"html/template"
)
Go would have two imported packages named template, and it could not determine which one template.New means.
An import alias gives a package a local name for the current file:
import htmltemplate "html/template"
The alias does not rename the actual package. It only changes how that package is referenced in this source file.
This matters when packages have identical names, when a package name is unclear, or when an alias makes code easier to read. In this example, aliases also make an important security distinction visible: html/template is intended for HTML output and automatically escapes untrusted values, while text/template produces plain text.
Mental Model
Think of an import as adding a contact to your phone.
Two different people might both be named Alex. If you save both contacts only as Alex, you will not know which person to call. Instead, you label them Alex Work and Alex Family.
Similarly, Go sees two packages both named template. Import aliases give each one a distinct local label:
htmltemplatefor HTML templatestexttemplatefor text templates
Then Go knows exactly which package you mean.
Syntax and Examples
Use this syntax to assign an import alias:
import aliasName "package/path"
For the two template packages:
package main
import (
"fmt"
htmltemplate "html/template"
texttemplate "text/template"
)
func main() {
htmlTmpl, err := htmltemplate.New("html").Parse(`<p>Hello, {{.}}</p>`)
if err != nil {
panic(err)
}
textTmpl, err := texttemplate.New("text").Parse("Hello, {{.}}\n")
if err != nil {
panic(err)
}
fmt.Printf("HTML template type: %T\n", htmlTmpl)
fmt.Printf("Text template type: %T\n", textTmpl)
}
The aliases are used as qualifiers:
htmltemplate.New(...)
texttemplate.New(...)
Do not write html.template.New. html/template is an import path, not an object named html that contains an object named template.
A practical HTTP example uses html/template to render a page safely:
package main
import (
"net/http"
htmltemplate "html/template"
)
func handlerHTML(w http.ResponseWriter, r *http.Request) {
tmpl, err := htmltemplate.New("page").Parse(`<h1>Hello, {{.}}</h1>`)
if err != nil {
http.Error(w, "could not create template", http.StatusInternalServerError)
return
}
if err := tmpl.Execute(w, "Ada"); err != nil {
http.Error(w, "could not render template", http.StatusInternalServerError)
}
}
For actual web pages, prefer html/template rather than text/template. It contextually escapes inserted data to help prevent HTML injection and cross-site scripting (XSS).
Step by Step Execution
Consider this complete program:
package main
import (
"bytes"
"fmt"
htmltemplate "html/template"
texttemplate "text/template"
)
func main() {
var htmlOutput bytes.Buffer
var textOutput bytes.Buffer
htmlTmpl := htmltemplate.Must(htmltemplate.New("html").Parse(`<p>{{.}}</p>`))
textTmpl := texttemplate.Must(texttemplate.New("text").Parse(`Message: {{.}}`))
name := `<strong>Ada</strong>`
htmlTmpl.Execute(&htmlOutput, name)
textTmpl.Execute(&textOutput, name)
fmt.Println(htmlOutput.String())
fmt.Println(textOutput.String())
}
Execution flow:
-
html/templateis imported locally ashtmltemplate. -
text/templateis imported locally astexttemplate. -
Two
bytes.Buffervalues collect output in memory. -
htmltemplate.New(...).Parse(...)creates an HTML-aware template. -
texttemplate.New(...).Parse(...)creates a plain-text template. -
The input string contains HTML markup:
<strong>Ada</strong>. -
When the HTML template executes, it escapes the input because it is being inserted into HTML text context. Its output is approximately:
<p><strong>Ada</strong></p> -
When the text template executes, it leaves the input unchanged:
Message: <strong>Ada</strong>
The import aliases make it immediately clear which behavior comes from which package.
Real World Use Cases
Import aliases are useful in several practical situations:
- HTML pages and plain-text emails: Render a browser page with
html/templateand an email body or log message withtext/template. - Packages with common names: Two third-party packages may both use names such as
config,client,api, orlog. - Database drivers: A project may use packages whose default names would be unclear next to each other.
- Generated and handwritten code: Generated code can import a package with an alias to avoid collisions with existing imports.
- Readable domain names: An alias can clarify intent, such as
userpbfor generated user protocol-buffer code orpaymentapifor an external SDK.
Use aliases mainly to resolve a collision or improve clarity. Avoid aliases that make familiar packages harder to recognize without a good reason.
Real Codebase Usage
In production Go code, aliases are usually short, descriptive, and consistent.
A common pattern for these packages is:
import (
htmltemplate "html/template"
texttemplate "text/template"
)
When handling HTTP requests, combine template work with error handling and early returns:
func renderPage(w http.ResponseWriter, name string) {
tmpl, err := htmltemplate.New("page").Parse(`<h1>Hello, {{.}}</h1>`)
if err != nil {
http.Error(w, "template setup failed", http.StatusInternalServerError)
return
}
if err := tmpl.Execute(w, name); err != nil {
http.Error(w, "template rendering failed", http.StatusInternalServerError)
return
}
}
Real applications often parse templates once at startup instead of parsing them on every request. For example, they may store a parsed *htmltemplate.Template in an application struct and call ExecuteTemplate for each request.
Also notice that Go requires imported packages to be used. If a file imports texttemplate but never refers to it, the compiler reports an unused-import error. This rule helps keep dependencies explicit and source files clean.
Common Mistakes
Importing both packages without aliases
This fails because both imports introduce the name template:
import (
"html/template"
"text/template"
)
Use explicit aliases instead:
import (
htmltemplate "html/template"
texttemplate "text/template"
)
Treating an import path like a nested name
This is invalid:
html.template.New("page")
html/template is a string-like import path. It is not accessed with dots. After aliasing, use the alias directly:
htmltemplate.New("page")
Reusing err incorrectly with :=
This is invalid when both tHTML and tText are new but err already exists in the same scope:
var err error
tHTML, err := htmltemplate.New("html").Parse("...")
tText, err := texttemplate.New("text").Parse("...") // error
On the second line, use = because err is already declared and no new variable is introduced by that statement in the same scope:
var err error
tHTML, err := htmltemplate.New("html").Parse("...")
tText, err = texttemplate.New("text").Parse("...")
More commonly, check each error immediately:
tHTML, err := htmltemplate.New("html").Parse("...")
if err != nil {
return
}
tText, err := texttemplate.New("text").Parse("...")
if err != nil {
return
}
Ignoring template errors
Parse and Execute can fail. Ignoring errors can lead to missing output or a server that behaves unpredictably. Check errors, especially in HTTP handlers.
Using text/template for untrusted HTML
Do not render untrusted data into HTML using text/template:
texttemplate.Must(texttemplate.New("page").Parse(`<p>{{.}}</p>`))
Use html/template for HTML documents. Its escaping behavior is designed for HTML contexts.
Comparisons
| Topic | html/template | text/template |
|---|---|---|
| Main purpose | Generate HTML documents | Generate plain text or arbitrary text formats |
| Escapes inserted values | Yes, contextually for HTML | No automatic HTML escaping |
| Good for | Web pages and HTML emails | Text emails, config files, reports, code generation |
| API style | Very similar to text/template | Very similar to html/template |
| Preferred for browser output | Yes | No |
| Import form | Example | When to use it |
|---|---|---|
| Normal import | import "net/http" | The package name is unique and clear. |
| Aliased import | import htmltemplate "html/template" | A name collision exists or a clearer local name is needed. |
| Blank import | import _ "driver/package" | Only package initialization side effects are needed. |
| Dot import | import . "some/package" | Rarely appropriate; it places exported names directly in the current scope. Avoid it in most application code. |
Aliases are local to one file. Another .go file in the same package must declare its own imports and aliases.
Cheat Sheet
// Alias syntax
import localName "module/or/package"
// Resolve same-name packages
import (
htmltemplate "html/template"
texttemplate "text/template"
)
htmlTmpl := htmltemplate.Must(htmltemplate.New("page").Parse(`<p>{{.}}</p>`))
textTmpl := texttemplate.Must(texttemplate.New("message").Parse(`Hello, {{.}}`))
- Go refers to an import by its package name, not by the final import-path segment alone.
- Use aliases when two imports would have the same local package name.
- An alias is valid only in the file that declares it.
- Write
htmltemplate.New, nothtml.template.New. - Every normal import must be used in that file.
- Prefer
html/templatewhen generating HTML with data that may be untrusted. - Check errors returned by
ParseandExecute.
FAQ
Why does Go say template redeclared as imported package name?
Both html/template and text/template declare their package name as template. Importing both without aliases creates two names called template in the same file.
How do I alias an imported package in Go?
Put the desired local name before the import path:
import htmltemplate "html/template"
Then refer to it as htmltemplate in that file.
Can I use html.template.New after importing html/template?
No. Go import paths are not accessed as dotted objects. Use the package name or alias directly, such as htmltemplate.New.
Is html/template different from text/template?
Yes. Their APIs are similar, but html/template automatically escapes values for HTML contexts. Use it for browser-rendered HTML.
Do import aliases rename a package everywhere?
No. An alias only changes the local name in the source file where it appears.
Should I always use aliases for imports?
No. Use normal imports when names do not conflict and are already clear. Aliases are best for collisions and meaningful clarification.
Can I give two packages any alias names I want?
Yes, provided each alias is a valid Go identifier and does not conflict with another name in that file. Choose descriptive names.
Why do I get an unused import error after adding an alias?
Aliasing does not change Go's rule that normal imports must be used. Remove the import or reference the aliased package in the file.
Mini Project
Description
Build a small program that produces both an HTML greeting and a plain-text greeting from the same input. The project demonstrates how import aliases let two packages with the same declared name coexist clearly in one Go file.
Goal
Use aliased imports to parse and execute one html/template template and one text/template template.
Requirements
Create aliases for both template packages so their names do not conflict. Create one HTML template and one plain-text template. Render the same input value with both templates. Store each rendered result in a separate buffer. Print both outputs and observe the escaping difference.
Keep learning
Related questions
Are Go Maps Passed by Value or Reference?
Learn Go map parameter and return semantics: maps are passed by value, while copies share underlying data. Know when map pointers are useful.
Authentication for Go REST APIs: Sessions, Tokens, and Middleware
Learn practical authentication patterns for Go REST APIs, including password hashing, server sessions, bearer tokens, middleware, and security rules.
Automatic Build Versioning in Go: Embed Incrementing Build Numbers
Learn how to add automatic build versioning in Go using linker flags, build metadata, CI counters, and Git-based version values.