Library / SDK
icebob/fastest-validator avatar
icebob/fastest-validator

fastest-validator: a schema validator that compiles itself into a function

:zap: The fastest JS validator library for NodeJS

1,464 stars100 forksJavaScriptMIT

At a glance

What is it?
fastest-validator is a dependency-free JavaScript validator for NodeJS, the browser and Deno that turns a schema into a compiled checker function using the `Function` constructor, with 24 built-in validators, nested objects, strict mode and configurable error output. It is MIT licensed and version 1.19.1, but its headline speed claim comes from a Node 12 benchmark rather than a current runtime.
Who is it for?
Adopt fastest-validator if you validate large volumes of small objects on a hot path, if you want a schema without a build step or a runtime dependency tree, and if you can live with a validator that compiles code with the `Function` constructor, because that rules it out for sites with a strict Content Security Policy. Do not adopt it if you need transformation, coercion or cross-field rules as a first class concept, since the library's scope is checking a shape.
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 63 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

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

Editorial analysis

A schema compiler, not a schema interpreter

fastest-validator is a JavaScript validator library for NodeJS, the browser and Deno, and its defining characteristic is the way it executes a schema.

Most validation libraries walk a schema object at runtime. For each object you validate, the library reads the schema, works out which rule applies, and executes it. That is a lot of repeated work when the schema never changes, and it is exactly the situation in a request handler, where the same schema is applied to every incoming payload.

fastest-validator takes the opposite approach. The first step is to compile the schema to a compiled checker function, and after that, to validate an object you just call that checker function. The README marks this method as the fastest, and the reason is straightforward: the schema analysis happens once, and what remains is a plain JavaScript function that the engine can optimise.

The approach section explains the mechanism and, importantly, preempts the obvious objection. In order to achieve the lowest cost and highest performance, fastest-validator creates and compiles functions using the `Function` constructor. The README then distinguishes this from the dangers of a runtime eval: no user input is involved in creating the validation schema that compiles into the function, and it is as safe as writing code normally and having it compiled by V8 in the usual way.

That argument is sound for the library's own threat model, and it is the right place to look for the real constraint. The constraint is not the schema author, it is the hosting environment. A page served with a Content Security Policy that forbids `unsafe-eval` will refuse to compile the checker, and the library's central mechanism is exactly the thing that policy blocks.

The intended user is a backend developer validating request bodies, query parameters and messages on a hot path, who wants a schema as configuration and a result as a boolean or an error list, without pulling in a dependency tree.

The feature set in one list

The key features list is short enough to read as a specification of what the library does and does not attempt.

There are 24 built-in validators, many sanitizations, and support for custom validators and aliases. Nested objects and array handling are there, as are strict object validation, multiple validators, customizable error messages and a programmable error object. Two claims in that list are about the project rather than the API: no dependencies, and unit tests with 100% coverage.

No dependencies is a genuine differentiator for a library that will end up in a server's dependency tree, and the package metadata backs it up, since the `dependencies` block is absent and everything in `devDependencies` is tooling for development and testing. The type definitions are shipped from `index.d.ts` in the `files` list alongside `dist` and `lib`.

The error model is worth understanding because it shapes how you write the calling code. A successful check returns `true`. A failure returns an array of error objects, each with a `type`, a `field` and a `message`. The `type` is a machine-readable reason such as `required`, the `field` is the path to the offending property, and the `message` is the human-readable text. The error messages are customizable, and the error object itself is programmable, which is how you turn the result into your own error format rather than mapping it yourself at every call site.

Strict object validation is the other feature that changes behaviour rather than adding syntax. In strict mode, properties that are not in the schema are rejected rather than ignored, which catches the class of bug where a client sends a field your code does not understand and your code silently drops it. That is usually a good default for API boundaries and a bad default for validating objects that have extra properties by design, so it is a decision to make rather than a default to accept.

The `sanitizations` deserve a mention too, since they are the one place where the library goes past checking. Sanitizers transform a value as part of validation, which is convenient and also means a check can have side effects on the object you passed in.

Installing it and the compile-then-check pattern

Installation is one command through NPM:

bash
$ npm i fastest-validator --save

or with Yarn:

bash
$ yarn add fastest-validator

The usage pattern has two halves. You define a schema, compile it once, and then call the resulting checker for each object. The README's example:

js
const Validator = require("fastest-validator");

const v = new Validator();

const schema = {
    id: { type: "number", positive: true, integer: true },
    name: { type: "string", min: 3, max: 255 },
    status: "boolean" // short-hand def
};

const check = v.compile(schema);

console.log("First:", check({ id: 5, name: "John", status: true }));
// Returns: true

Two things are visible there. The `status: "boolean"` line is a short-hand definition, so a bare type string is a complete rule when you do not need constraints. And the checker is a separate variable, which is the point: you compile once at module load and reuse the function for the life of the process.

On failure the checker returns an array of error objects rather than a boolean, so the calling code has to handle both shapes:

js
console.log("Second:", check({ id: 2, name: "Adam" }));
/* Returns an array with errors:
    [
        {
            type: 'required',
            field: 'status',
            message: 'The \'status\' field is required!'
        }
    ]
*/

The `type` of `required` is the useful part for an API, because it lets you map errors to status codes without parsing the message text. The `field` is the property path, which for nested objects gives you the location of the problem in the payload.

If you want to stop at the first problem rather than collect all of them, the option is on the validator instance:

js
const v = new Validator({ haltOnFirstError: true });

That is a compile-time decision in effect, since the checker is generated from the validator's configuration, so you cannot toggle it per call. If different endpoints need different behaviour, you keep two validator instances or two compiled checkers.

Required, optional, nullable and the three ways to say null is wrong

The field semantics are where most validation bugs live, and the library is explicit about them.

Every field in the schema is required by default, and you make a field optional by setting `optional: true`. That default is the opposite of what a JSON schema user might expect, and it is a deliberate choice: an explicit required field catches the typo where you meant to add a property to the schema and did not.

Nullable is a separate axis from optional. If you want to disallow `undefined` but allow `null`, you use `nullable` instead of `optional`. A nullable field with a default value treats `null` as a valid input:

js
const schema = {
   about: { type: "string", nullable: true, default: "Hi! I'm using javascript" }
}

So an `undefined` value becomes the default string, while an explicit `null` stays `null` and passes as valid.

The third case is the one that catches people. The README describes situations where you want to consider `null` as a valid input even for a required field, for instance a field that is required and null without specifying `nullable: true`, a field that is required and not null by specifying `nullable: false`, or a field that is optional but specifically not null. All three need the `considerNullAsAValue` validator option set to `true`:

js
const v = new Validator({considerNullAsAValue: true});

const schema = {foo: {type: "number"}, bar: {type: "number", optional: true, nullable: false}, baz: {type: "number", nullable: false}};
const check = v.compile(schema);

With that option on, `foo` being null is valid, `bar` being null is invalid because it says not null, and `baz` being null is invalid for the same reason. The rule to hold in your head is that the option changes what `null` means globally, and the per-field `nullable` flag is then what distinguishes the fields that care about the difference.

It is a lot of configuration surface for what sounds like a detail, and it is the surface where mistakes are easiest. Reading the error `type` values from the README and the `examples/` directory, which includes a `full.js` file, is the fastest way to build an intuition for how the combinations behave.

Browser, Deno and the framework integrations

The library is usable in three runtimes, and the README shows the load path for each.

In the browser, it is a script tag:

html
<script src="https://unpkg.com/fastest-validator"></script>

followed by the same compile-then-check pattern with a global `FastestValidator`. The package metadata points the `browser` field at `dist/index.min.js`, so a bundler picks up the prebuilt bundle rather than the Node entry point.

In Deno, it is an ESM import, and the README notes that with esm.sh TypeScript is now supported:

js
import FastestValidator from "https://esm.sh/fastest-validator@1"

The `deno-test/` directory at the repository root shows that the Deno path is tested rather than assumed, and there is a `deno/` example.

The framework integrations are the third area. Moleculer is natively supported. Fastify is supported by using fastify-fv, a separate adapter project. Express is supported by using fastest-express-validator, also a separate project.

That listing is worth reading carefully. One of the three is native and two are third-party adapters maintained outside this repository. For a Fastify or Express user, the schema definition and the checker are from this library, while the request-hook integration, the way the schema is declared in the route, and the error response format come from the adapter. The version compatibility between the adapter and the validator is therefore something you have to check yourself, and it is the kind of dependency arrangement where the upstream library is faster-moving than the adapter.

The `examples/` directory also shows the scope of the API beyond the basic case, with files for `async.js`, `custom.js`, `custom-functions.js`, `cyclic.js`, `multi.js`, `next.js`, `precompiled.js`, `halt-on-first-error.js` and a `with-react-nextjs` directory. A `precompiled` example in particular suggests you can build a checker ahead of time, which is the pattern to reach for if you want to avoid compiling at runtime in a serverless environment.

The speed claim, and what it does not measure

The performance claim is the reason most people arrive at this library, so it is worth reading precisely rather than repeating.

The README states 8 million validations per second, and shows a benchmark line of 8,678,752 rps, measured on an Intel i7-4770K with Node.JS 12.14.1. It also states, in comparison to other popular libraries, more than 50x faster than Joi, with the comparison chart hosted in the validator-benchmark repository.

Two things follow. The measurement is the project's own, on a specific machine and a specific Node version, and Node 12 is several major versions behind. The README itself is careful to invite you to reproduce it, with the clone and benchmark commands:

bash
$ git clone https://github.com/icebob/fastest-validator.git
$ cd fastest-validator
$ npm install
$ npm run bench

The benchmark script in the repository is `node benchmark/index.js`, and the `benchmark/` directory is at the root of the tree, with `benchmarkify` in the dev dependencies.

What the number does not tell you is more important than what it does. It measures validation of simple objects against a schema, with the schema compiled ahead of time. It does not cover the compile step, which is where the `Function` constructor cost lands, and it does not cover sanitization, custom validators, nested schemas, or the case where your schema is built at runtime from user input, which is exactly the case the `Function` constructor makes expensive and risky. It also says nothing about the memory profile of a process holding many compiled checkers.

The honest reading is that the architecture gives the library a real advantage on the workload it is designed for, and the number is old enough that you should reproduce it on your own runtime and your own payload shapes before you build a design decision on it.

Licence, versions, and where a different validator fits

The licence is MIT, the author is Icebob, and the repository is not archived. The recent releases are v1.19.1 from 2025-04-30, v1.19.0 from 2024-07-28 and v1.18.0 from 2024-04-21, and the last push to the default branch was on 2026-08-20.

So the code is being worked on and the tags are sparse, which is the same pattern as several other libraries in this ecosystem: the working branch moves and the published versions lag. The `CHANGELOG.md` at the root is where the differences between versions are recorded.

There are three cases where a different approach is the better one, and the difference is about what you want the validator to do rather than how fast it is.

The first is transformation. fastest-validator's job is checking, with sanitizations as an adjacent feature. If your requirement is to take an arbitrary input and produce a typed, defaulted, coerced object, you want a library whose model is conversion rather than checking, and where the output type is the point.

The second is cross-field rules. The library's model is per-field rules on an object shape. A rule like "if `type` is `premium` then `seats` must be greater than zero" is not expressible in the schema, so it goes into hand-written code next to the validator, and at that point you have two sources of truth about what is valid.

The third is the runtime you deploy into. The `Function` constructor is the mechanism that makes the library fast, and it is also the mechanism a strict Content Security Policy forbids. A browser extension, a site with a careful CSP, or an environment with a hardened runtime is a case where the alternative approach, a validator that interprets a schema rather than compiling one, is the only viable one, and you accept the per-call cost in exchange for the policy compatibility.

That is the trade in one sentence. fastest-validator buys its speed by generating code, and the price is a runtime that will let it.

Editorial conclusion

Adopt fastest-validator if you validate large volumes of small objects on a hot path, if you want a schema without a build step or a runtime dependency tree, and if you can live with a validator that compiles code with the `Function` constructor, because that rules it out for sites with a strict Content Security Policy. Do not adopt it if you need transformation, coercion or cross-field rules as a first class concept, since the library's scope is checking a shape. Verify three things first: that your Content Security Policy permits the code compilation the library relies on, that the error output shape your application consumes matches the default array of error objects, and that the 1.x behaviour you rely on is unchanged, since the newest tag is v1.19.1 from 2025-04-30 while the branch was pushed on 2026-08-20.

Frequently asked questions

How do I install fastest-validator and use it?

Install it with `npm i fastest-validator --save` or `yarn add fastest-validator`, then define a schema and compile it with `v.compile(schema)`. The returned checker function returns `true` for valid input and an array of error objects with `type`, `field` and `message` for invalid input.

How does fastest-validator achieve its speed?

It creates and compiles functions using the `Function` constructor, so the schema analysis happens once at compile time and each validation is a plain function call. The README notes that no user input is involved in creating the schema, which is what distinguishes this from a runtime eval.

What is the difference between optional and nullable in fastest-validator?

Every field is required by default, `optional: true` allows the field to be missing, and `nullable: true` allows `null` while still disallowing `undefined`. A nullable field with a `default` value applies that default when the value is `undefined` but keeps an explicit `null`.

Can I use fastest-validator with Express or Fastify?

The README lists Moleculer as natively supported, Fastify through the fastify-fv project, and Express through the fastest-express-validator project. Both of the latter are separate adapters maintained outside this repository.

What is the latest fastest-validator version?

The newest tag is v1.19.1, published on 2025-04-30, preceded by v1.19.0 in July 2024 and v1.18.0 in April 2024. The last push to the master branch was on 2026-08-20, and the package is MIT licensed with no runtime dependencies.

Official sources

  1. icebob/fastest-validator on GitHub
  2. Issues
  3. License: MIT
  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/icebob-fastest-validator.svg)](https://hysenlabs.com/projects/icebob-fastest-validator)