Validator v10.30.4 puts a large rule set behind struct tags
Validator v10.30.4 checks whole structs or individual values using rules such as required, email, oneof, length limits, field comparisons, and format checks. It can descend into slices, arrays, and maps, including map keys. Struct-level callbacks cover rules that do not belong to one field, while custom type handlers can unwrap values such as database driver types. Gin uses this package as its default validator, which makes it a familiar choice for Go HTTP services.
The appeal is consistency. A request model can carry its validation rules beside JSON tags, and ValidationErrors gives callers structured details for every failed field. Applications can extract JSON names instead of Go field names and register translated messages through the companion locale packages. That still leaves product decisions to the caller: which errors are safe to expose, whether to stop or aggregate, and how a business rule maps to an HTTP response are outside Validator's job.
What happened when we ran it
Our sandbox installed commit dfe35cf in 17 seconds and added 18 packages. The build completed in 24 seconds, then go test finished in 14 seconds with 50 passed and 0 failed. The clean result matters for a validation library because edge cases are its product. We did not run the README's upstream microbenchmarks, so our result says nothing about nanoseconds per operation or application throughput.
The checkout contained 102 files, roughly 78,983 lines of source, and used 2.3 MB before dependency installation. Our scan found 1 CI workflow file, no Dockerfile, and no separate tests directory. Go projects often keep _test.go files beside package code, so the missing directory does not conflict with the 50 passing tests. Setup needs no service process or secret, and the full install, build, and test sequence took 55 seconds.
Invalid tag definitions can panic at runtime
The package documentation says bad validation input can panic by design and gives an unknown validator name as an example. Alias registration also panics for restricted names. This policy catches programmer errors loudly, but the compiler cannot inspect a string such as required_if=State active. Teams should exercise every registered tag path in tests and avoid constructing tag expressions from untrusted input. If validation rules change frequently under ordinary business review, code-based rules may be easier to trace.
Validator's error contract also deserves deliberate handling. A bad value passed to the API can return InvalidValidationError; ordinary rule failures arrive as ValidationErrors; success is nil. The README demonstrates errors.As for the distinction. Treating every non-nil value as a user mistake can turn a programming error into a misleading 400 response. A small adapter around the shared Validator instance is worth writing once, especially when several handlers need the same field naming and translation policy.
One shared instance keeps the parsed v10 metadata cache useful
validator.New() builds caches for structs and parsed tags, and its documentation says the resulting instance is thread-safe for validation and intended to be reused as a singleton. Creating one per request throws away that cache. Registration is different: custom validations, aliases, type functions, and struct callbacks are documented as not thread-safe. Assemble them at process startup, then publish the configured instance to request handlers without mutating it.
The required-struct default is scheduled to change in v11
The README recommends constructing v10 with validator.WithRequiredStructEnabled(). That option enables behavior documented as the future v11+ default. Adopting it now reduces migration surprise, but it can expose assumptions around nested non-pointer structs and zero values. Teams should add cases for omitted, zero, nil, and partially filled nested data before changing the option. Version upgrades deserve the same request-fixture tests as an API contract change.
The current module declares Go 1.25.0, and the maintenance policy guarantees support for the 2 most recent major Go versions. The README says a minimum Go version increase will use at least a minor package release. That is a reasonable policy for a library tracking security and operating-system fixes, but conservative teams must watch both module and toolchain versions. Our lab image was labeled Go 1.24 Bookworm and completed the build; the supplied result does not explain the toolchain resolution behind that success.
A September 7 push offsets the 326-item open queue
GitHub showed 20,149 stars, 240 open issues, and 86 open pull requests. The repository was pushed on September 7, 2026, and v10.30.4 was released four days earlier. That release included translation work, dependency updates, FQDN length enforcement, more branch coverage, and an RFC 8141 URN rule. Recent merged pull requests and issue discussion show active maintenance even though the combined queue is large.
The README's call for maintainers is a real capacity warning. Validator is widely used, has a decade of history, and continues to ship, yet 326 open threads make quick attention to every edge case unlikely. Format validators are especially exposed to standards detail: recent work touched FQDN labels, credit-card separators, CVE identifiers, and field-exclusion semantics. Pin a minor version, test the exact formats your application accepts, and do not assume a broad built-in tag matches every product policy.
Version 10 is the practical choice when tags fit your code review
Ozzo Validation is the direct alternative for teams that prefer normal Go expressions to struct-tag strings. Protovalidate fits organizations whose contracts already live in Protocol Buffers and must behave across several languages. Validator wins when Go structs are the center of the application and developers value its existing tag vocabulary, Gin integration, collection traversal, and translation hooks. Its 55-second clean lab sequence makes evaluation cheap.
Use one configured instance, register everything before serving traffic, and test malformed as well as valid requests. Enable WithRequiredStructEnabled() before v11 forces the decision, then pin the behavior with nested-struct fixtures. Validator has enough surface area to replace piles of repetitive checks, but it should remain the structural boundary rather than the home for authorization, database policy, or changing business workflows. The latter are clearer as ordinary Go code.
