Library / SDK
asaskevich/govalidator avatar
asaskevich/govalidator

asaskevich/govalidator: struct tags, sanitizers and the v12 module path

[Go] Package of validators and sanitizers for strings, numerics, slices and structs

6,202 stars572 forksGoMIT

At a glance

What is it?
A Go validation and sanitization library modelled on validator.js, distributed as github.com/asaskevich/govalidator/v12. The tag-based struct validation is the part most teams adopt; the 2021 release history and the v11 to v12 import change are the parts they trip over.
Who is it for?
Adopt asaskevich/govalidator if you want struct-tag validation in a Go service and you are willing to pin an import path and read the tag semantics rather than assume them. Do not adopt it if you need a validation framework with locale-aware messages, cross-field rules expressed declaratively, or a release cadence you can plan upgrades around; the most recent release listed is v11.0.1 from 2021-03-07, and the repository's last push was on 2026-09-18.
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 13 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 September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What asaskevich/govalidator is for

The package describes itself as "a package of validators and sanitizers for strings, structs and collections," and the README states it is based on validator.js. That lineage explains the shape of the API: a long flat list of predicate functions such as IsEmail, IsURL and IsJSON, plus a smaller set of string transformers such as BlackList and CamelCaseToUnderscore. The audience is Go developers who receive untrusted input, typically in an HTTP handler or a decoding step, and want to reject or clean it before it reaches business logic. Two layers exist. The function layer is stateless: you call IsEmail(s) and get a bool. The struct layer is where the package earns its place in a project: you annotate fields with a valid tag and call ValidateStruct, and the library walks the struct with reflection, collecting errors per field. It is not a schema language and it is not a code generator. It is a reflection-driven checker that reads tags you already wrote next to your type definition, which means the validation rule and the field it applies to live in the same place.

How ValidateStruct reads your tags

Validation is driven by the valid struct tag. A field tagged `valid:"email"` is checked with the email rule; a field tagged `valid:"-"` is skipped entirely. The README's examples make the interaction with the package-level settings explicit, and this is the part worth reading twice. SetFieldsRequiredByDefault(true) changes the meaning of an untagged field: with it on, a struct field that carries no valid tag at all fails validation regardless of its value. The README's first example struct, with an untagged Name field, "will fail govalidator.ValidateStruct() (and the field values do not matter)" under that setting. Adding `valid:"-"` to Name exempts it, and adding `optional` to a rule such as `valid:"email,optional"` means the field is only checked when non-empty. The second setting, SetNilPtrAllowedByRequired, controls whether a nil pointer on a required field passes; the README says it is disabled by default "for consistency," and that with it disabled both nil and zero values produce validation errors. Errors come back as an error value, and the package exposes ErrorByField and ErrorsByField to pull a message out by field name, which is what you would hand to an API response. The README recommends calling SetFieldsRequiredByDefault in a package init function or main, which makes the setting global to the process. That is a real constraint: in a large binary, one init call changes validation behaviour for every struct in every package.

Installing it and validating a first struct

The README gives two install commands. The first fetches the current major version module path. The second pins the gopkg.in alias. Both are run from a shell with Go already installed.

bash
go get github.com/asaskevich/govalidator/v12

The repository's go.mod declares `module github.com/asaskevich/govalidator/v12` and `go 1.13`, so the import path in your source must match the module path, including the version suffix. The README shows the import line and a short alias form for teams that do not want to type the long name. Note that parts of the README's own examples import the v11 path, which is a documentation inconsistency rather than an instruction.

go
import (
  valid "github.com/asaskevich/govalidator/v12"
)

With the import in place, define a struct and validate it. The README's example structs use an email field and a Name field exempted with a hyphen, and the call is govalidator.ValidateStruct. What you should see is an error when the email value is present but malformed, and no error when it is empty and tagged optional.

go
type signup struct {
  Name  string `valid:"-"`
  Email string `valid:"email,optional"`
}

_, err := valid.ValidateStruct(signup{Name: "a", Email: "not-an-email"})

The two return values are the struct and an error; the README's examples discard the first. If you also want the string-level check without a struct, the function list includes IsEmail, IsURL, IsJSON and roughly a hundred others, and they are called directly.

Custom validators and the v11 signature change

The README documents a breaking change to custom validators, and it is the kind of change that produces a compile error rather than a silent bug, which is preferable. The old custom validator signature took one parameter, `func(i interface{}) bool`. The new signature takes two, `func(i interface{}, o interface{}) bool`, where the second parameter is the object being validated. The README states the reason plainly: a context was added "for structs this is the object being validated" and this "makes dependent validation possible." In other words, a rule on one field can now inspect a sibling field, which the single-argument form could not do. The registration mechanism changed at the same time. Assigning directly into govalidator.CustomTypeTagMap was replaced by a Set method on the same map, and the README says this "was changed to prevent data races when accessing custom validators." So the migration has two parts: update the function signature, and move from map assignment to CustomTypeTagMap.Set. If you are porting a codebase that registered custom validators the old way, the compiler will catch the signature but the map assignment is a different expression, and the README's before-and-after snippets are the reference for both.

Where the package stops helping

The struct tag is a string, and the library parses it. There is no compile-time checking of rule names, so a typo in a tag is a runtime problem, not a build failure. The README does not document a way to enumerate valid tag names programmatically, so the function list in the README is the reference, and it is long. That list also contains entries that are easy to misread: IsExistingEmail is listed alongside IsEmail, and the README does not explain what the former does beyond its name, which suggests it performs some additional existence check that the documentation does not describe. Do not assume its behaviour. The second limitation is global state. SetFieldsRequiredByDefault and SetNilPtrAllowedByRequired are process-wide switches, and the README recommends setting them in init or main. If your service validates structs from two different subsystems with different expectations about untagged fields, one of them will be wrong. The third is scope: this library validates values. It does not fetch records, check uniqueness against a database, or enforce cross-request invariants. A rule like "this username is not already taken" has to live in your own code, registered as a custom validator if you want it in the tag.

Alternatives and the actual difference

The obvious comparison is go-playground/validator, the other widely used Go struct-tag validation package. The difference in approach is in the tag vocabulary and the error model. go-playground/validator is built around a single validate tag with a rich expression syntax that covers cross-field comparisons and conditional rules in the tag itself, and it ships a translation layer for human-readable messages in multiple languages. asaskevich/govalidator takes the opposite position: its rules are mostly single-value predicates inherited from validator.js, and anything that depends on another field goes through a custom validator function with the new two-argument signature. That is more code to write, but it is also plain Go that a debugger can step through, and it does not require learning a tag grammar. The second alternative is to skip a library and write the checks. For a struct with three fields and two rules, hand-written code with a small error type is less machinery than a reflection pass and a global setting. asaskevich/govalidator starts paying for itself when the same struct is validated in several places and you want the rules to travel with the type definition rather than being repeated. On the search side, the queries that bring people to this package include "go validator alternative" and "govalidator golang," which suggests a fair number of visitors arrive while comparing it against something else rather than while reading its documentation.

Maintenance, licence and upgrade cost

The repository is not archived, and its last push was on 2026-09-18. The releases listed in the README are older: v11.0.0 and v11.0.1 both from 2021-03-07, and v11 from 2020-08-17. So commits continue while tagged releases do not, and the README still contains examples importing the v11 path even though go.mod declares v12. The practical consequence is that a team pinning a tagged release is pinning something from 2021, while a team tracking master is tracking untagged code. Neither is wrong, but they are different risk positions and the README does not discuss which is intended. The licence is MIT, which is permissive and places few conditions on redistribution; the LICENSE file is at the repository root. This is a description of the licence identifier, not legal advice, and if your organisation has rules about dependency licences, the LICENSE file is the document to read. On upgrade cost: the v11 to v12 move changes the import path because the module path carries the major version, and the custom validator signature change documented in the README is a compile-time break. Budget for a search across your codebase for the old import string and for any direct assignments into CustomTypeTagMap. Both are mechanical, and neither is silent.

Editorial conclusion

Adopt asaskevich/govalidator if you want struct-tag validation in a Go service and you are willing to pin an import path and read the tag semantics rather than assume them. Do not adopt it if you need a validation framework with locale-aware messages, cross-field rules expressed declaratively, or a release cadence you can plan upgrades around; the most recent release listed is v11.0.1 from 2021-03-07, and the repository's last push was on 2026-09-18. Before writing code, verify three things: that your build resolves github.com/asaskevich/govalidator/v12 and not the older non-versioned path, that SetFieldsRequiredByDefault is either left off or paired with valid:"-" on every field you do not intend to validate, and that each tag you rely on is listed in the README's function list. If any of those three checks fails, the failure will appear as a validation error on a field you never intended to check, which is the most common way this package surprises a new user.

Frequently asked questions

How do I use asaskevich/govalidator in a Go project?

Install it with go get github.com/asaskevich/govalidator/v12, import that same path, then either call the standalone predicate functions such as IsEmail or annotate struct fields with a valid tag and call govalidator.ValidateStruct. The README recommends importing under a short alias if the full path is inconvenient.

What is asaskevich/govalidator an alternative to?

The package is based on validator.js, so its rule vocabulary follows that JavaScript library. In Go, the closest comparison is go-playground/validator, which puts cross-field and conditional rules in a single tag expression, whereas asaskevich/govalidator handles dependent rules through custom validator functions that receive the object being validated.

Why does importing asaskevich/govalidator fail after upgrading from v11?

The module path includes the major version. The repository's go.mod declares module github.com/asaskevich/govalidator/v12, so the import string must end in /v12. Some examples in the README still show the v11 path, which is a documentation inconsistency rather than a supported import.

What does SetFieldsRequiredByDefault change in asaskevich/govalidator?

With it enabled, struct fields that carry no valid tag fail validation regardless of their values. Fields you want to skip must be marked with valid:"-", and fields that should only be checked when present use a rule such as valid:"email,optional". The README suggests calling it from a package init function or main.

Can asaskevich/govalidator check one field based on another field's value?

Yes, through a custom validator. The README documents a signature change for custom validators from func(i interface{}) bool to func(i interface{}, o interface{}) bool, where the second parameter is the object being validated, and states that this makes dependent validation possible.

Official sources

  1. asaskevich/govalidator on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
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/asaskevich-govalidator.svg)](https://hysenlabs.com/projects/asaskevich-govalidator)