godump prints Go structs with + and - visibility markers, and can diff two of them
A minimal, developer-friendly pretty-printer and debug dumper for Go structs, inspired by Laravel’s dump() and Symfony’s VarDumper.
At a glance
- What is it?
- godump is a zero-dependency pretty printer for Go structs, slices and maps with terminal, HTML and JSON output, cyclic reference detection and truncation limits. Its distinguishing feature over go-spew and pp is the plus and minus marker distinguishing exported fields from unexported ones, plus file and line reporting on every dump.
- Who is it for?
- godump fits a Go service where you are inspecting structs at the boundary between packages and want to see unexported fields, compare two values after a change, or emit something a browser can render in a log pipeline, since no other option in this comparison offers HTML output or diff HTML.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 6 days ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 7, 2026, and from our analysis. They are not legal advice.
Star history
- goforj/godump1,770 ★ · +2
| Repository | 2026-10-16 | 2026-11-07 |
|---|---|---|
| goforj/godump | 1.8k | 1.8k |
2 Stars in the last 22 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
The plus and minus markers are the actual innovation
The basic call prints something specific:
type User struct { Name string }
godump.Dump(User{Name: "Alice"})
// #main.User {
// +Name => "Alice" #string
// }Three things in three lines. The `#main.User` prefix is the package-qualified type name, so you know which package a type came from when several share a name. The trailing `#string` is the underlying type of the value. And the `+` in front of `Name` marks the field as exported.
That last marker is the feature the comparison table isolates. go-spew and pp both handle unexported struct fields, but neither marks them. With `+` for exported and `-` for unexported, a dump shows you at a glance whether the field you are looking at is something other packages can actually reach, which is the question that matters when you are debugging why a value did not arrive where you expected.
The diff mode uses the same markers for a different purpose, where `+` and `-` become line changes:
before := User{Name: "Alice"}
after := User{Name: "Bob"}
godump.Diff(before, after)
// #main.User {
// - +Name => "Alice" #string
// + +Name => "Bob" #string
// }The type header stays, the changed field shows both values, and you read it as a normal diff. Working out what changed in a deeply nested structure by eye is where this earns its place.
Every feature has a runnable example directory: `examples/basic`, `examples/diff`, `examples/diffextended`, `examples/diffhtml`, `examples/diffstr`, `examples/dump`, `examples/dumphtml`, `examples/dumpjson`, `examples/dumpjsonstr`, `examples/dumpstr`, `examples/fdump`, `examples/dd`, `examples/builder`, `examples/kitchensink`, `examples/extended` and `examples/newdumper`.
Zero dependencies and Go 1.18, with go.mod showing both
The claim at the top of the README is that godump is a zero-dependency debug dumper, and the module file confirms it in the smallest way possible:
module github.com/goforj/godump
go 1.18There is no `require` block at all. A debugging library you add to a service brings no transitive dependencies, which means it cannot participate in a dependency conflict, cannot pull a version of something your project already pins, and cannot break when one of its own dependencies is yanked.
`go 1.18` is the language floor. That is old enough to be unremarkable in 2026, and it means godump compiles into anything from that release onward without pulling the project forward.
The README badge names 130 tests, and coverage is tracked through Codecov with a badge in the header.
The source layout is flat, which suits a library this size. `godump.go` is the dumper, `diff.go` is the comparison, each with its `_test.go` beside it, and `internal/` holds the unexported machinery. `docs/` holds the API documentation and a `generate.sh` script, and the examples have their own `go.mod` and `go.sum` so they compile as a separate module against the published API rather than the local tree.
The builder options are the escape hatch from sane defaults
The package-level functions cover the common cases. `Dump` prints, `DumpStr` returns a string, `DumpHTML` returns HTML, `DumpJSON` prints JSON, `Fdump` writes to an `io.Writer`, `Dd` dumps and exits, and the three diff variants print, stringify or render as HTML.
When the defaults do not fit, `NewDumper` takes options:
godump.NewDumper(
godump.WithMaxDepth(15),
godump.WithMaxItems(100),
godump.WithMaxStringLen(100000),
godump.WithWriter(os.Stdout),
godump.WithSkipStackFrames(10),
godump.WithDisableStringer(false),
godump.WithoutColor(),
).Dump(v)The three limits can prevent dumps of large values from becoming excessively long. Depth caps recursion, item count truncates long slices and maps, and string length caps a single large field. The defaults, 15, 100 and 100000, are generous for the struct-inspecting case and will need lowering if you dump something bigger.
`WithSkipStackFrames` with a default of 10 is the option to look at closely. It exists so that when godump reports the file and line of the call site, it reports yours rather than the frames inside godump itself. The default is a fixed number, so if your dump is wrapped in a helper function the attribution shifts.
`WithDisableStringer` interacts with types implementing `fmt.Stringer`. Left enabled, godump uses the type's own `String` method, which produces nicer output for types designed to be printed and useless output for types that implement it badly. Disabling it makes the reflection walk the actual fields, which is what you want when debugging.
Two more options exist as example directories rather than in the README's builder list: `examples/withexcludefields` and `examples/withfieldmatchmode`.
Comparing it to go-spew and pp, honestly
The README publishes a feature table against `go-spew` and `pp`, and inviting you to suggest improvements or additional comparisons, which is a good sign about how the author handles it.
Reading the table, the three libraries agree on the basics: all three give colorized terminal output, all three write to an `io.Writer`, all three handle unexported struct fields, all three handle structs, maps, slices, pointers and interfaces, and all three offer string output for testing. All three are Go-idiomatic and none is a general-purpose serializer.
godump's additions are HTML output, JSON helpers, the three diff functions, file and line reporting, explicit visibility markers, the three truncation limits, dump-and-die, pretty package-qualified type names and the builder API.
The table marks cyclic reference detection and control character escaping as supported for godump, while go-spew is marked as approximate for both. If you dump a structure with a back-reference, test that case yourself before relying on it.
The real trade-off is that the alternatives are older and more settled. If you only need terminal output for structs, go-spew is the boring choice. The reason to pick godump is one of the four godump-only columns.
The project is also listed in Awesome Go under the parsers, encoders and decoders section.
Contribution requires running a docs script, not just tests
The contribution note has two requirements and the second is the one people miss.
All tests must pass. Then you must run `./docs/generate.sh` to update the API index in the README before submitting a pull request. The API index is generated content embedded in the README, which explains the `<!-- test-count:embed:start -->` and `<!-- test-count:embed:end -->` markers around the 130-test badge at the top: the badge is generated too, and a pull request that does not regenerate it produces a diff that looks unrelated to the change.
There is also a requirement that all public functions have documentation blocks with examples. For a library whose selling point is readable output, having runnable examples on every exported function is a consistent standard.
The Makefile is unusually well organised, with a self-documenting `help` target implemented in Perl that parses `##` comments and groups targets by category. The targets are `test` running `go test./...`, `vet` running `go vet./...`, `docs-watch` running `sh docs/watcher.sh`, and a pair of modernization targets:
modernize: ##@modernization Apply Go modernization fixes.
@echo "Running gopls modernize with -fix..."
$(MODERNIZE_CMD) -test -fix ./...The modernize command is pinned to `golang.org/x/tools/gopls/internal/analysis/modernize/cmd/[email protected]` and fetched with `go run` on demand, so there is a `modernize-check` target that runs the same analysis without applying fixes, suitable for CI. Linting is golangci-lint via `.golangci.yml`.
Release history: v1.9.1 on 2026-02-27, v1.9.0 on 2025-12-24, v1.8.0 on 2025-12-20. The last push was on 2026-10-16, while the last listed release is v1.9.1 from February 2026. Licence is MIT. Licence is MIT.
Editorial conclusion
godump fits a Go service where you are inspecting structs at the boundary between packages and want to see unexported fields, compare two values after a change, or emit something a browser can render in a log pipeline, since no other option in this comparison offers HTML output or diff HTML. It is the wrong choice for a hot loop, because it reflects over unexported fields and renders a tree on every call, and the zero-dependency claim means you cannot blame a transitive upgrade when it misbehaves. Before adopting it in production logging, check `WithSkipStackFrames`, whose default of 10 is a guess about your call depth, and confirm the file and line attribution still points at your code rather than into godump itself.
Frequently asked questions
How do I install godump?
Run go get github.com/goforj/godump. The module requires Go 1.18 or later and declares no dependencies, so nothing else is pulled into your build.
How do I diff two structs with godump?
Use godump.Diff(a, b) to print, DiffStr(a, b) to return a string, or DiffHTML(a, b) for HTML. The output keeps the type header and marks changed fields with - for the old value and + for the new one.
How do I limit how much godump prints?
Build a Dumper with WithMaxDepth, WithMaxItems and WithMaxStringLen, whose defaults are 15, 100 and 100000 respectively. Lower them if you are dumping large slices, maps or long strings.
How does godump handle types that implement fmt.Stringer?
By default it uses the type's own String method. WithDisableStringer turns that off so the dumper reflects over the actual struct fields, which is what you usually want when debugging.
What does godump add over go-spew and pp?
HTML output, JSON helpers, diff functions, file and line reporting on each dump, + and - visibility markers for exported and unexported fields, the three truncation limits, dump-and-die, and a builder API. All three support terminal output, io.Writer and unexported fields.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/goforj-godump)Star history chart for your README
[](https://hysenlabs.com/projects/goforj-godump)Was this useful?