open vs closed enum: Can You Still Change It After Release?
Every enum defined in Lesson 11 was the «stock model». The official docs spend real ink on a different question: after your project ships, can an enum still grow members? The answer is enforced for you by the enum's own type rules — this page covers the closed and open contracts, and what each one costs.
1. Why «After Release» Is a Big Deal
On a throwaway solo demo, reshape your enums however you like — code and data are both in your hands anyway. A long-running project is different: after v1 ships, your enum values may already be lying in players' save data; v2's new code and v1's old data have to share the stage. Suddenly «add one member to the enum» is no longer a casual edit but a version-compatibility event: what should the old version's entry-routing cases do when an entry they've never seen walks in?
Many languages and engines wait for the game to actually run and crash before you find out. Verse's approach has personality: the moment you build the enum, you must declare your intent — «sealed for good» or «door left ajar» — and then the Compile-stage checks hold you to that promise to the bitter end.
2. closed: Sealed for Good, in Exchange for an Exhaustive-Match Safety Net
Enums are closed by default: once the project ships, the entry list is frozen — later versions can neither add nor remove. It sounds like a restriction, but it's a big free gift: exhaustive matching. Since the engine knows exactly which entries exist, a case that spells them all out can skip the fallback exit (Switch on Enum's Default pin) — and if you miss one, Compile flat-out refuses:
# closed by default: the member set is frozen, so case can match exhaustively
chest_tier := enum{Common, Rare, Epic}
TierLabel(Tier:chest_tier)<computes>:string =
case (Tier):
chest_tier.Common => "Common"
chest_tier.Rare => "Rare"
chest_tier.Epic => "Epic"
▸ Blueprint translation: a default-closed chest_tier enum (Common / Rare / Epic), plus a Blueprint function TierLabel that uses case to translate the three entries into "Common" / "Rare" / "Epic". Because the entries are frozen, spelling out all three is enough — no Default exit needed.
The safety net only truly pays out during maintenance: add Legendary to chest_tier during development, and every case you forgot to update across the whole project gets named by Compile. Its flip side — leave a fallback exit (Default) on a case, and new entries slip silently into the fallback; the net fails on the spot. Hence the advice for closed enums: spell them all out whenever you can; leave a Default exit sparingly.
3. open: Door Left Ajar — Trading Discipline for Flexibility
If you're certain this enum is bound to grow — say, damage types: fire and ice this season, poison all but guaranteed next — you can leave the door ajar at definition time by adding the <open> marker:
# open: later versions may add new members after release
damage_type := enum<open>{Fire, Ice}
▸ Blueprint translation: exactly like building an ordinary enum, only with the <open> marker hung after the name — telling the engine «this list will grow more entries later».
The cost shows up immediately: for every case over an open enum, Compile forces you to keep a default (fallback) exit — old code can absolutely run into an entry that was only added in a newer version, and someone has to catch it (for the exact fallback syntax, defer to the official enum docs ↗). In other words, open trades the discipline of «one spare exit at every case» for the freedom to «keep expanding after release»; closed trades the other way. Neither contract is better — only better suited to your live-ops plan.
The last puzzle piece is <persistable>: only an enum defined with this marker can go into player save data (the kind that survives quit-and-rejoin, one copy per player — think SaveGame data). Put all three together and you'll notice something rare among engines — «what may change after release» is written straight into the enum's type rules: what may change, who's responsible when it does, whether old saves still read — all settled at the Compile stage. For developers planning to run their project as a «long-term service» rather than a «one-shot piece», this is one of the most concrete engineering promises Verse makes.
What is the biggest benefit a default (closed) enum buys you?
Sources
Compiled from the official Epic documentation: Enum in Verse — official Epic Games documentation ↗