Skip to content

Add stringbool feature similar to Zod #1240

@alexilyaev

Description

@alexilyaev

Proposal

Add stringbool to Valibot core

Intro

Zod added a new schema in v4 z. stringbool() (https://zod.dev/api?id=stringbool)

In some cases (e.g. parsing environment variables) it's valuable to parse certain string "boolish" values to a plain boolean value. To support this, Zod 4 introduces z.stringbool():

This works great when validating and parsing environment variables (e.g. using t3-env), where we want a specific set of string values to be converted into a boolean.

Usage example with Zod and t3-env

src/evn.ts

import { createEnv } from "@t3-oss/env-core";
import { z } from "zod/v4";
 
export const env = createEnv({
  server: {
    DATABASE_URL: z.string().url(),
    DATABASE_LOG_ENABLED: z.stringbool(),
  },
  runtimeEnv: process.env,
});

.env

DATABASE_URL="https://sometihng.com"
DATABASE_LOG_ENABLED="1"

src/main.ts

import { env } from './src/env';

env.DATABASE_LOG_ENABLED
// true

Basic user-land implementation of stringbool in Valibot

src/env.ts

import { optional, picklist, pipe, string, transform, url } from 'valibot';
import { createEnv } from '@t3-oss/env-nextjs';

interface StringBoolParams {
  truthy?: string[];
  falsy?: string[];
  case?: 'sensitive' | 'insensitive' | undefined;
}

function stringbool(params: StringBoolParams = {}) {
  const defaultValues = {
    truthy: ['true', '1', 'yes', 'on', 'y', 'enabled'] as const,
    falsy: ['false', '0', 'no', 'off', 'n', 'disabled'] as const,
  };

  const truthy = params.truthy ?? defaultValues.truthy;
  const falsy = params.falsy ?? defaultValues.falsy;
  const stringBoolEnum = [...truthy, ...falsy] as const;

  return pipe(
    string(),
    transform((str) => (params.case === 'sensitive' ? str : str.toLowerCase())),
    picklist(stringBoolEnum),
    transform((str) => truthy.includes(str)),
  );
}

export const env = createEnv({
  server: {
    DATABASE_URL: pipe(string(), url()),
    DATABASE_LOG_ENABLED: optional(stringbool(), 'false'),
  },
  runtimeEnv: process.env,
});

Considerations

Should it be added to Valibot core or as an external utility library?

  • I believe it should be in core as it is a common enough use case to be useful out-of-the-box

Should it be a Schema or an Action?

  • Reading through Valibot Docs - Mental model, it seems that stringbool in Valibot should be an Action and not a Schema, as it basically accepts only a string as an input and transforms the result into a boolean based on the value

Implementation

  • As mentioned on Discord, the implementation should not use other schemas or methods, but serve as standalone code with no dependencies
  • Can check for current implementation of coercion actions for primitives

Related

  • Similar actions can be proposed: truthy and falsy

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions