Skip to content

cloudwego/thriftgo

Thriftgo

thriftgo is an Apache Thrift IDL compiler written in Go. It generates Go source code from .thrift files and extends the standard compiler with a plugin system for custom code generation.

What it does

  • Parses Thrift IDL files and generates Go code with extensive customization options.
  • Use it when you need to generate Go types, serialization code, or RPC interfaces from .thrift definitions, especially in the CloudWeGo ecosystem.

Compatibility

The generated Go code depends on the Apache Thrift Go runtime library. Thriftgo targets github.com/apache/thrift v0.13.0 only. Version 0.14.0 introduced breaking changes to core interfaces (TProtocol, TTransport, TProcessor) by adding context.Context parameters, making it incompatible with code generated by thriftgo.

To avoid the Apache Thrift runtime dependency entirely, use no_default_serdes and no_processor together — this generates plain Go structs without Read/Write methods or processor/client code. Alternatively, use thrift_import_path=<path> to redirect the import to a fork or vendored copy.

Installation

Prerequisites: Go 1.18 or later. Ensure $GOPATH/bin (default: ~/go/bin) is in your PATH so the installed binary is accessible.

Install via go install (recommended):

go install github.com/cloudwego/thriftgo@latest

Install from source:

go install github.com/cloudwego/thriftgo@latest

Verify installation:

thriftgo --version

Quick start

Generate Go code from a Thrift IDL file:

thriftgo -g go example.thrift

Output is written to ./gen-go/<namespace>/.

Usage

thriftgo [options] <file.thrift>

Global flags

Flag Short Type Default Description
--version bool false Print the compiler version and exit.
--help -h bool false Print help message and exit.
--gen -g string Target language and options (required). Repeatable for multiple backends.
Form: language[:key1=val1[,key2[,key3=val3]]].
Available backends: go, fastgo (experimental).
--out -o string ./gen-<lang> Output directory.
Supports {namespace} and {namespaceUnderscore} placeholders.
--include -i string Add a search path for includes. Repeatable.
--recurse -r bool false Recursively generate code for all included files.
--plugin -p string Invoke an external plugin. Repeatable.
Form: plugin[=path][:key1=val1[,...]].
--verbose -v bool false Output detailed info logs to stderr.
--quiet -q bool false Suppress all warnings and info logs.
--check-keywords bool true Parsed but currently unused.
Intended to warn if identifiers use keywords from common languages.
--plugin-time-limit duration 1m Execution time limit for plugins. 0 means no limit.

--quiet suppresses all output including warnings. --verbose adds info-level logs. When both are set, --quiet wins.

fastgo backend (experimental)

The fastgo backend generates additional k-<file>.go files containing high-performance FastRead, FastWrite, and BLength methods for structs, unions, and exceptions. It runs the standard go backend first and then appends these files.

thriftgo -g fastgo example.thrift

fastgo accepts the same options as the go backend. Do not combine -g go and -g fastgofastgo already runs the go backend internally, so using both would produce duplicate files.

Go backend options (-g go:<options>)

Options are passed as a comma-separated list after go:. Combine multiple options with commas:

thriftgo -g go:naming_style=golint,gen_setter,template=slim example.thrift

Boolean options accept true, false, or empty (empty means true).

Option Default Description
thrift_import_path=<path> Override the thrift runtime import path.
Default: github.com/apache/thrift/lib/go/thrift.
use_package=<path>=<repl> Replace an import path. Form: path=replacement.
naming_style=<style> thriftgo Identifier naming style: golint, apache, or thriftgo.
ignore_initialisms false Disable spelling correction of initialisms (e.g. URL).
package_prefix=<prefix> Prepend a package prefix to all generated import paths.
template=<name> Use an alternative code template: slim or raw_struct.
json_enum_as_text false Generate MarshalText and UnmarshalText for enum values.
enum_marshal false Generate MarshalText for enum values.
enum_unmarshal false Generate UnmarshalText for enum values.
gen_setter false Generate Set* methods for struct fields.
gen_db_tag false Generate db:"<fieldname>" struct tags.
omitempty_for_optional true Generate omitempty JSON tags for optional fields.
use_type_alias true Generate type aliases for typedef instead of type definitions.
validate_set true Generate code to validate uniqueness of set elements.
value_type_in_container false Use value types (not pointers) for struct-like types in containers.
scan_value_for_enum true Generate Scan and Value methods for enums.
Implements database/sql interfaces.
reorder_fields false Reorder struct fields to improve memory layout.
typed_enum_string false Prefix the type name to enum string representations.
keep_unknown_fields false Generate code to store unrecognized fields in structs.
gen_deep_equal false Generate DeepEqual for structs, unions, and exceptions.
Silently disabled when template=slim.
compatible_names false Append _ to names with a New prefix or Args/Result suffix.
reserve_comments false Preserve comments from the Thrift IDL in generated code.
nil_safe false Generate nil-safe getter methods.
frugal_tag false Generate frugal struct tags.
unescape_double_quote true Unescape double quotes in tag literals.
gen_type_meta false Generate and register type metadata for structs.
gen_json_tag true Generate json struct tags.
always_gen_json_tag false Generate json tags even when a go.tag annotation is present.
snake_style_json_tag false Use snake_case style for JSON tags.
lower_camel_style_json_tag false Use lowerCamelCase style for JSON tags.
with_reflection false Generate *-reflection.go files with runtime type metadata for structs.
Required by with_field_mask.
enum_as_int_32 false Generate enum types as int32.
trim_idl false Remove unused definitions from the IDL before generating code.
json_stringer false Use JSON marshaling in the String() method.
with_field_mask false Generate field-mask support for structs.
Also requires with_reflection.
field_mask_halfway false Support setting field-mask on non-root structs.
field_mask_zero_required false Write zero value for required fields filtered by field-mask.
Default: write current value.
thrift_streaming false Recognize streaming annotations and generate streaming service methods.
no_default_serdes false Skip generating default Thrift serialization/deserialization code.
no_alias_type_reflection_method false Skip type reflection methods in *-reflection.go for types annotated with
thrift.is_alias="true".
enable_ref_interface false Generate interface fields without pointer types for types annotated with
thrift.is_interface="true" in referenced Thrift files.
use_option false Parse Thrift annotations into struct-style option fields.
Unrecognized keys are silently ignored.
streamx false Generate streaming interfaces using streamx mode.
Requires thrift_streaming.
no_fmt false Skip formatting of generated Go code.
skip_empty false Skip generating files that have no content.
no_processor false Skip generating the default Thrift processor and client.
get_enum_annotation false Generate GetAnnotation methods for enum types.
apache_warning false Call a runtime warning function in Read/Write methods when Apache codec is used.
apache_adaptor false Replace Read/Write bodies with delegate calls to the Kitex fast codec adaptor.
Uses gopkg/protocol/thrift/apache/adaptor.
skip_go_gen false Skip Go code generation; only parse the IDL and execute plugins.
code_ref false Instead of regenerating types, import them from the package path
specified in idl-ref.yaml.
code_ref_slim false Like code_ref but generates fewer local aliases to reduce import conflicts.
exp_code_ref false Like code_ref_slim but keeps some structs as local definitions. (experimental)
keep_code_ref_name false When using code_ref, write the ref file with the same filename
instead of appending -ref.go.
enable_nested_struct false Generate nested fields when thrift.nested="true" is set on a field.
Requires slim or raw_struct template.

Flag details

Explanations for flags that require more context than the table provides.

naming_style

Controls how IDL identifiers (struct names, field names, etc.) are converted to Go identifiers. All three styles split on _ and capitalize words, with common initialisms like url, id, http upgraded to uppercase (URL, ID, HTTP) by default.

Style Key differences
thriftgo (default) Capitalizes words that start with a lowercase letter; already-uppercase words are left unchanged. Does not append _ to any names.
golint Follows stricter golint-style rules. Preserves leading underscores (_name stays _Name) and underscores between digits (v1_2V1_2).
apache Replicates the apache/thrift Go generator. Names ending in Args or Result get an extra _ appended (GetUserArgsGetUserArgs_). Uppercase words following _ keep an underscore prefix in the output.

ignore_initialisms disables the initialism correction (user_urlUserUrl instead of UserURL).

compatible_names

thriftgo generates <FuncName>Args and <FuncName>Result structs for every RPC method. If your IDL defines a user struct whose name ends in Args or Result, or starts with New, the names collide. compatible_names appends _ to the user-defined name to resolve this.

# IDL
struct GetUserArgs { 1: string id }   # would collide with generated GetUser_args

Without compatible_names: compile error due to duplicate name. With it: GetUserArgs_ is generated instead.

value_type_in_container

By default, struct-like types inside list, set, or map are generated as pointer types:

// default
type MyStruct struct { Items []*Inner }

With value_type_in_container:

// with value_type_in_container
type MyStruct struct { Items []Inner }

Use this to avoid heap allocations when container elements are small and frequently iterated.

gen_type_meta

Generates an init() block in each file that registers every struct into a global metadata registry:

func init() {
    meta.RegisterStruct(NewMyStruct, <serialized-IDL-bytes>)
}

This enables runtime reflection-based construction of structs by name. Used by frameworks that need to instantiate types dynamically without knowing them at compile time.

json_stringer

Changes the generated String() method on structs to return a JSON representation instead of Go's default fmt.Sprintf("%+v", p)-style output. Useful when struct values are logged or printed and a JSON format is preferred.

with_reflection, with_field_mask, field_mask_halfway, field_mask_zero_required

These four flags work together to enable field-mask support — a mechanism for selectively serializing/deserializing only a subset of struct fields (similar to Protobuf FieldMask).

  • with_reflection: generates *-reflection.go files containing type descriptors (field names, IDs, types). Required by field-mask for path validation.
  • with_field_mask: adds a _fieldmask *fieldmask.FieldMask field and Set_FieldMask() method to each struct. Read/Write then consult the mask and skip excluded fields.
  • field_mask_halfway: by default a field-mask may only be set on the root (top-level) struct. This option allows setting it on any nested struct. Note: if multiple parent objects share the same child, only one parent's mask will take effect.
  • field_mask_zero_required: required fields that are excluded by a mask are normally still written with their current value. With this option they are written as zero values instead.

Minimal usage:

thriftgo -g go:with_field_mask,with_reflection service.thrift

thrift_streaming and streamx

Two flags, two levels of streaming support:

  • thrift_streaming: without this, any service method with a streaming annotation is silently dropped from the generated output. Enable it to retain and generate streaming methods.
  • streamx: changes the generated streaming interface types to use github.com/cloudwego/kitex/pkg/streaming (the streamx API). Requires thrift_streaming.

Use thrift_streaming alone when targeting the default Kitex streaming API. Add streamx when targeting the newer streamx API.

no_default_serdes

By default every struct gets Read(iprot thrift.TProtocol) and Write(oprot thrift.TProtocol) methods containing the full field-by-field serialization logic. With no_default_serdes, those method bodies are replaced with stub insertion points (ExtraFieldMap, ExtraStruct), allowing a plugin or external code to supply alternative serialization (e.g. Frugal, fast codec).

apache_warning and apache_adaptor

Two options for managing the coexistence of Apache Thrift codec and Kitex fast codec:

  • apache_warning: keeps the standard generated Read/Write logic but prepends a call to apache_warning.WarningApache(typeName) in each method. This emits a runtime log warning whenever the Apache codec path is taken, helping identify hot paths that should be migrated.
  • apache_adaptor: replaces the entire Read/Write body with apache_adaptor.AdaptRead(p, iprot) / apache_adaptor.AdaptWrite(p, oprot) from github.com/cloudwego/gopkg. The adaptor transparently routes calls to Kitex fast codec. Use this when migrating existing Apache-codec-dependent code without changing call sites.

These are mutually exclusive: when apache_adaptor is set, the full Read/Write body (including any apache_warning call) is not generated.

code_ref, code_ref_slim, exp_code_ref, keep_code_ref_name

When multiple services share types from a common IDL, regenerating that IDL for each service produces duplicate definitions. The code_ref family solves this by importing types from an already-generated package instead of regenerating them.

Requires an idl-ref.yaml (or idl-ref.yml) in the working directory that maps IDL paths to existing Go package paths:

ref:
  path/to/shared.thrift: github.com/myorg/shared/gen
  • code_ref: for each IDL with a ref entry, replaces local type generation with imports from the specified path. Generates a <name>-ref.go file containing type aliases.
  • code_ref_slim: generates fewer aliases than code_ref, reducing the chance of import conflicts.
  • exp_code_ref: like code_ref_slim but keeps some structs as local definitions rather than aliases (experimental).
  • keep_code_ref_name: writes the ref file using the same filename as the normal output file instead of appending -ref.go.

trim_idl

Before generating, walks the IDL and removes all definitions (structs, enums, typedefs, etc.) that are not reachable from service definitions. Useful when a large shared IDL contains many types but only a small subset are used by a specific service.

A warning is printed showing how many definitions were trimmed:

[WARN] removed 42 unused structures with 187 fields

use_option

Thrift IDL allows arbitrary string annotations on fields and types. With use_option, annotations whose keys match known option definitions from the thrift_option extension are parsed into typed struct-style option fields in the generated code. Keys that do not match any known option are silently ignored.

enable_nested_struct

By default every IDL field becomes a named, typed Go field. A field annotated with thrift.nested="true" is instead embedded anonymously (Go struct embedding), so its sub-fields are promoted to the parent struct. Only valid with the slim or raw_struct template; thriftgo automatically switches to slim if this option is set and no template is specified.

Input / Output behavior

  • Input: A single .thrift IDL file as a positional argument. Additional include search paths via -i.
  • Stdin: Not used by the main tool. Plugins receive a serialized Request on stdin.
  • Stdout: Plugins write their serialized Response to stdout.
  • Stderr: Warnings and info logs (controlled by -v/-q).
  • Output files: Written to ./gen-<lang>/<namespace>/ by default. Override with -o.

Output is not written to stdout and cannot be piped directly.

Configuration

No config file. All configuration is via flags and environment variables.

Name Type Required Default Description
THRIFTGO_DEBUG string No "" Set to 1 to enable CPU and heap profiling (writes thriftgo-cpu.pprof and thriftgo-heap.pprof).

Precedence: flags > environment variables > defaults.

idl-ref.yaml

The code_ref, code_ref_slim, and exp_code_ref flags read an idl-ref.yaml (or idl-ref.yml) file from the working directory. It maps IDL file paths to an existing Go package path, so thriftgo imports types from that package instead of regenerating them.

ref:
  path/to/shared.thrift: github.com/myorg/shared/gen

Examples

Generate Go code with golint naming and setter methods:

thriftgo -g go:naming_style=golint,gen_setter example.thrift

Recursively generate code for an IDL and all its includes:

thriftgo -r -g go service.thrift

Generate to a custom output directory with a package prefix:

thriftgo -o ./generated -g go:package_prefix=github.com/myorg/myproject service.thrift

Use the slim template and skip formatting:

thriftgo -g go:template=slim,no_fmt service.thrift

Generate with field-mask and reflection support:

thriftgo -g go:with_field_mask,with_reflection service.thrift

Invoke an external plugin alongside the Go generator:

thriftgo -g go -p my-plugin:option1=val1 service.thrift

Exit codes

Code Meaning
0 Success.
2 Error: invalid arguments, IDL parse failure, semantic error, generation failure, or no output language specified.

Troubleshooting

Problem Cause Fix
require exactly 1 argument for the IDL parameter No .thrift file given, or multiple positional arguments provided. Pass exactly one IDL file as the last argument.
No output language(s) specified -g flag is missing. Add -g go (or another backend) to the command.
found include circle Circular include chain in the IDL files. Break the circular dependency in the .thrift files.
unsupported naming style Invalid value passed to naming_style=. Use one of: golint, apache, thriftgo.
invalid argument for use_package use_package value is not in path=replacement form. Use the form use_package=some/pkg=replacement/pkg.
Plugin times out Plugin takes longer than --plugin-time-limit. Increase the limit: --plugin-time-limit=5m, or set 0 for no limit.
Field-mask has no effect with_field_mask used without with_reflection. Add with_reflection to the same -g options list.
Streaming functions missing from output streamx used without thrift_streaming. Add thrift_streaming to the same -g options list.
enable_nested_struct has no effect Not using the slim or raw_struct template. Add template=slim to the options list.

About

An implementation of thrift compiler in go language.

Topics

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors