Library / SDK
sanity-io/litter avatar
sanity-io/litter

sanity-io/litter: readable Go data snapshots

Litter is a pretty printer library for Go data structures to aid in debugging and testing.

1,653 stars61 forksGoMIT

At a glance

What is it?
Litter is a Go pretty printer for debugging and snapshot-style tests, with compact output, pointer handling, global or local configuration, and custom type formatting. Its terse presentation is the main attraction, while recent release history is not documented.
Who is it for?
Litter fits Go developers who want readable debug output and consistent string-based snapshots, especially when JSON or YAML obscures type details. It is less suitable for projects that require stable output across unreleased formatter changes or need a documented release and upgrade process.
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 172 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 October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Why sanity-io/litter targets Go debugging and snapshots

Litter addresses a narrow but common Go problem: standard debug output can be hard to scan when a value contains nested structs, pointers, interfaces, maps, or repeated references. The library renders values as Go literals, which gives developers type names and field structure without switching immediately to a separate serialization format. That makes it useful during debugging and especially when a test needs to inspect a complete value directly.

The README positions snapshots as its main testing use case. A test can call `Sdump`, save the returned string as expected data, and compare later results against that file. Because the README states that Litter produces consistent, sorted output, this approach gives the test a readable record of the value rather than only a pass or fail message. It also preserves Go type names, including package qualifiers by default, which JSON normally removes.

This makes Litter most relevant to engineers working with application data structures, API payloads, domain models, and internal state. It is less compelling when output must become a public interchange format. The repository does not document a compatibility policy for emitted snapshots, so teams should not assume that every formatting change between Go or Litter versions is harmless.

How Litter renders values and repeated pointers

The package offers two central entry points. `Dump` writes a value to standard output, while `Sdump` returns the rendered text as a string. Both accept a value and optional formatting configuration. Their output includes newlines, indentation, type information, and aliases where needed, giving a nested value a structure that resembles valid Go source.

Pointer tracking is a notable part of the implementation described by the README. Litter detects circular references and aliasing. In a self-referential struct, it prints a comment containing a placeholder such as `p0`, then refers to that placeholder from the pointer field instead of recursively printing the object forever. Repeated non-circular pointers can also be replaced by aliases for consistency. Projects that require every pointer occurrence to be expanded can set `DisablePointerReplacement`, although circular references must still receive placeholder handling.

Litter also supports per-type presentation control through the `Dumper` interface. A type can implement `LitterDump(w io.Writer)` and write its preferred representation. Litter may indent that output to fit its current context and may add a pointer comment to the first line. This extension point is useful when a domain type already owns a clear textual representation, but it also transfers part of the formatting responsibility to the type. A custom dumper that emits unstable text, invalid Go syntax, or indentation-sensitive content can weaken the consistency that makes Litter attractive for tests.

Global litter.Config and per-call Options

Litter separates global configuration from a compartmentalized local configuration. The global `litter.Config` controls properties such as package-name removal, visibility of private fields, field exclusions, separators, compact output, and pointer replacement. `StripPackageNames` can shorten names when package context is already clear. `HomePackage` offers a narrower version of that behavior by naming the package whose types should lose their package prefix.

`HidePrivateFields` omits private struct fields. That can make output shorter, but it also reduces test coverage when a private field contains behaviorally important state. `FieldExclusions` accepts a regular expression and is documented as useful for hiding generated `XXX_` fields from `protoc-gen-go`. These controls are easy to misuse because an expected snapshot records only what the formatter is permitted to show. A test can pass while a hidden field changes.

The `Options` type duplicates the relevant configuration for a local formatter. That prevents one test or helper from changing the process-wide `litter.Config`, which is preferable when formatting settings differ by package or subsystem. The documented tradeoff is reduced convenience. Global configuration is concise, while `Options` requires code to construct and retain a formatter. The README does not document concurrency guarantees for mutating global configuration during concurrent formatting, so callers should avoid changing `litter.Config` while formatting work may be running unless that behavior is verified separately.

Installing Litter and creating the first Go dump

The repository declares module path `github.com/sanity-io/litter` and Go version `1.16` in `go.mod`. The README gives this installation command:

bash
$ go get -u github.com/sanity-io/litter

The `-u` flag instructs Go to update the module and its dependencies when fetching the package. Because the project has no GitHub releases, this module-based command is the installation route documented by the repository rather than a versioned release archive.

A Go file can import the package using the path declared in `go.mod`:

go
import "github.com/sanity-io/litter"

The README's basic example defines a recursive `Person` model and prints a value with `Dump`:

go
type Person struct {
	Name   string
	Age    int
	Parent *Person
}

litter.Dump(Person{
	Name:   "Bob",
	Age:    20,
	Parent: &Person{
		Name: "Jane",
		Age:  50,
	},
})

The documented output keeps the concrete type names and expands the nested parent. `Dump` prints directly to standard output, so the reader should see the formatted struct after the call. For snapshot tests, replace that behavior conceptually with `Sdump`, which returns a string that can be stored and compared. The README does not provide a supported command for generating or refreshing snapshots automatically; snapshot creation remains application code.

Using custom Dumpers without surrendering type context

A type can control its own Litter representation by implementing `Dumper`. The interface is deliberately small:

go
type Dumper interface {
	LitterDump(w io.Writer)
}

The method receives an `io.Writer`, allowing the implementation to emit one line or several. The repository's examples show a single-line integer type writing `<custom>` and a multiline struct writing a brace-delimited block. Litter handles surrounding indentation and may decorate the first line with a pointer comment. This means a custom type does not need to reproduce all of Litter's top-level formatting.

The interface is appropriate for types whose internal representation is too detailed or whose stable identity is already expressed by another syntax. The README does not specify escaping, error handling, concurrency requirements, or whether generated text must remain valid Go. Its earlier statement that Litter output is syntactically correct Go creates an important constraint for readers, but the custom dumper documentation does not explicitly guarantee that arbitrary `LitterDump` output preserves that property. If snapshots must compile or parse as Go, teams should check custom implementations rather than relying on the package-level claim alone.

Litter compared with Spew, JSON, and YAML snapshots

The README identifies Spew as the project that inspired Litter and says their emphasis differs: Litter focuses on terseness and readability. The README names Spew as an inspiration and contrasts Litter's focus on terseness and readability. The repository does not include a feature-by-feature Spew comparison, so details such as configuration coverage or formatting guarantees should not be inferred beyond the stated difference in focus.

JSON and YAML are the other practical alternatives named by the README. They are better suited when the expected value must be portable between languages or consumed as standard configuration data. Their ordinary representation does not retain Go-specific type names in the same way as Litter, and pointer identity or aliasing is not represented as an Litter-style placeholder. Litter is therefore the clearer choice for Go snapshots where the value's Go shape is part of what a developer wants to review.

There is a maintenance cost to choosing readable snapshots. The expected files can change when formatting behavior, configuration, package names, or Go type definitions change. The repository has no GitHub releases and does not document snapshot migration tooling. JSON may require fewer updates in a cross-language pipeline, but it loses some of the concrete type visibility that makes Litter useful. The correct choice depends on whether Go readability or format interchange is the primary requirement.

Maintenance, license, and upgrade boundaries

The repository is not archived, and its last push was on 2026-05-04. Those are the only maintenance facts available here. There are no GitHub releases, so the repository does not present versioned release notes or a documented stable-channel policy through that mechanism. The `go.mod` file declares Go 1.16 as the module's language version. Upgrading Litter through module tooling may also involve dependency resolution, so projects should review `go.mod` and `go.sum` changes rather than assuming the package can be replaced in isolation.

Litter is distributed under the MIT License. That permits use, modification, distribution, and inclusion in larger software subject to the license terms, while copied license and copyright notices must be retained. This is a statement about the repository's stated license, not legal advice for a particular product or distribution.

Before depending on committed snapshots, inspect that changelog and test the exact output for private fields, generated fields, maps, interfaces, pointers, and custom dumpers. The concrete upgrade boundary is the module version selected by the consumer, not a documented GitHub release.

Editorial conclusion

Litter fits Go developers who want readable debug output and consistent string-based snapshots, especially when JSON or YAML obscures type details. It is less suitable for projects that require stable output across unreleased formatter changes or need a documented release and upgrade process. Before adoption, check `go.mod`, the configured output for private fields and pointers, and the exact behavior of your custom `Dumper` implementations; the repository has no GitHub releases, and its last push was on 2026-05-04.

Frequently asked questions

How do I install sanity-io/litter in a Go project?

The README documents `go get -u github.com/sanity-io/litter`. The module path is `github.com/sanity-io/litter`, and `go.mod` declares Go 1.16.

What is the difference between litter.Dump and litter.Sdump?

`litter.Dump` writes the formatted data structure to standard output. `litter.Sdump` returns the dump as a string, which is the documented form for snapshot-style tests.

How does sanity-io/litter handle circular references?

Litter detects circular references and aliasing, then replaces additional references to the same object with alias placeholders such as `p0`. Pointer replacement can be disabled except where it is necessary for circular references.

Can I hide private or generated fields from sanity-io/litter output?

Yes. Set `HidePrivateFields` to hide private struct fields, or use `FieldExclusions` with a regular expression to hide selected fields such as generated `XXX_` fields.

How does a Go type provide custom formatting to sanity-io/litter?

Implement the `Dumper` interface and define `LitterDump(w io.Writer)`. The method writes the desired representation, and Litter may indent it or add a pointer comment.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. sanity-io/litter on GitHub
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/sanity-io-litter.svg)](https://hysenlabs.com/projects/sanity-io-litter)