Spraxium logoSpraxium

Validators Reference

Every built-in validator decorator for @spraxium/env explained with types and behavior. Learn string, number, boolean, network, Discord, data, and common validators including MinLength, MaxLength, Matches, Min, Max, IsPositive, IsNegative, IsDiscordWebhookUrl, and IsDiscordClientSecret.

How validators work

Every validator is a property decorator that attaches a validation rule to the field metadata. When the schema runs at boot time, rules execute in the order they were declared on the property. Each rule can include a transform step that converts the raw string into the target type and a validate step that checks whether the converted value is acceptable. If any rule returns an error message, the field fails validation.

You can stack multiple validators on a single property. A field like a Redis URI might use IsRedisUri for format checking and Secret for masking. The pipeline runs every rule sequentially, so Transform runs its conversion before Validate sees the value. Understanding this order matters when you combine custom transforms with built-in type validators.

The validators are organized into six families: string, number, boolean, network, Discord, and data validators. A seventh group, common validators, contains utility decorators that modify field behavior without checking types.

Choosing validators well

Start with the validator that matches the runtime type you want in the application, then add constraint validators for tighter business rules. In other words, first decide whether the field should become a string, number, or boolean, and only then add checks like minimum length, pattern matching, or numeric bounds.

That order keeps schemas easier to read. Anyone opening the env file can quickly understand what the field becomes in code and which extra rules it must satisfy.

String validators

IsString confirms that the value is a non-empty string. Use it for any free-form text field. Three constraint validators can be stacked on top to further restrict the value.

DecoratorArgumentsDescription
IsString()NoneValidates that the value is a non-empty string.
MinLength(min)min: numberValidates that the string has at least the given number of characters.
MaxLength(max)max: numberValidates that the string has at most the given number of characters.
Matches(pattern, message?)pattern: RegExp, message?: stringValidates that the string matches the given regular expression. Accepts an optional custom error message.
src/app.env.ts
@Env('APP_NAME')
@IsString()
@MinLength(3)
@MaxLength(64)
APP_NAME!: string;

@Env('SLUG', { secret: false })
@IsString()
@Matches(/^[a-z0-9-]+$/, 'Must be lowercase alphanumeric with hyphens')
SLUG!: string;

Number validators

Three validators handle numeric values. Each one transforms the raw string into a JavaScript number before validating its shape. They differ in what they accept after conversion.

DecoratorAcceptsExample values
IsNumberAny finite number, including decimals"3.14", "42", "-1.5"
IsIntegerWhole numbers only"42", "-7", "0"
IsPortInteger between 1 and 65535"3000", "8080", "443"

All three transform the string with Number() before validating. IsNumber rejects NaN and empty strings. IsInteger further requires Number.isInteger() to pass. IsPort adds a range check from 1 to 65535 on top of the integer requirement.

Four constraint validators work on top of any numeric field and must be applied after the type validator:

DecoratorArgumentsDescription
Min(min)min: numberValidates that the numeric value is greater than or equal to the given minimum.
Max(max)max: numberValidates that the numeric value is less than or equal to the given maximum.
IsPositive()NoneValidates that the numeric value is greater than zero.
IsNegative()NoneValidates that the numeric value is less than zero.
src/app.env.ts
@Env('RATE_LIMIT')
@IsNumber()
@Min(1)
@Max(1000)
RATE_LIMIT!: number;

@Env('MAX_RETRIES')
@IsInteger()
@IsPositive()
MAX_RETRIES!: number;

@Env('HTTP_PORT', { secret: false })
@IsPort()
HTTP_PORT!: number;

Boolean validator

The IsBoolean validator transforms string representations into native booleans. It accepts four raw values: "true", "false", "1", and "0". The comparison is case-insensitive and trims whitespace, so " TRUE " resolves to true. Any other value fails validation.

After transformation, the property holds a real JavaScript boolean. You never need to compare against the string "true" in your code. This is the recommended way to handle feature flags and toggle switches stored in environment variables.

src/app.env.ts
@Env('ENABLE_METRICS', { default: 'false', secret: false })
@IsBoolean()
ENABLE_METRICS!: boolean;

Network validators

Five validators cover common network-related formats. Each one checks the string against a specific pattern without transforming the value, since network URIs and addresses remain as strings.

DecoratorValidatesExample
IsUrl(options?)Any parseable URL via the URL constructor. Pass the https option to reject non-HTTPS URLs."https://api.example.com"
IsEmailBasic email format like [email protected]"[email protected]"
IsHostHostname, IPv4, or IPv6 address"localhost", "192.168.1.1"
IsMongoUriURI starting with mongodb:// or mongodb+srv://"mongodb+srv://user:[email protected]/db"
IsRedisUriURI starting with redis:// or rediss://"redis://localhost:6379"

Network validators work well with Secret to mask credentials in the startup log. A MongoDB connection string contains a password, so the default masking behavior protects it automatically. Hostnames and ports are safe to display, so mark them with secret: false in the @Env options.

src/app.env.ts
@Env('CALLBACK_URL', { secret: false })
@IsUrl({ https: true })
CALLBACK_URL!: string;

@Env('MONGO_URI')
@IsMongoUri()
MONGO_URI!: string;

@Env('REDIS_URI')
@IsRedisUri()
REDIS_URI!: string;

@Env('API_HOST', { default: 'localhost', secret: false })
@IsHost()
API_HOST!: string;

Discord validators

Four validators target Discord-specific formats. They are strict about shape because invalid tokens, IDs, or webhook URLs cause hard-to-debug authentication failures at connect time.

DecoratorValidates
IsDiscordToken()Three-segment base64url string, 59–100 chars. Validates each segment uses only base64url characters.
IsDiscordId()Numeric snowflake, 17–19 digits. Rejects non-digit characters and out-of-range lengths.
IsDiscordWebhookUrl()Full Discord webhook URL matching the Discord webhook path on discord.com, canary.discord.com, or ptb.discord.com. Always mark this field with @Secret() because the URL embeds a token.
IsDiscordClientSecret()OAuth2 client secret: non-empty URL-safe string of 24–64 characters without whitespace. Always mark this field with @Secret().

For Discord-specific values, strict validation is worth the extra ceremony. A malformed webhook URL or client secret often fails far away from the env file, which makes startup validation one of the cheapest places to catch the mistake.

src/app.env.ts
@Env('DISCORD_TOKEN')
@IsDiscordToken()
TOKEN!: string;

@Env('GUILD_ID', { secret: false })
@IsDiscordId()
GUILD_ID!: string;

@Env('ALERT_WEBHOOK')
@IsDiscordWebhookUrl()
@Secret()
ALERT_WEBHOOK!: string;

@Env('DISCORD_CLIENT_SECRET')
@IsDiscordClientSecret()
@Secret()
CLIENT_SECRET!: string;

Data validators

Two validators handle structured data stored as strings in environment variables.

IsJson parses the raw value with JSON.parse during the transform phase. If parsing succeeds, the property holds the parsed JavaScript object or array. If parsing fails, the raw string passes through and the validate phase rejects it. This is useful for complex configuration that you want to store as a JSON string in a single environment variable.

IsEnum accepts an array of allowed values and checks that the resolved value matches one of them. It does not transform the value, so it works on strings by default. You can combine it with a type validator like IsNumber if your enum values are numeric, since IsEnum runs its check after all transforms complete.

src/app.env.ts
@Env('FEATURE_FLAGS')
@IsJson()
FEATURE_FLAGS!: Record<string, boolean>;

@Env('LOG_LEVEL', { default: 'info', secret: false })
@IsEnum(['debug', 'info', 'warn', 'error'])
LOG_LEVEL!: string;

Common validators

The common validators do not check types. Instead they modify how the field behaves in the pipeline. You use them alongside type validators to control optionality, masking, defaults, and custom logic.

IsOptional and Default both make the field optional, but Default also provides a concrete fallback. If you use Default, the field always resolves to a value. If you use IsOptional alone, the property can be undefined at runtime.

Transform intercepts the raw string and returns the new value. It runs before any validate step in the same rule and before rules declared below it. This lets you normalize data, like trimming whitespace or splitting comma-separated lists, before the type validator sees the value.

Validate adds a custom check to the pipeline. The function receives the already-transformed value and returns true when it is acceptable or a string error message when it is not. This is the escape hatch for business rules that the built-in validators do not cover.

@Env('ALLOWED_ORIGINS', { secret: false })
@Transform((raw) => raw.split(',').map((s) => s.trim()))
@Validate((value) => Array.isArray(value) && value.length > 0 ? true : 'Expected at least one origin')
ALLOWED_ORIGINS!: string[];