Cerial

Enums vs Literals

When to use enums vs literal types — a practical comparison

Cerial offers two ways to define union-like field types: enums and literals. Both create a set of allowed values for a field, but they serve different purposes and have different capabilities. This page helps you choose the right one.

Quick Comparison

FeatureEnumsLiterals
Variant typesString-onlyString, int, float, bool, broad types, objects, tuples, literal refs, enum refs
Const objectYes (StatusEnum)No
Union typeYes (StatusEnumType)Yes (Status)
Runtime accessStatusEnum.ACTIVEString literals only
CompositionVia extends inheritanceInline refs (literal/enum names in body)
Object/tuple variantsNoYes
Sub-field selectNoNo (boolean select only)
OrderByYes (alphabetical string ordering)Excluded (mixed types make ordering ambiguous)
Where operatorseq, neq, in, notIn, contains, startsWith, endsWitheq, neq, in, notIn (+ more based on variant types)

When to Use Enums

Enums are the right choice when you have a fixed set of string labels and want runtime access through a generated const object. They're simpler, more ergonomic, and give you autocompletion:

enum Status { ACTIVE, INACTIVE, PENDING }
enum Role { ADMIN, EDITOR, VIEWER }

model User {
  id Record @id
  status Status
  role Role
}
import { StatusEnum, RoleEnum } from './generated/client';

// Const object provides autocompletion and safe refactoring
if (user.role === RoleEnum.ADMIN) {
  // ...
}

Choose enums when:

  • All values are strings
  • You want a const object for runtime access (StatusEnum.ACTIVE)
  • You need orderBy support (alphabetical sorting)
  • You want a clean, Prisma-like declaration syntax

When to Use Literals

Literals are the right choice when you need mixed types, structured variants, or inline composition from other literals and enums:

# Mixed types — not possible with enums
literal Priority { 'low', 'medium', 'high', 1, 2, 3 }

# Broad types — accept any value of a type
literal Flexible { String, Int }

# Object variants — structured data in the union
object Point { x Float, y Float }
literal Shape { 'none', Point }

# Inline composition — combine multiple sources
enum Role { ADMIN, EDITOR, VIEWER }
literal Access { Role, 'custom', 'guest' }

Choose literals when:

  • You need numbers, booleans, or mixed types
  • You want object or tuple variants in the union
  • You want to compose a union from other literals or enums inline
  • You don't need a runtime const object

Composition Styles

Both enums and literals support building on existing definitions, but through different mechanisms:

MechanismEnumsLiterals
Inline referenceNot supportedliteral Extended { Base, 'extra' } — values expanded inline
extends keywordenum Child extends Parent { NEW_VALUE }literal Child extends Parent { 'extra' }

Enums use extends for inheritance — the child inherits all parent values and can add new ones. Literals can use either inline references (placing a literal or enum name directly in the variant list) or extends.

# Enum composition via extends
enum BaseRole { VIEWER, EDITOR }
enum AdminRole extends BaseRole { ADMIN, SUPER_ADMIN }

# Literal composition via inline reference
literal Status { 'active', 'inactive' }
literal ExtendedStatus { Status, 'archived' }

Cross-Referencing

Literals can reference enums by name. When a literal includes an enum, the enum's string values are inlined into the literal's union:

enum Status { ACTIVE, INACTIVE, PENDING }

literal ExtendedStatus { Status, 'ARCHIVED', 'DELETED' }
# Resolves to: 'ACTIVE' | 'INACTIVE' | 'PENDING' | 'ARCHIVED' | 'DELETED'

This lets you start with an enum for its const object benefits, then extend it into a literal when you need additional values or mixed types in a different context.

Decision Guide

  • "I have a fixed set of string labels" → Use an enum
  • "I need numbers, booleans, or mixed types" → Use a literal
  • "I want runtime access via a const object" → Use an enum
  • "I need object or tuple variants in the union" → Use a literal
  • "I want to compose unions from other definitions" → Use a literal (inline refs) or an enum (extends)
  • "I need orderBy on this field" → Use an enum (literals are excluded from orderBy)

You can use both in the same project — enums for simple string constants that benefit from a const object, and literals for more complex union types. They work well together, especially since literals can reference enums.

On this page