davecgh/go-spew
Implements a deep pretty printer for Go data structures to aid in debugging
Healthy across all four use cases
weakest axisPermissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓20 active contributors
- ✓ISC licensed
- ✓CI configured
Show all 6 evidence items →Show less
- ✓Tests present
- ⚠Stale — last commit 2y ago
- ⚠Concentrated ownership — top contributor handles 71% of recent commits
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/davecgh/go-spew)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/davecgh/go-spew on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: davecgh/go-spew
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/davecgh/go-spew shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across all four use cases
- 20 active contributors
- ISC licensed
- CI configured
- Tests present
- ⚠ Stale — last commit 2y ago
- ⚠ Concentrated ownership — top contributor handles 71% of recent commits
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live davecgh/go-spew
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/davecgh/go-spew.
What it runs against: a local clone of davecgh/go-spew — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in davecgh/go-spew | Confirms the artifact applies here, not a fork |
| 2 | License is still ISC | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 791 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of davecgh/go-spew. If you don't
# have one yet, run these first:
#
# git clone https://github.com/davecgh/go-spew.git
# cd go-spew
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of davecgh/go-spew and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "davecgh/go-spew(\\.git)?\\b" \\
&& ok "origin remote is davecgh/go-spew" \\
|| miss "origin remote is not davecgh/go-spew (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(ISC)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"ISC\"" package.json 2>/dev/null) \\
&& ok "license is ISC" \\
|| miss "license drift — was ISC at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "spew/spew.go" \\
&& ok "spew/spew.go" \\
|| miss "missing critical file: spew/spew.go"
test -f "spew/config.go" \\
&& ok "spew/config.go" \\
|| miss "missing critical file: spew/config.go"
test -f "spew/dump.go" \\
&& ok "spew/dump.go" \\
|| miss "missing critical file: spew/dump.go"
test -f "spew/format.go" \\
&& ok "spew/format.go" \\
|| miss "missing critical file: spew/format.go"
test -f "spew/bypass.go" \\
&& ok "spew/bypass.go" \\
|| miss "missing critical file: spew/bypass.go"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 791 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~761d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/davecgh/go-spew"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
go-spew implements a deep pretty printer for Go data structures that recursively formats complex values (structs, maps, slices, pointers, interfaces) into human-readable output with optional type annotations and pointer addresses. It solves the debugging problem of inspecting nested Go objects that the standard fmt package handles poorly, enabling developers to see the full structure and relationships within complex data at a glance. Single package structure: spew/ contains the core implementation split into bypass.go/bypasssafe.go (reflection helpers), common.go (shared state), config.go (configuration), dump.go (Dump/Fdump/Sdump functions), and format.go (Printf-style formatting). Tests are colocated with _test.go suffixes, and example_test.go provides runnable usage examples.
👥Who it's for
Go developers debugging applications who need to inspect complex nested data structures during development and testing. Test suite authors writing assertions and debugging test failures. Backend engineers working with large struct hierarchies, circular references, or unexported fields.
🌱Maturity & risk
Highly mature and stable. The package has 100% test coverage (documented in test_coverage.txt), comprehensive test files (dump_test.go, format_test.go, spew_test.go), active CI/CD via .travis.yml, and handles edge cases like CGO builds (dumpcgo_test.go) and unsafe operations. No breaking changes are typical—this is a stable debugging utility used widely in the Go ecosystem.
Very low risk. The codebase has zero external dependencies (only stdlib), a focused scope limited to printing, and is a single-file import (github.com/davecgh/go-spew/spew). The main risk is single-maintainer maintenance (davecgh), but the stable nature and 100% test coverage mean bugs are unlikely. Last commit age and open issues are not visible in provided data, so check GitHub directly.
Active areas of work
Without commit history in the provided data, the repo appears in maintenance mode rather than active feature development. The stable feature set (Dump, Fdump, Sdump, Printf variants with %v/%+v/%#v/%#+v flags) is complete. Check GitHub issues and recent commits to see if bug fixes or Go version compatibility updates are in flight.
🚀Get running
git clone https://github.com/davecgh/go-spew.git
cd go-spew
go test ./spew
Daily commands:
This is a library, not an executable. To test: go test ./spew. To use in your own code: import "github.com/davecgh/go-spew/spew" then call spew.Dump(myVar) or spew.Printf("%+v", myVar).
🗺️Map of the codebase
spew/spew.go— Main entry point exporting public API functions (Dump, Println, Printf, Sprintf) that all users interact with; defines the primary interface.spew/config.go— Configuration structure (Config) that controls all formatting behavior; every contributor must understand how user preferences flow through the system.spew/dump.go— Core dump implementation handling recursive traversal of Go data structures; the engine of the pretty printer.spew/format.go— String formatting layer that converts internal representations to human-readable output; critical for output correctness.spew/bypass.go— Unsafe reflection bypass for accessing unexported struct fields; essential architectural decision for deep inspection capability.spew/common.go— Shared utilities (canConvert, unsafeAddr, etc.) used across dump and format operations; foundational helper logic.
🧩Components & responsibilities
- spew.Dump() / Printf() / Sprintf() (Go stdlib fmt, io.Writer) — Public API; routes calls to Config methods; handles writer output
- Failure mode: Panic if input is nil or invalid writer; otherwise handles all Go types gracefully
- Config (Struct with string/bool/int fields) — User-facing options (Indent, DisablePointerAddresses, MaxDepth, etc.); controls dump behavior
- Failure mode: Invalid config values (negative indent, etc.) may produce malformed output
- dumpPtr() traversal (reflect, unsafe, sync (seenPointers)) — Core recursive engine; inspects type via reflection and unsafe access; manages pointer cycles
- Failure mode: Panic on reflection errors or unsafe memory access; infinite loop if cycle detection fails
- bypass (unsafe) / bypasssafe (safe fallback) (unsafe pointers, reflect for fallback) — Low-level field access; tries unsafe first, falls back to safe reflection
- Failure mode: Unsafe version may panic on layout changes; safe version silently omits inaccessible fields
- format.Sprintf() (strings.Builder, fmt.Sprintf) — Formats dumped output into final string with indentation, elision, and Config rules applied
- Failure mode: Memory exhaustion on very deep/large structures; no built-in size limits
🔀Data flow
User code→spew.Dump() / Printf() / Sprintf()— User calls public API with data to inspect and optional Configspew.Dump()→Config— undefined
🛠️How to make changes
Add support for a new Go type in dumps
- Identify the type's reflection kind in spew/dump.go's dumpPtr function switch statement (
spew/dump.go) - Add a new case branch to handle the type (e.g., reflect.Chan, reflect.Interface) (
spew/dump.go) - Implement type-specific traversal logic following patterns from existing cases (map, slice, struct, etc.) (
spew/dump.go) - Add corresponding formatting rules in spew/format.go if custom formatting is needed (
spew/format.go) - Add test cases covering the new type in spew/dump_test.go (
spew/dump_test.go)
Add a new configuration option to control dump behavior
- Add a new boolean or string field to the Config struct (
spew/config.go) - Document the option in the Config struct comments (
spew/config.go) - Reference the config field in spew/dump.go where the decision is made (e.g., in dumpPtr) (
spew/dump.go) - Update spew/format.go to respect the new configuration during output formatting (
spew/format.go) - Add test cases in spew/dump_test.go or spew/format_test.go covering the new behavior (
spew/dump_test.go)
Handle a new edge case or fix a reflection limitation
- Add the edge case test to spew/dump_test.go or spew/common_test.go (
spew/dump_test.go) - Implement the fix in the appropriate layer: spew/common.go (utilities), spew/dump.go (traversal), or spew/bypass.go (unsafe access) (
spew/common.go) - If the fix affects type detection or conversion, update canConvert or related helpers in spew/common.go (
spew/common.go) - Run existing tests to ensure no regressions across dump_test.go, dumpcgo_test.go, and dumpnocgo_test.go (
spew/dump_test.go)
🔧Why these technologies
- Go reflection package — Core mechanism for inspecting type information and traversing arbitrary Go data structures at runtime without code generation.
- Unsafe pointers (spew/bypass.go) — Enables access to unexported struct fields that reflection normally hides, providing comprehensive deep inspection capability.
- Printf-style formatting (spew/format.go) — Familiar API for developers; allows integration with standard logging and testing frameworks (testing.T, log packages).
- Build tags (dumpcgo_test.go, dumpnocgo_test.go) — Allows platform-specific testing for CGO environments vs. pure Go; ensures compatibility across build configurations.
⚖️Trade-offs already made
-
Use unsafe memory access to inspect unexported fields
- Why: Unsafe access is the only way to achieve true deep inspection of opaque types and private fields.
- Consequence: Introduces potential fragility across Go versions if internal memory layouts change; requires fallback (bypasssafe.go) for environments where unsafe is unavailable.
-
Recursive traversal with cycle detection (seenPointers map)
- Why: Prevents infinite loops on circular data structures while maintaining readability.
- Consequence: Cycle detection overhead; must track all visited pointers; may use significant memory for large graphs.
-
Reflect-based traversal without custom type handlers
- Why: Simplifies implementation and ensures all types are handled uniformly.
- Consequence: Cannot optimize for domain-specific types (e.g., custom JSON marshalers); output format is fixed.
-
Inline formatting during dump (not separate AST)
- Why: Simpler, faster implementation; single-pass traversal.
- Consequence: Harder to extend for alternative output formats (XML, JSON) without rewriting core logic.
🚫Non-goals (don't propose these)
- Does not provide JSON or machine-readable output formats
- Does not support custom type handlers or Stringer interfaces
- Does not provide incremental/streaming dump for very large structures
- Does not support platform-independent serialization (only human-readable debug output)
🪤Traps & gotchas
The bypass.go module uses unsafe pointers and may not work on all architectures—the codebase falls back to bypasssafe.go gracefully but you won't see unexported struct fields in output. CGO builds are tested separately (dumpcgo_test.go) because unsafe behavior differs. The pretty printer expands all reachable values recursively; passing a circular reference will cause infinite recursion unless you use spew.Config.MaxDepth to limit depth.
🏗️Architecture
💡Concepts to learn
- Unsafe pointer access to unexported fields — go-spew uses
unsafe.Pointerarithmetic inbypass.goto read unexported struct fields that reflection normally forbids—critical for complete struct inspection but requires architecture-specific handling - Circular reference detection via visited map — The State struct in
common.gotracks visited pointer addresses to prevent infinite recursion when dumping self-referential data structures (e.g., linked lists, graphs) - Recursive reflection introspection — go-spew deeply walks the Go type system using
reflect.Value.Kind(),Type(), and field iteration to determine how to format each value—essential to understand the implementation strategy - Format verb customization (%v, %+v, %#v, %#+v) — go-spew extends Go's fmt package verbs with additional flags (+ for pointers, # for types) parsed and handled in
format.go—allows compact inline printing modes - Indentation state machine — The State struct manages nesting level and indent string accumulation to produce aligned, readable output; understanding indent string management is key to modifying output formatting
- Interface{} dynamic type resolution — go-spew must handle
interface{}by dynamically inspecting the concrete type at runtime via reflection—crucial for printing values of unknown static type - Build tags (CGO conditional compilation) — The codebase uses build tags (
// +build cgo,// +build !cgo) in test files to handle different unsafe behavior in CGO vs. pure Go builds—important when modifying unsafe code paths
🔗Related repos
kr/pretty— Alternative pretty printer for Go values with similar goals but different formatting style; compare output for preferencedavecgh/go-xdr— Same author's serialization library; often used alongside go-spew to debug marshaling/unmarshaling of complex data structuresstretchr/testify— Popular assertion library that internally uses go-spew for human-readable diff output in test failuresgoogle/go-cmp— Modern alternative for deep equality testing and diffing; designed as a better alternative to reflect.DeepEqual and used with go-spew for debugging diffs
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add Go 1.18+ generics compatibility tests
The repo has no test coverage for Go generics (1.18+). With the rise of generic code in the Go ecosystem, go-spew should demonstrate proper handling of generic types, type parameters, and constraint interfaces. This would ensure the pretty printer works correctly with modern Go code patterns.
- [ ] Create spew/generics_test.go to test generic function signatures, generic struct fields, and parameterized types
- [ ] Test output formatting for constraint interfaces like comparable, any, and custom constraints
- [ ] Verify behavior with nested generics (e.g., map[string][]T and struct with multiple type parameters)
- [ ] Compare test output against expected formats in spew/testdata/
Replace Travis CI with GitHub Actions workflow
The repo uses .travis.yml for CI, which is outdated. GitHub Actions is now the standard for GitHub projects. This modernizes the CI pipeline, improves integration with GitHub, and removes dependency on external CI services.
- [ ] Create .github/workflows/test.yml with matrix testing for Go versions (1.13+, latest)
- [ ] Include steps for: go test ./..., coverage reporting (integrate with coveralls), and go vet
- [ ] Remove or deprecate .travis.yml with a note in README.md
- [ ] Update README badges to reference GitHub Actions instead of Travis CI
Add concurrent safety tests for unsafe pointer bypass
The spew/bypass.go and spew/bypasssafe.go files handle unsafe pointer operations to inspect unexported fields. There are no tests validating thread-safe concurrent access patterns. Adding race condition tests would ensure the package is safe for concurrent use in multi-threaded applications.
- [ ] Create spew/bypass_race_test.go with -race flag-compatible tests
- [ ] Test concurrent calls to Dump/Sprintf on same/different data structures
- [ ] Verify that unsafe pointer dereferencing doesn't cause data races when called from multiple goroutines
- [ ] Run tests with 'go test -race ./...' to validate no race conditions exist
🌿Good first issues
- Add support for Go 1.18+ generic types in output formatting—currently
spew/dump.gomay not pretty-printgeneric[T]syntax distinctly; trace through the reflection cases and add a test indump_test.go. - Enhance the testdata helpers in
spew/testdata/dumpcgo.gowith examples of uncommon types (e.g.,sync.Mutex,time.Time,*os.File) and verify Dump output is sensible for each—add corresponding test cases tointernal_test.go. - Document the exact behavior of the unsafe field access in a comment block in
spew/bypass.goexplaining when and why it works, and add an example toexample_test.goshowing the difference between safe and unsafe output on a struct with unexported fields.
⭐Top contributors
Click to expand
Top contributors
- @davecgh — 71 commits
- @dajohi — 7 commits
- [@Patrick Mezard](https://github.com/Patrick Mezard) — 3 commits
- @briandorsey — 2 commits
- @TShadwell — 2 commits
📝Recent commits
Click to expand
Recent commits
d8f796a— travis: test against go 1.11 (dajohi)8991bc2— travis: test against go 1.10.x (dajohi)87df7c6— simpler, more robust bypass (rogpeppe)db69d09— vet: fix vet warnings (dajohi)ecdeabc— Add Go tip to coverage matrix (kevinburke)dce690a— Update tests for cgo changes to Go tip. (davecgh)a476722— travis: test against go 1.9 (dajohi)adab964— travis: test against 1.8.x (dajohi)9fadf46— travis: Use gometalinter (dajohi)e250ec7— Fix 'and/or' in the ISC license text (Fabio Rapposelli)
🔒Security observations
go-spew is a well-maintained debugging library with strong security posture. The main security concerns are inherent to its design as a deep data structure printer and appropriate use of the unsafe package. No critical vulnerabilities detected. The project maintains 100% test coverage, uses ISC license (permissive), and appears to follow Go security best practices. Primary recommendations focus on documentation of safe usage patterns and awareness of information disclosure risks when printing sensitive data structures.
- Low · Use of Unsafe Package —
spew/bypass.go, spew/bypasssafe.go, spew/internalunsafe_test.go. The presence of 'bypass.go' and 'bypasssafe.go' files, along with 'internalunsafe_test.go', suggests use of Go's unsafe package for reflection and memory manipulation. While necessary for a deep pretty printer, unsafe code can bypass Go's memory safety guarantees if misused. Fix: Ensure unsafe code is thoroughly tested and audited. Verify that unsafe operations are minimal and well-documented. Maintain comprehensive test coverage (already at 100%) and consider adding fuzzing tests to catch edge cases. - Low · Potential Information Disclosure via Pretty Printing —
spew/dump.go, spew/format.go. A deep pretty printer that outputs all data structure contents could inadvertently expose sensitive information (passwords, tokens, API keys) if used on objects containing such data. There's no built-in mechanism to redact sensitive fields. Fix: Document security considerations in README about not using go-spew on objects containing sensitive data. Consider adding optional field filtering or masking capabilities. Add security warnings in API documentation.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.