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 fastgo — fastgo 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:
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_2 → V1_2).
apache
Replicates the apache/thrift Go generator. Names ending in Args or Result get an extra _ appended (GetUserArgs → GetUserArgs_). Uppercase words following _ keep an underscore prefix in the output.
ignore_initialisms disables the initialism correction (user_url → UserUrl 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:
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.
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.
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.
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:
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).
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.
Thriftgo
thriftgo is an Apache Thrift IDL compiler written in Go. It generates Go source code from
.thriftfiles and extends the standard compiler with a plugin system for custom code generation.What it does
.thriftdefinitions, 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.0only. Version 0.14.0 introduced breaking changes to core interfaces (TProtocol,TTransport,TProcessor) by addingcontext.Contextparameters, making it incompatible with code generated by thriftgo.To avoid the Apache Thrift runtime dependency entirely, use
no_default_serdesandno_processortogether — this generates plain Go structs withoutRead/Writemethods or processor/client code. Alternatively, usethrift_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 yourPATHso the installed binary is accessible.Install via
go install(recommended):Install from source:
Verify installation:
Quick start
Generate Go code from a Thrift IDL file:
Output is written to
./gen-go/<namespace>/.Usage
Global flags
--version--help-h--gen-gForm:
language[:key1=val1[,key2[,key3=val3]]].Available backends:
go,fastgo(experimental).--out-o./gen-<lang>Supports
{namespace}and{namespaceUnderscore}placeholders.--include-i--recurse-r--plugin-pForm:
plugin[=path][:key1=val1[,...]].--verbose-v--quiet-q--check-keywordsIntended to warn if identifiers use keywords from common languages.
--plugin-time-limit1m0means no limit.--quietsuppresses all output including warnings.--verboseadds info-level logs. When both are set,--quietwins.fastgobackend (experimental)The
fastgobackend generates additionalk-<file>.gofiles containing high-performanceFastRead,FastWrite, andBLengthmethods for structs, unions, and exceptions. It runs the standardgobackend first and then appends these files.fastgoaccepts the same options as thegobackend. Do not combine-g goand-g fastgo—fastgoalready runs thegobackend 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:Boolean options accept
true,false, or empty (empty meanstrue).thrift_import_path=<path>Default:
github.com/apache/thrift/lib/go/thrift.use_package=<path>=<repl>path=replacement.naming_style=<style>thriftgogolint,apache, orthriftgo.ignore_initialismsURL).package_prefix=<prefix>template=<name>slimorraw_struct.json_enum_as_textMarshalTextandUnmarshalTextfor enum values.enum_marshalMarshalTextfor enum values.enum_unmarshalUnmarshalTextfor enum values.gen_setterSet*methods for struct fields.gen_db_tagdb:"<fieldname>"struct tags.omitempty_for_optionalomitemptyJSON tags for optional fields.use_type_aliastypedefinstead of type definitions.validate_setvalue_type_in_containerscan_value_for_enumScanandValuemethods for enums.Implements
database/sqlinterfaces.reorder_fieldstyped_enum_stringkeep_unknown_fieldsgen_deep_equalDeepEqualfor structs, unions, and exceptions.Silently disabled when
template=slim.compatible_names_to names with aNewprefix orArgs/Resultsuffix.reserve_commentsnil_safefrugal_tagfrugalstruct tags.unescape_double_quotegen_type_metagen_json_tagjsonstruct tags.always_gen_json_tagjsontags even when ago.tagannotation is present.snake_style_json_tagsnake_casestyle for JSON tags.lower_camel_style_json_taglowerCamelCasestyle for JSON tags.with_reflection*-reflection.gofiles with runtime type metadata for structs.Required by
with_field_mask.enum_as_int_32int32.trim_idljson_stringerString()method.with_field_maskAlso requires
with_reflection.field_mask_halfwayfield_mask_zero_requiredDefault: write current value.
thrift_streamingno_default_serdesno_alias_type_reflection_method*-reflection.gofor types annotated withthrift.is_alias="true".enable_ref_interfacethrift.is_interface="true"in referenced Thrift files.use_optionUnrecognized keys are silently ignored.
streamxRequires
thrift_streaming.no_fmtskip_emptyno_processorget_enum_annotationGetAnnotationmethods for enum types.apache_warningRead/Writemethods when Apache codec is used.apache_adaptorRead/Writebodies with delegate calls to the Kitex fast codec adaptor.Uses
gopkg/protocol/thrift/apache/adaptor.skip_go_gencode_refspecified in
idl-ref.yaml.code_ref_slimcode_refbut generates fewer local aliases to reduce import conflicts.exp_code_refcode_ref_slimbut keeps some structs as local definitions. (experimental)keep_code_ref_namecode_ref, write the ref file with the same filenameinstead of appending
-ref.go.enable_nested_structthrift.nested="true"is set on a field.Requires
slimorraw_structtemplate.Flag details
Explanations for flags that require more context than the table provides.
naming_styleControls how IDL identifiers (struct names, field names, etc.) are converted to Go identifiers. All three styles split on
_and capitalize words, with common initialisms likeurl,id,httpupgraded to uppercase (URL,ID,HTTP) by default.thriftgo(default)_to any names.golint_namestays_Name) and underscores between digits (v1_2→V1_2).apacheArgsorResultget an extra_appended (GetUserArgs→GetUserArgs_). Uppercase words following_keep an underscore prefix in the output.ignore_initialismsdisables the initialism correction (user_url→UserUrlinstead ofUserURL).compatible_namesthriftgo generates
<FuncName>Argsand<FuncName>Resultstructs for every RPC method. If your IDL defines a user struct whose name ends inArgsorResult, or starts withNew, the names collide.compatible_namesappends_to the user-defined name to resolve this.Without
compatible_names: compile error due to duplicate name. With it:GetUserArgs_is generated instead.value_type_in_containerBy default, struct-like types inside
list,set, ormapare generated as pointer types:With
value_type_in_container:Use this to avoid heap allocations when container elements are small and frequently iterated.
gen_type_metaGenerates an
init()block in each file that registers every struct into a global metadata registry: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_stringerChanges the generated
String()method on structs to return a JSON representation instead of Go’s defaultfmt.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_requiredThese 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.gofiles containing type descriptors (field names, IDs, types). Required by field-mask for path validation.with_field_mask: adds a_fieldmask *fieldmask.FieldMaskfield andSet_FieldMask()method to each struct.Read/Writethen 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:
thrift_streamingandstreamxTwo 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 usegithub.com/cloudwego/kitex/pkg/streaming(the streamx API). Requiresthrift_streaming.Use
thrift_streamingalone when targeting the default Kitex streaming API. Addstreamxwhen targeting the newer streamx API.no_default_serdesBy default every struct gets
Read(iprot thrift.TProtocol)andWrite(oprot thrift.TProtocol)methods containing the full field-by-field serialization logic. Withno_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_warningandapache_adaptorTwo options for managing the coexistence of Apache Thrift codec and Kitex fast codec:
apache_warning: keeps the standard generatedRead/Writelogic but prepends a call toapache_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 entireRead/Writebody withapache_adaptor.AdaptRead(p, iprot)/apache_adaptor.AdaptWrite(p, oprot)fromgithub.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_adaptoris set, the fullRead/Writebody (including anyapache_warningcall) is not generated.code_ref,code_ref_slim,exp_code_ref,keep_code_ref_nameWhen multiple services share types from a common IDL, regenerating that IDL for each service produces duplicate definitions. The
code_reffamily solves this by importing types from an already-generated package instead of regenerating them.Requires an
idl-ref.yaml(oridl-ref.yml) in the working directory that maps IDL paths to existing Go package paths:code_ref: for each IDL with a ref entry, replaces local type generation with imports from the specified path. Generates a<name>-ref.gofile containing type aliases.code_ref_slim: generates fewer aliases thancode_ref, reducing the chance of import conflicts.exp_code_ref: likecode_ref_slimbut 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_idlBefore 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:
use_optionThrift IDL allows arbitrary string annotations on fields and types. With
use_option, annotations whose keys match known option definitions from thethrift_optionextension 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_structBy 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 theslimorraw_structtemplate; thriftgo automatically switches toslimif this option is set and no template is specified.Input / Output behavior
.thriftIDL file as a positional argument. Additional include search paths via-i.Requeston stdin.Responseto stdout.-v/-q)../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.
THRIFTGO_DEBUG""1to enable CPU and heap profiling (writesthriftgo-cpu.pprofandthriftgo-heap.pprof).Precedence: flags > environment variables > defaults.
idl-ref.yamlThe
code_ref,code_ref_slim, andexp_code_refflags read anidl-ref.yaml(oridl-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.Examples
Generate Go code with golint naming and setter methods:
Recursively generate code for an IDL and all its includes:
Generate to a custom output directory with a package prefix:
Use the slim template and skip formatting:
Generate with field-mask and reflection support:
Invoke an external plugin alongside the Go generator:
Exit codes
02Troubleshooting
require exactly 1 argument for the IDL parameter.thriftfile given, or multiple positional arguments provided.No output language(s) specified-gflag is missing.-g go(or another backend) to the command.found include circleincludechain in the IDL files..thriftfiles.unsupported naming stylenaming_style=.golint,apache,thriftgo.invalid argument for use_packageuse_packagevalue is not inpath=replacementform.use_package=some/pkg=replacement/pkg.--plugin-time-limit.--plugin-time-limit=5m, or set0for no limit.with_field_maskused withoutwith_reflection.with_reflectionto the same-goptions list.streamxused withoutthrift_streaming.thrift_streamingto the same-goptions list.enable_nested_structhas no effectslimorraw_structtemplate.template=slimto the options list.