Migrate from Superstruct

Migrating from Superstruct to Valibot is particularly easy since both libraries share the same functional and composable design. Most structs map directly to a Valibot schema. The following guide will help you migrate step by step and also point out important differences.

Replace imports

The first thing to do after installing Valibot is to update your imports. We recommend importing Valibot with a wildcard, which gives you access to the entire API through a single variable while remaining fully tree-shakable.

// Change this
import { object, string, assert } from 'superstruct';
const Schema = object({ key: string() });

// To this
import * as v from 'valibot';
const Schema = v.strictObject({ key: v.string() });

There is one detail to watch out for. Superstruct's methods expect the value as the first argument and the struct as the second. In Valibot, the schema always comes first.

// Change this
assert(input, Schema);

// To this
v.assert(Schema, input);

Restructure code

Superstruct wraps structs with refinement functions like size and pattern. In Valibot you use pipelines to do the same thing. This is a function that starts with a schema and is followed by up to 19 validation or transformation actions.

// Change this
const Schema = size(pattern(string(), /^[a-z]+$/), 3, 30);

// To this
const Schema = v.pipe(
  v.string(),
  v.regex(/^[a-z]+$/),
  v.minLength(3),
  v.maxLength(30)
);

The validation methods map almost one-to-one. assert keeps its name, is keeps its name with flipped arguments, validate returns a result object with safeParse, and create becomes parse.

// Change this
const [error, value] = validate(input, Schema);

// To this
const result = v.safeParse(Schema, input);
if (result.success) {
  console.log(result.output);
} else {
  console.log(result.issues);
}

We recommend that you read our mental model guide to understand how the individual functions of Valibot's modular API work together.

Coercion and defaults

Superstruct separates validation from coercion. Coercions and defaults defined with coerce, defaulted and trimmed are only applied when calling create, but not when calling assert or is. Valibot does not make this distinction. Transformations and default values are part of the schema and are always applied when parsing.

// Change this
const Schema = defaulted(trimmed(string()), 'foo');
const value = create(input, Schema);

// To this
const Schema = v.optional(v.pipe(v.string(), v.trim()), 'foo');
const value = v.parse(Schema, input);

For type coercions defined with coerce, use a pipeline with an explicit transform action or one of the dedicated transformation actions like toNumber or toDate.

// Change this
const Schema = coerce(number(), string(), (value) => parseFloat(value));

// To this
const Schema = v.pipe(v.string(), v.decimal(), v.toNumber());

Change names

Most of the names are the same as in Superstruct. However, there are some exceptions. The following table shows all names that have changed.

SuperstructValibot
assignObject merging
coercepipe and transform
createparse
defaultedoptional
definecustom
dynamiclazy
enumspicklist
funcfunction
InferInferOutput
integernumber with integer
intersectionintersect
maskparse with object
maxmaxValue, ltValue
minminValue, gtValue
nonemptynonEmpty
objectstrictObject
patternregex
refinecheck
sizeminLength, maxLength, minValue, maxValue and others
StructErrorValiError
trimmedtrim
typelooseObject
validatesafeParse

Other details

Below are some more details that may be helpful when migrating from Superstruct to Valibot.

Unknown object keys

Superstruct provides three behaviors for unknown object keys, and each of them has a direct equivalent in Valibot. object rejects unknown keys, which matches strictObject. type allows and keeps unknown keys, which matches looseObject. The mask method removes unknown keys, which matches the default behavior of object when parsing. See the objects guide for more details.

// Change this
const value = mask(input, object({ key: string() }));

// To this
const value = v.parse(v.object({ key: v.string() }), input);

Error details

Superstruct's StructError provides a failures method that returns all validation failures. In Valibot, the issues are directly available on the result of safeParse or via the issues property of a ValiError. The flatten, summarize and getDotPath methods help you work with them. See the issues guide for more details.

Async validation

Superstruct does not support asynchronous validation. With Valibot, you get it for free. Functions like pipeAsync and checkAsync allow you to run asynchronous logic, such as database checks, as part of your schema. See the async guide for more details.

Contributors

Thanks to all the contributors who helped make this page better!

  • GitHub profile picture of @fabian-hiller

Partners

Thanks to our partners who support the project ideally and financially.

Sponsors

Thanks to our GitHub sponsors who support the project financially.

  • GitHub profile picture of @vasilii-kovalev
  • GitHub profile picture of @UpwayShop
  • GitHub profile picture of @ruiaraujo012
  • GitHub profile picture of @hyunbinseo
  • GitHub profile picture of @nickytonline
  • GitHub profile picture of @kibertoad
  • GitHub profile picture of @caegdeveloper
  • GitHub profile picture of @Thanaen
  • GitHub profile picture of @bmoyroud
  • GitHub profile picture of @ysknsid25
  • GitHub profile picture of @dslatkin