# VineJS, validation that stays out of the way of your controller

> VineJS is a form data validation library for Node.js, published as @vinejs/vine, aimed at validating HTTP request bodies without pulling a framework into the picture. The repository is unusually candid about its priorities, with a benchmarks.md in the root, a separate benchmarks/ directory, and a package build that deliberately excludes the benchmark and test artefacts from the published tarball.

**vinejs/vine** — VineJS is a form data validation library for Node.js

- Repository: https://github.com/vinejs/vine
- Website: https://vinejs.dev
- Stars: 1,281 · Forks: 37
- Language: TypeScript
- License: MIT
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/vinejs-vine

## A validation library, not a framework

VineJS is described as a form data validation library for Node.js, and the README is clear that you may use it to validate the HTTP request body in your backend applications. That sentence sets the scope precisely. It is not a web framework, it does not own your request lifecycle, and it does not need to be the only thing in your stack.

The package is published as @vinejs/vine, version 4.4.0, with the description Form data validation library for Node.js, and it is MIT licensed. The default branch is 4.x, and the homepage is vinejs.dev with the documentation at vinejs.dev/docs/introduction. The library was built by Harminder Virk, and the tooling around it comes from the AdonisJS ecosystem, with @adonisjs/eslint-config, @adonisjs/prettier-config and @adonisjs/tsconfig in the dev dependencies.

The interesting part of the package.json is the export map, because it shows the shape of the public API rather than a single entry point. The main export is the root, there is a ./defaults subpath pointing at build/src/defaults.js, a ./factories subpath at build/factories/main.js, a ./types subpath at build/src/types.js, and a wildcard for ./schema/base/* which exposes the base schema implementations individually. That last one is worth noting, because it means you can import a single schema class rather than pulling in the whole registry.

The engines field says node >=18.16.0, the package is an ES module with type set to module, and the main entry is build/index.js. The files list includes build and then excludes build/benchmarks, build/bin and build/tests, which is a small detail that says the project treats its published artefact as something worth keeping clean.

The recent releases are v4.4.0 for substituting nested field names in custom message, v4.3.1 for updating dependencies, and v4.3.0 for JSON Schema support, which is the most substantial of the three, with the last push on 2026-10-14.

## The benchmark story, and the four shapes it measures

The README header calls VineJS one of the fastest validation libraries for Node.js, and the repository backs that up with a benchmarks.md file in the root and a benchmarks/ directory, which is unusual and welcome in a library that makes a performance claim.

The benchmark script is in the package.json and it names four files, which is the clearest statement of the shape of the data the library is designed for:

```bash
node --import=@poppinss/ts-exec benchmarks/flat_object.js && node --import=@poppinss/ts-exec benchmarks/nested_object.js && node --import=@poppinss/ts-exec benchmarks/array.js && node --import=@poppinss/ts-exec benchmarks/union.js
```

A flat object is the simple case, a nested object tests whether the traversal cost grows with depth, an array tests repeated elements, and a union tests the discriminated path where a value can be one of several shapes. Those four together are a reasonable statement of what a form validation library actually has to do, and the fact that the benchmark code is in the repository rather than in a blog post means you can run it against your own data.

The build tooling is modern and worth noting for a library that runs in a request path. The compile step is tsdown for the JavaScript output plus a separate tsc pass for the declarations, with the precompile step running the linter and the clean first. The test runner is Japa, with @japa/assert, @japa/expect-type, @japa/runner and @japa/snapshot, plus @ark/attest for type level testing, and the tests are run through @poppinss/ts-exec with source maps enabled. Coverage is c8.

The type level testing is the part that matters most for this kind of library, because a validation library's correctness is mostly about whether the inferred type of the parsed data matches the schema. A test suite that only checks runtime behaviour would miss a schema that validates correctly but infers the wrong type, and expect-type and attest are the tools for catching exactly that.

The documentation is generated with typedoc, the linting is eslint with the AdonisJS config, and formatting is prettier with the AdonisJS config. The release process is release-it with conventional-changelog.

## Where it sits in the AdonisJS ecosystem

The build tooling tells you more about the library's context than the feature list does, and the context is the AdonisJS framework.

The dev dependencies are the giveaway. @adonisjs/eslint-config, @adonisjs/prettier-config and @adonisjs/tsconfig are the shared configuration packages from that ecosystem, and the test stack is Japa, which is the AdonisJS test runner, along with @ark/attest for type level assertions and @poppinss/ts-exec for running TypeScript directly without a build step. The whole toolchain is the AdonisJS one, and the project is maintained by someone who works in that ecosystem.

That context explains the shape of the library. A form data validation library for a Node HTTP request body is a component of a web framework rather than a general purpose utility, and the design decisions follow from that. The separate exports for defaults, factories and types are there so the library can sit inside a request pipeline without forcing a particular structure on the application around it. The./factories subpath in particular is the piece a framework would need, because a framework that wants to build schemas from configuration needs to construct them dynamically.

The 4.x branch is the current line and the version is 4.4.0, and the release cadence shows active work rather than maintenance. The 4.3.0 release added JSON Schema support in February 2026, which is a significant addition because it means a project that already has JSON Schema definitions, from an OpenAPI document or from another service, can use them rather than rewriting them as VineJS schemas. The 4.4.0 release in April 2026 added the ability to substitute nested field names in custom messages, which is the kind of fix that only matters once people have real nested forms and real error copy to show.

The sponsoring page in the README is a row of company logos, and the sponsoring set includes a route planning service, an e-learning platform, a test infrastructure service and two more, which is a fairly normal spread for a library that is used in production by teams of very different kinds.

There is a funding.json in the repository root, and the contributing guide lives in a separate.github repository rather than in the project itself, which is a common arrangement for organisations that keep a shared contributing guide across several projects.

## The four exports, and what each is for

Looking at the export map again tells you how the library is meant to be used, because each subpath is a different relationship with your code.

The root export is the entry point for the everyday case, where you define a schema and validate a payload against it. The ./defaults subpath is for global configuration, the settings that apply to every validation rather than to one schema, and exporting it separately means the defaults module can be loaded without dragging in the whole schema registry when you only need to configure it.

The ./factories subpath is the interesting one. Factories are how you create schema instances with options, rather than constructing them by hand, and putting them on their own export path means a codebase that wants to build schemas dynamically, for example from a configuration file or from a database, can import just the factory layer and stay out of the rest of the library.

The ./types subpath exposes the type definitions, which matters for a TypeScript library where the inferred types are half the product. If your validation result type is what your controller signature depends on, you need those types without importing the runtime, and a separate export path is how you avoid pulling runtime code into a type-only position.

The ./schema/base/* wildcard is the most specific. It lets you import an individual base schema implementation, such as a string schema or a number schema, directly. For a large project that only uses a handful of schema types, that is a meaningful difference in what gets bundled, and it is a design decision that only makes sense in a library that cares about the size of what ends up in your request path.

The overall shape, then, is a library organised by how tightly you want to couple to it. The root for the common case, the defaults for global configuration, the factories for dynamic construction, the types for type-only usage, and the base schemas one at a time for a bundle-sensitive project. The factories/ and src/ directories in the repository root reflect that split, and there is a bin/ directory with the test entry point at bin/test.ts, which is what the quick:test script runs.

## Conclusion

VineJS suits a Node service that wants schema validation for request bodies without adopting a web framework, particularly if you come from the AdonisJS ecosystem where the library is maintained. It is the wrong choice if you need a full validation framework with transforms and complex cross-field logic in one place, since the library is scoped to form data validation, and it is the wrong choice if you are on Node 16, because the package requires Node 18.16.0 or newer. Before adopting it, read the benchmarks.md file in the repository root rather than trusting the speed claim in the README header, and check the release notes for the 4.x line, where 4.3.0 added JSON Schema support and 4.4.0 added substituting nested field names in custom messages.

## FAQ

### What is VineJS used for?

It is a form data validation library for Node.js, and the README says you may use it to validate the HTTP request body in your backend applications. The package is published as @vinejs/vine and requires Node 18.16.0 or newer.

### What subpath exports does the @vinejs/vine package offer?

The main export at the root, plus ./defaults for global default settings, ./factories for creating schema instances, ./types for the type definitions, and a wildcard ./schema/base/* that exposes individual base schema implementations so a project can import only what it needs.

### Does VineJS support JSON Schema?

Yes, that was added in the v4.3.0 release from 2026-02-06. The v4.4.0 release from 2026-04-27 added the ability to substitute nested field names in custom messages, and v4.3.1 was a dependency update.

### What does the VineJS benchmark cover?

Four scripts, for a flat object, a nested object, an array and a union, run with node --import=@poppinss/ts-exec. The benchmark code and a benchmarks.md summary are both in the repository rather than only published as a claim.

### How is VineJS tested?

With Japa, including @japa/assert, @japa/expect-type and @japa/snapshot, plus @ark/attest for type level testing, and coverage through c8. The tests run through bin/test.ts via @poppinss/ts-exec with source maps enabled, and the lint step runs before the test step.

## Sources

- [License: MIT](https://github.com/vinejs/vine/blob/4.x/LICENSE)
- [Project website](https://vinejs.dev)
- [README](https://github.com/vinejs/vine/blob/4.x/README.md)
- [Releases](https://github.com/vinejs/vine/releases)
- [vinejs/vine on GitHub](https://github.com/vinejs/vine)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/vinejs-vine
