Skip to main content
Version: 2.1.2

Benchmark Results

Generated: 2026-09-02 11:51:31 UTC

If you're interested in diving deeper, check out our benchmark repository.

Library Notes​

Feature Comparison​

FeaturePedantigoPlaygroundOzzoHumaGodanticGodasse
Declarative constraints✅ tags✅ tags✅ rules✅ tags✅ methods❌ hand-written
JSON Schema generation✅❌❌✅✅❌
Default values✅❌❌❌✅✅
Unmarshal + validate✅❌❌✅✅✅
Validate existing struct✅✅✅❌✅❌*

*Godasse requires hand-written Validate() methods

Library Descriptions​

  1. Pedantigo - Struct tag-based validation (validate:"required,email,min=5"). JSON Schema generation with caching.

  2. Playground (go-playground/validator) - Struct tag-based validation. Rich constraint library, no JSON Schema.

  3. Ozzo (ozzo-validation) - Rule builder API (validation.Field(&u.Name, validation.Required, validation.Length(2,100))). No struct tags.

  4. Huma - OpenAPI-focused. Validates map[string]any against schemas, not structs directly.

  5. Godantic - Method-based constraints (FieldName() FieldOptions[T]). JSON Schema, defaults, streaming partial JSON.

  6. Godasse - Deserializer with default: tag. All constraint validation requires hand-written Validate() methods.


Getting the Best Performance​

New[T]() does the expensive work once: it walks the struct via reflection, resolves every constraint tag, and builds an internal field-constraint cache (plus the JSON field deserializers). That one-time cost is what the New section below measures (microsecond range). Every other operation - Validate, Unmarshal, Marshal, Schema - reuses that precomputed cache and runs in the hundreds-of-ns to low-µs range, which is why those numbers consistently beat libraries that re-resolve constraints or re-walk structs on every call.

This only pays off if the *Validator[T] returned by New is built once and reused - not recreated per request. Two ways to do that:

Module-level variable (sufficient to call the validator directly):

var userValidator = validator.New[User]()

func handleCreateUser(body []byte) (*User, error) {
return userValidator.Unmarshal(body) // reuses the cached field constraints
}

Register (needed in addition, only if a framework integration - e.g. the Echo Binder plugin, or UnmarshalInto - must find the validator for a type it only knows via reflect.Type at runtime, not through your module-level variable):

var _ = validator.Register(validator.New[User]())

Register[T] may be called exactly once per type - a second call for the same type panics, by design. A type could have multiple differently-configured validators (different Options), and pedantigo has no way to guess which one a framework plugin should resolve to, so it refuses to silently pick one. Call Register from exactly one package-level var declaration per type.


Validate​

Validate existing struct (no JSON parsing)

StructPedantigoPlaygroundOzzoHumaGodanticGodasse
Simple1.41 µs (10 allocs)2.27 µs (7 allocs)13.06 µs (43 allocs)unsupported6.18 µs (48 allocs)unsupported
Complex2.25 µs (15 allocs)3.67 µs (9 allocs)12.76 µs (139 allocs)unsupported14.22 µs (120 allocs)unsupported
Large1.60 µs (22 allocs)1.96 µs (3 allocs)48.06 µs (254 allocs)unsupported14.98 µs (126 allocs)unsupported

JSONValidate​

JSON bytes → struct, then a separate validate step

StructPedantigoPlaygroundOzzoHumaGodanticGodasse
Simple3.50 µs (19 allocs)4.31 µs (16 allocs)unsupported3.54 µs (26 allocs)unsupportedunsupported
Complex9.69 µs (39 allocs)11.06 µs (33 allocs)unsupported10.33 µs (78 allocs)unsupportedunsupported

Marshal​

Validate + JSON marshal

StructPedantigoPlaygroundOzzoHumaGodanticGodasse
Simple1.93 µs (11 allocs)2.82 µs (9 allocs)unsupportedunsupportedunsupportedunsupported

Unmarshal​

JSON bytes → validated struct in a single call

StructPedantigoPlaygroundOzzoHumaGodanticGodasse
Simple5.47 µs (49 allocs)unsupportedunsupportedunsupported11.69 µs (81 allocs)4.70 µs (42 allocs)
Complex16.86 µs (132 allocs)unsupportedunsupportedunsupported50.92 µs (285 allocs)16.41 µs (149 allocs)

New​

Validator creation overhead

StructPedantigoPlaygroundOzzoHumaGodanticGodasse
Simple15.73 µs (129 allocs)16.50 µs (187 allocs)unsupported31.44 µs (255 allocs)27.50 µs (305 allocs)6.90 µs (72 allocs)
Complex37.71 µs (299 allocs)unsupportedunsupported76.32 µs (515 allocs)7.64 µs (75 allocs)24.08 µs (243 allocs)

Schema​

JSON Schema generation

StructPedantigoPlaygroundOzzoHumaGodanticGodasse
Uncached28.07 µs (227 allocs)unsupportedunsupported31.41 µs (255 allocs)unsupportedunsupported
Cached18 ns (0 allocs)unsupportedunsupported648 ns (6 allocs)unsupportedunsupported

OpenAPI​

OpenAPI-compatible schema generation

StructPedantigoPlaygroundOzzoHumaGodanticGodasse
Uncached29.05 µs (229 allocs)unsupportedunsupported31.68 µs (255 allocs)unsupportedunsupported
Cached18 ns (0 allocs)unsupportedunsupported665 ns (6 allocs)unsupportedunsupported

Summary​

Validate_Simple (struct validation)​

Libraryns/opallocsvs Pedantigo
Pedantigo1.41 µs10baseline
Playground2.27 µs71.60x slower
Ozzo13.06 µs439.24x slower
Huma---
Godantic6.18 µs484.37x slower
Godasse---

Validate_Complex (nested structs)​

Libraryns/opallocsvs Pedantigo
Pedantigo2.25 µs15baseline
Playground3.67 µs91.63x slower
Ozzo12.76 µs1395.66x slower
Huma---
Godantic14.22 µs1206.31x slower
Godasse---

JSONValidate_Simple (JSON → struct, then validate)​

Libraryns/opallocsvs Pedantigo
Pedantigo3.50 µs19baseline
Playground4.31 µs161.23x slower
Ozzo---
Huma3.54 µs261.01x slower
Godantic---
Godasse---

JSONValidate_Complex (nested JSON)​

Libraryns/opallocsvs Pedantigo
Pedantigo9.69 µs39baseline
Playground11.06 µs331.14x slower
Ozzo---
Huma10.33 µs781.07x slower
Godantic---
Godasse---

Unmarshal_Simple (JSON → validated struct, single call)​

Libraryns/opallocsvs Pedantigo
Pedantigo5.47 µs49baseline
Playground---
Ozzo---
Huma---
Godantic11.69 µs812.14x slower
Godasse4.70 µs421.17x faster

Unmarshal_Complex (nested JSON, single call)​

Libraryns/opallocsvs Pedantigo
Pedantigo16.86 µs132baseline
Playground---
Ozzo---
Huma---
Godantic50.92 µs2853.02x slower
Godasse16.41 µs1491.03x faster

Schema_Uncached (first-time generation)​

Libraryns/opallocsvs Pedantigo
Pedantigo28.07 µs227baseline
Playground---
Ozzo---
Huma31.41 µs2551.12x slower
Godantic---
Godasse---

Schema_Cached (cached lookup)​

Libraryns/opallocsvs Pedantigo
Pedantigo18 ns0baseline
Playground---
Ozzo---
Huma648 ns635.32x slower
Godantic---
Godasse---

Generated by pedantigo-benchmarks

Benchmark naming convention
Benchmark_<Library>_<Feature>_<Struct>

Libraries: Pedantigo, Playground, Ozzo, Huma, Godantic, Godasse
Features: Validate, JSONValidate, Marshal, Unmarshal, New, Schema, OpenAPI
Structs: Simple (5 fields), Complex (nested), Large (20+ fields)