A Go package for generating Go code

go get



MIT License GoDoc Build Status Go Report Card Codecov Coverage Report

go-poet is a Go package for generating Go code, inspired by javapoet.

Typically, code generation uses text templating which can be error prone and hard to maintain. This project aims to fix these issues by giving you an API to generate Go constructs in a typesafe way, while handling imports and formatting for you.


$ go get


Here's a Hello World Go file

package main

import (

func main() {
    fmt.Println("Hello world!")

and the go-poet code to generate it

main := poet.NewFuncSpec("main").
    Statement("$T($S)", poet.TypeReferenceFromInstance(fmt.Println), "Hello world!")

file := poet.NewFileSpec("main").

Getting Started

To get started, import ""

The end goal of go-poet is to create a compilable file. To construct a new file with package main

file := poet.NewFileSpec("main")

Files contain CodeBlocks which can be global variables, functions, structs, and interfaces. go-poet will handle any imports for you via TypeReferences. The types that you create or reference can be used in code via Templates.

Code Blocks


Functions can have parameters, result parameters, and statements within them.

add := poet.NewFuncSpec("add").
    Parameter("a", poet.Int).
    Parameter("b", poet.Int).
    ResultParameter("", poet.Int).
    Statement("return a + b")

which produces

func add(a int, b int) int {
    return a + b

To add control flow statements, use BlockStart and BlockEnd. Indentation will be handled for you.

loop := poet.NewFuncSpec("loop").
    BlockStart("for i := 0; i < 5; i++").
    Statement("$T($L)", poet.TypeReferenceFromInstance(fmt.Println), "i").


func loop() {
    for i := 0; i < 5; i++ {


Interfaces can have other interfaces embedded within them, as well as method declarations.

inter := poet.NewInterfaceSpec("AddWriter").


type AddWriter interface {
    add(a int, b int) int


Structs can have fields, directly attached methods, and a comment.

foo := poet.NewStructSpec("foo").
    Field("buf", poet.TypeReferenceFromInstance(&bytes.Buffer{}))

m := foo.MethodFromFunction("f", true, add)


type foo struct {
    buf *bytes.Buffer

func (f *foo) add(a int, b int) int {
    return a + b


Global variables and constants can be added directly to a file, either standalone or in groups.

file.GlobalVariable("a", poet.String, "$S", "hello")
file.GlobalConstant("b", poet.Int, "$L", 1)
var a string = "hello"

const b int = 1

or if you want to group them

    Variable("a", poet.Int, "$L", 7).
    Variable("b", poet.Int, "$L", 2).
    Constant("c", poet.Int, "$L", 3).
    Constant("d", poet.Int, "$L", 43)
const (
    c int = 3
    d int = 43

var (
    a int = 7
    b int = 2

Type References

To ensure type safe code and handle a generated file's imports, use TypeReferences.

For example, to use bytes.Buffer as a parameter to a function

poet.NewFuncSpec("foo").Parameter("buf", poet.TypeReferenceFromInstance(&bytes.Buffer{}))


func foo(buf *bytes.Buffer) {

The poet.TypeReferenceFromInstance function takes an instance of a variable or a function and uses reflection to determine its type and package.

Package Aliases

To use an aliased package's name from a TypeReference, use poet.TypeReferenceFromInstanceWithAlias.

poet.TypeReferenceFromInstanceWithAlias(&bytes.Buffer{}, "myAlias")

produces a TypeReference with type


Custom Names

For type aliases, you may want to reference the aliased name instead of the underlying type.

To do this, use poet.TypeReferenceFromInstanceWithCustomName

poet.TypeReferenceFromInstanceWithCustomName(uint8(0), "byte")

Unqualified Types

If you want a type to be unqualified, create a type alias with the prefix _unqualified followed by the name

type _unqualifiedBuffer bytes.Buffer
typeRef := TypeReferenceFromInstance(_unqualifiedBuffer{})

produces the type Buffer


Format strings are used to construct statements in functions or values for variables.

We currently support these format specifiers:

  • Strings $S Takes a string as input, surrounding it with quotes and escaping quotes within the input
  • Literals $L Takes any value as input, and uses Go's Sprintf %v formatting to write the input
  • Types $T Takes a TypeReference as input, and writes its qualified/aliased name


Dave Polansky

Kevin Deenanauth