Skip to content
JohanLindvallPublic

About

Go code generator for fast, allocation-light json.Unmarshaler implementations, plus a zero-copy toolkit for reading, editing and validating raw JSON

Topics

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

Lightning ⚡

CI Go Reference Go version Version License: MIT

Fast JSON decoding for Go, generated from your types. Lightning writes reflection-free UnmarshalJSON methods and provides a toolkit for reading, streaming, editing, and validating JSON without a schema.

Quick start · Documentation · Run an example in your browser · Benchmarks · Contributing

Why Lightning?

  • Keep your Go types and call sites. Generated methods implement json.Unmarshaler; encoding/json.Unmarshal calls them automatically. Call v.UnmarshalJSON(data) directly to skip that entry point.
  • Control allocations. Reuse slices, maps, and pointers across decodes. Opt into string aliasing or in-place unescaping when you own the input buffer.
  • Use the CPU you have. Runtime dispatch selects SIMD scanners on amd64 and arm64, with portable fallbacks on other architectures.
  • Read only what you need. The public pkg/json toolkit looks up paths, walks arrays, streams large documents, and edits raw JSON without generation.

Lightning has deliberate differences from encoding/json, including exact key matching, null handling, and numeric overflow. Read the compatibility guide before migrating.

Quick start

Requires Go 1.25 or newer. In a new directory:

go mod init example.com/events
go get github.com/JohanLindvall/lightning@latest

Save this as event.go:

package main

import (
    "fmt"
    "log"
    "time"
)

//go:generate go run github.com/JohanLindvall/lightning $GOFILE

type Event struct {
    ID   int64     `json:"id"`
    Kind string    `json:"kind"`
    At   time.Time `json:"at"`
    Tags []string  `json:"tags"`
}

func main() {
    data := []byte(`{"id":42,"kind":"deploy","at":"2026-10-01T12:00:00Z","tags":["prod"]}`)
    var e Event
    if err := e.UnmarshalJSON(data); err != nil {
        log.Fatal(err)
    }
    fmt.Println(e.ID, e.Kind, e.At.Format(time.RFC3339), e.Tags)
}

Generate the decoder and run it:

go generate ./...
go mod tidy
go run .
# 42 deploy 2026-10-01T12:00:00Z [prod]

Generation writes event_unmarshal.go beside your schema. The directive uses the version in your go.mod, keeping the generator and its runtime together. Run go generate ./... again after changing the schema or upgrading Lightning.

See the generator guide for installation options, supported types, reuse, and custom unmarshalers, or tags and directives for nocopy, strict, emptyslice, lax, and other options.

Use the toolkit without generation

Import github.com/JohanLindvall/lightning/pkg/json to work directly with bytes. Install it in your module:

go get github.com/JohanLindvall/lightning/pkg/json@latest

This standalone example looks up a nested string:

package main

import (
    "fmt"
    "log"

    json "github.com/JohanLindvall/lightning/pkg/json"
)

func main() {
    data := []byte(`{"user":{"name":"Ada"}}`)
    raw, err := json.Lookup(data, "user", "name")
    if err != nil {
        log.Fatal(err)
    }
    name, err := json.String(raw)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(name) // Ada
}

Lookup results alias the input; keep it unchanged while using them. Use the checked edit functions when editing untrusted input. Valid follows Lightning's documented grammar; it is not a substitute for encoding/json.Valid when you need exactly the standard library's acceptance rules.

Documentation

I want to… Start here
Generate a decoder or reuse a target Generator guide
Configure tags and directives Options reference
Look up values, validate, escape, or parse JSON toolkit · API reference
Process a large response as it arrives Streaming
Set values or remove defaults Editing JSON
Check migration and buffer ownership rules Compatibility and input contracts
Understand CPU support or measure performance Performance guide
Work on Lightning itself Contributing · Repository layout

Benchmarks

The comparison suite covers real-world documents and synthetic workloads, with generated decoders, DecodeAny, encoding/json, easyjson, sonic, goccy/go-json, and json/v2. It reports latency, bytes allocated, and allocation counts.

Architecture Decoder comparisons Toolkit and runtime benchmarks
amd64 Results Results
arm64 Results Results

These are single-run CI snapshots, not a guarantee for your workload. Check the CPU and toolchain headers, compare same-run ratios, and measure your own data. The performance guide explains how to reproduce the suite.

Help and contributing

Questions, bug reports, documentation fixes, tests, and performance work are welcome. Open an issue with a small example, or follow CONTRIBUTING.md to run the project and prepare a pull request. You can try the runnable examples without installing anything.

If Lightning helps your project, a star helps other Go developers discover it.

License

MIT © Johan Lindvall. See the credits for algorithms and benchmark sources.

About

Go code generator for fast, allocation-light json.Unmarshaler implementations, plus a zero-copy toolkit for reading, editing and validating raw JSON

Topics

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages