VibORM
Fields

Enum Field

Enum field type that restricts values to a predefined set of options

Basic Usage

import { s } from "viborm";

s.enum(["PENDING", "ACTIVE", "SUSPENDED"]); // Required enum
s.enum(["PENDING", "ACTIVE"]).nullable(); // Enum | null

Chainable Methods

s.enum(["USER", "ADMIN", "MODERATOR"])
  .name("role")         // Set database enum type name (for reuse across tables)
  .nullable()           // Allow NULL
  .schema(schema)       // Custom StandardSchema validator (e.g., branded types)
  .default("USER")      // Default value (must be in enum)
  .map("column_name");  // Custom column name

Naming Enums for Reuse

By default, VibORM generates enum type names based on the table and column (e.g., user_status_enum). Use .name() to create a shared enum type that can be reused across multiple tables:

// Define a named enum at the top level
const Status = s.enum(["PENDING", "ACTIVE", "INACTIVE"]).name("status");

// Use it in multiple models - same PostgreSQL enum type
const user = s.model({
  id: s.string().id(),
  status: Status.default("PENDING"), // Uses "status" enum type
});

const order = s.model({
  id: s.string().id(),
  status: Status.default("PENDING"), // Same "status" enum type
});

Without .name(), each column would create its own enum type:

  • user_status_enum for users.status
  • order_status_enum for orders.status

With .name("status"), both columns share the same status enum type.

Migration Behavior

Named enums are tracked as a single type. When you modify the enum values, VibORM generates one ALTER TYPE instead of multiple.

Custom Schema Validation

You can add custom validation or branded types to enum fields:

import { pipe, picklist, brand } from "valibot";

// Branded enum type
const role = s.enum(["USER", "ADMIN", "MODERATOR"]).schema(brand("Role"));

Type Inference

The TypeScript type is automatically inferred as a union:

const role = s.enum(["USER", "ADMIN", "MODERATOR"]);
// TypeScript type: "USER" | "ADMIN" | "MODERATOR"

const status = s.enum(["draft", "published", "archived"]).nullable();
// TypeScript type: "draft" | "published" | "archived" | null

Database Behavior

PostgreSQL creates a native ENUM type:

CREATE TYPE "Role" AS ENUM ('USER', 'ADMIN', 'MODERATOR');
CREATE TABLE users (
  role "Role" NOT NULL
);

MySQL uses inline ENUM:

CREATE TABLE users (
  role ENUM('USER', 'ADMIN', 'MODERATOR') NOT NULL
);

SQLite stores as TEXT with check constraint:

CREATE TABLE users (
  role TEXT CHECK(role IN ('USER', 'ADMIN', 'MODERATOR')) NOT NULL
);

Type Mapping

ModifierTypeScriptPostgreSQLMySQLSQLite
s.enum([...])Union typeENUMENUMTEXT
.nullable()T | nullENUM NULLENUM NULLTEXT NULL
.array()T[]ENUM[]JSONJSON

Examples

// User role
const role = s.enum(["USER", "ADMIN", "MODERATOR"]).default("USER");

// Order status
const orderStatus = s
  .enum([
    "PENDING",
    "CONFIRMED",
    "PROCESSING",
    "SHIPPED",
    "DELIVERED",
    "CANCELLED",
  ])
  .default("PENDING");

// Content visibility
const visibility = s.enum(["PUBLIC", "PRIVATE", "UNLISTED"]).default("PUBLIC");

// Priority level
const priority = s.enum(["LOW", "MEDIUM", "HIGH", "CRITICAL"]);

// Subscription tier
const tier = s.enum(["FREE", "PRO", "ENTERPRISE"]).default("FREE");

Using with TypeScript

Extract the enum type for use elsewhere:

const statusField = s.enum(["ACTIVE", "INACTIVE", "PENDING"]);

// Extract type from field
type Status = (typeof statusField)["~"]["schemas"]["base"]["infer"];
// "ACTIVE" | "INACTIVE" | "PENDING"

// Use in your code
function updateStatus(id: string, status: Status) {
  return client.user.update({
    where: { id },
    data: { status },
  });
}

Enum vs String

AspectEnumString
Type safetyCompile-time restrictedAny string
ValidationDatabase enforcedNeeds custom validator
StorageOptimized (integer internally)Full string
FlexibilityFixed setAny value
MigrationsRequires migration to add valuesNo migration needed

When to Use Enum

  • Fixed set of values that rarely changes
  • Status fields, roles, types
  • Need database-level enforcement

When to Use String

  • Values may change frequently
  • User-defined categories
  • Need flexibility without migrations

Common Patterns

State Machine

const orderStatus = s.enum([
  "PENDING", // Initial state
  "CONFIRMED", // After payment
  "PROCESSING", // Being prepared
  "SHIPPED", // In transit
  "DELIVERED", // Completed
  "CANCELLED", // Cancelled by user
  "REFUNDED", // Money returned
]);

Multi-Level Permissions

const permission = s.enum(["NONE", "READ", "WRITE", "ADMIN"]);

On this page