CLI tool
FluentValidation/FluentValidation avatar
FluentValidation/FluentValidation

FluentValidation: strongly-typed validation rules for .NET

A popular .NET validation library for building strongly-typed validation rules.

9,756 stars1,277 forksC#Apache-2.0

At a glance

What is it?
FluentValidation builds validation rules with a fluent interface and lambda expressions, so rules live in their own classes instead of attributes on your models. It is free, Apache-2.0 licensed, and the README shows the whole API in about twenty lines.
Who is it for?
Adopt FluentValidation when validation rules are complex enough that data annotations stop expressing them, and when you want rules testable apart from the model. Skip it when a handful of Required attributes covers your DTOs, since a validator class per type is real overhead.
Can I use it commercially?
Yes. Apache-2.0 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 2 days ago.
What is it written in?
Mainly C#, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem FluentValidation solves: validation rules that outgrow attributes

Data annotations put validation on the model. That works until a rule needs a condition, a cross-field comparison, or a custom check that has nowhere to live except inside an attribute class. FluentValidation moves rules out of the model and into a validator class, where they are ordinary C#: lambdas, method calls, and conditionals. The README describes the library as using "a fluent interface and lambda expressions for building strongly-typed validation rules", which is the whole design in one sentence.

The audience is .NET developers whose validation has stopped being declarative. The README's own example already shows the shape of that: a rule that only applies when the customer has a discount, and a postcode rule backed by a private method. Neither is comfortable as an attribute. The trade-off is that validation is no longer visible on the model itself, so a reader of the DTO has to know a validator exists somewhere else.

How a validator is built and executed

A validator derives from AbstractValidator<T> and declares rules in its constructor. Each RuleFor takes a lambda that selects the property, and the chain that follows describes the constraint. The README's example covers the main shapes: NotEmpty on a string, NotEqual with a When condition, a Length range, and Must with a custom predicate plus WithMessage for the failure text.

Execution is a single call: validator.Validate(customer) returns a ValidationResult. The result carries IsValid and an Errors list of ValidationFailure objects. That is the entire data flow. There is no pipeline, no attribute scanning, no reflection over the model unless you ask for it. The README does not document async validation, dependency injection wiring, or ASP.NET Core integration; those live in the separate documentation site the README links to, so treat the README as the API surface and the docs site as the operational detail.

Installing FluentValidation and writing a first validator

The README gives one install path: the NuGet package manager or the dotnet CLI. The command adds the package to the current project.

bash
dotnet add package FluentValidation

After that, a validator is a class. The README's example is the reference to copy, and it is short enough to paste whole.

csharp
using FluentValidation;

public class CustomerValidator: AbstractValidator<Customer> {
  public CustomerValidator() {
    RuleFor(x => x.Surname).NotEmpty();
    RuleFor(x => x.Forename).NotEmpty().WithMessage("Please specify a first name");
    RuleFor(x => x.Discount).NotEqual(0).When(x => x.HasDiscount);
    RuleFor(x => x.Address).Length(20, 250);
    RuleFor(x => x.Postcode).Must(BeAValidPostcode).WithMessage("Please specify a valid postcode");
  }

  private bool BeAValidPostcode(string postcode) {
    // custom postcode validating logic goes here
  }
}

Running it is two lines. The README calls Validate on an instance and then reads the result.

csharp
var customer = new Customer();
var validator = new CustomerValidator();

ValidationResult results = validator.Validate(customer);
bool success = results.IsValid;
List<ValidationFailure> failures = results.Errors;

What you should see: success is true when every rule passes, and failures is empty. When a rule fails, failures holds one ValidationFailure per broken rule, with the message you supplied through WithMessage or the default text. The README does not document what happens when you call Validate with a null instance, so check that case yourself before it reaches production.

Where FluentValidation is the wrong tool

The README documents synchronous validation only. If your validation needs to hit a database or an HTTP endpoint, the call shape shown here does not cover it, and the README gives no async example. That is a real boundary, not a small one, for services that check uniqueness against a store.

A second limitation is structural. Rules live in validator classes, so there is no compiler-enforced link between a model and its validator. Rename a property and the lambda breaks at compile time, but delete a validator class and nothing complains until a request arrives unvalidated. Teams that rely on attributes appearing next to the property lose that locality. The README also does not describe a source generator or build-time check that would catch a missing validator, so the safety net is tests, not the compiler.

FluentValidation compared with DataAnnotations

The obvious alternative in .NET is System.ComponentModel.DataAnnotations, where you decorate properties with attributes and let the framework validate. The difference is where the rule lives and what it can express. An attribute is declarative, discovered by reflection, and limited to what the attribute author anticipated. A FluentValidation rule is imperative C# that can call a private method, read another property, or run conditionally through When.

The README example makes the gap concrete. The discount rule fires only when HasDiscount is true. In attributes that becomes a custom attribute or a model-level IValidatableObject implementation, which is closer to code than to declaration anyway. The cost of FluentValidation is the extra class and the extra Validate call. The benefit is that complex rules stay readable and testable in isolation, because a validator is just a class you can instantiate in a unit test.

Licence, sponsorship and what upgrading costs

FluentValidation is licensed under Apache-2.0. The README states it is copyright 2008-2022 .NET Foundation, Jeremy Skinner and other contributors, and that the project is part of the .NET Foundation. The README also asks commercial users to sponsor the project through GitHub Sponsors or OpenCollective, and lists Microsoft and JetBrains as sponsors. Sponsorship is a request, not a licence term; the Apache-2.0 text is what governs use, and it is the file to read if you need certainty. Nothing here is legal advice.

On upgrades, the recent release history shows 11.11.0, then 12.0.0, then 12.1.0. A major version bump between 11 and 12 is the point to check the Changelog.txt in the repository rather than assuming the API is unchanged. The README does not document a migration guide or a rollback procedure, so pin the package version in your project and read the changelog before moving across a major boundary. The last push to the repository was on 2026-09-09, so the codebase is being touched, but that says nothing about whether a given upgrade is safe for your code.

Editorial conclusion

Adopt FluentValidation when validation rules are complex enough that data annotations stop expressing them, and when you want rules testable apart from the model. Skip it when a handful of Required attributes covers your DTOs, since a validator class per type is real overhead. Before committing, check the licence question against the repository rather than a blog post, and confirm which package version your target framework resolves to.

Frequently asked questions

Is FluentValidation still free?

Yes. The README states the project is licensed under Apache-2.0 and asks commercial users to sponsor it financially, but sponsorship is a request rather than a licence term. The Apache-2.0 licence file in the repository is the document that governs use.

What are some alternatives to FluentValidation?

The closest alternative in .NET is System.ComponentModel.DataAnnotations, which puts validation attributes directly on model properties instead of in a separate validator class. The difference is expressiveness: attributes are declarative and reflection-driven, while FluentValidation rules are C# lambdas that can run conditionally or call private methods.

How can I use FluentValidation in ASP.NET Core web APIs?

The README does not document ASP.NET Core integration, and it points readers to the separate documentation site at fluentvalidation.net for usage instructions. The README itself only shows the library-level flow: install the NuGet package, define an AbstractValidator, and call Validate on an instance.

What is FluentValidation?

It is a .NET validation library that builds strongly-typed validation rules using a fluent interface and lambda expressions, as described in the README. Rules are declared inside a class deriving from AbstractValidator<T>, and validation runs through a single Validate call that returns a ValidationResult.

How do I write a conditional rule with FluentValidation?

The README example applies When to a rule, so the constraint only runs when the predicate is true: RuleFor(x => x.Discount).NotEqual(0).When(x => x.HasDiscount). The README does not document the other conditional forms, so check the documentation site for those.

Official sources

  1. FluentValidation/FluentValidation on GitHub
  2. License: Apache-2.0
  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/fluentvalidation-fluentvalidation.svg)](https://hysenlabs.com/projects/fluentvalidation-fluentvalidation)