Tag-based validation with 20+ built-in rules, nested struct support, and custom rules — zero dependencies.
GoValidate provides declarative struct validation using Go struct tags. Supports nested structs, slices, custom rules, and JSON field names — all with zero external dependencies.
| Feature | Description |
|---|---|
| Struct Tags | validate:"required,min=3,max=100" |
| 20+ Built-in Rules | required, min, max, email, url, ip, alpha, regex... |
| Nested Structs | Recursive validation with dot-notation errors |
| Slice Validation | Validates each element: Items[0].Name |
| Custom Rules | RegisterRule("phone", fn) |
| JSON Names | Uses json tag name in error messages |
| Error Map | errs.Map() → map[string][]string |
| Cross-field | oneof, numeric comparisons |
| Zero Dependencies | Only Go standard library + reflect |
go get github.com/kzxl/govalidatepackage main
import (
"fmt""github.com/kzxl/govalidate"
)
typeUserstruct {
Namestring`json:"name" validate:"required,min=3,max=50"`Emailstring`json:"email" validate:"required,email"`Ageint`json:"age" validate:"gte=0,lte=150"`Passwordstring`json:"password" validate:"required,min=8"`Rolestring`json:"role" validate:"oneof=admin user moderator"`
}
funcmain() {
user:=User{
Name: "Jo", // too shortEmail: "invalid", // bad emailAge: -1, // negative
}
errs:=govalidate.Validate(user)
iferrs.HasErrors() {
for_, e:=rangeerrs.Errors {
fmt.Printf(" %s [%s]: %s\n", e.Field, e.Rule, e.Message)
}
// Output:// name [min]: must be at least 3 characters// email [email]: must be a valid email address// age [gte]: must be >= 0// password [required]: is required
}
// Error map for API responsesfmt.Println(errs.Map())
// map[name:[must be at least 3 characters] email:[must be a valid email] ...]
}| Rule | Example | Description |
|---|---|---|
required | validate:"required" | Field must not be zero value |
min | validate:"min=3" | Min length (string/slice) or min value (number) |
max | validate:"max=100" | Max length or value |
len | validate:"len=5" | Exact length |
gt / gte | validate:"gt=0" | Greater than / greater than or equal |
lt / lte | validate:"lte=100" | Less than / less than or equal |
email | validate:"email" | Valid email format |
url | validate:"url" | Valid URL with scheme and host |
ip | validate:"ip" | Valid IPv4 or IPv6 |
alpha | validate:"alpha" | Letters only |
alphanum | validate:"alphanum" | Letters and numbers only |
numeric | validate:"numeric" | Numeric characters only |
lowercase | validate:"lowercase" | Must be all lowercase |
uppercase | validate:"uppercase" | Must be all uppercase |
contains | validate:"contains=keyword" | Must contain substring |
startswith | validate:"startswith=Hello" | Must start with prefix |
endswith | validate:"endswith=!" | Must end with suffix |
oneof | validate:"oneof=admin user" | Must be one of listed values |
regex | validate:"regex=^\\d{3}$" | Must match regex pattern |
datetime | validate:"datetime=2006-01-02" | Must parse with Go layout |
govalidate.RegisterRule("phone", func(v reflect.Value, paramstring) string {
ifv.Kind() !=reflect.String { return"" }
if!phoneRegex.MatchString(v.String()) {
return"must be a valid phone number"
}
return""
})
typeContactstruct {
Phonestring`validate:"required,phone"`
}typeOrderstruct {
CustomerCustomer`validate:"required"`Items []Item`validate:"min=1"`
}
typeItemstruct {
Namestring`validate:"required"`Priceint`validate:"gt=0"`
}
// Errors:// customer.name: is required// Items[0].Price: must be > 0Apache License 2.0 — See LICENSE for details.
✅ Validate structs, the Go way.