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"
)
type User struct {
Name string `json:"name" validate:"required,min=3,max=50"`
Email string `json:"email" validate:"required,email"`
Age int `json:"age" validate:"gte=0,lte=150"`
Password string `json:"password" validate:"required,min=8"`
Role string `json:"role" validate:"oneof=admin user moderator"`
}
func main() {
user := User{
Name: "Jo", // too short
Email: "invalid", // bad email
Age: -1, // negative
}
errs := govalidate.Validate(user)
if errs.HasErrors() {
for _, e := range errs.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 responses
fmt.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, param string) string {
if v.Kind() != reflect.String { return "" }
if !phoneRegex.MatchString(v.String()) {
return "must be a valid phone number"
}
return ""
})
type Contact struct {
Phone string `validate:"required,phone"`
}type Order struct {
Customer Customer `validate:"required"`
Items []Item `validate:"min=1"`
}
type Item struct {
Name string `validate:"required"`
Price int `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.