Ren'Py Variable Strategy: When to Use `define` vs `default` for Game State
When adding story flags mid‑development, choose <code>default</code> over <code>define</code> to maintain save compatibility. Here’s how to verify your variable strategy works correctly.
25 Aug 2025, 17:26 UTC

The Problem: Variables That Break Saves
When you’re mid‑development and need to add a new story flag, you face a critical choice: define or default? The wrong choice can make old saves unopenable or cause mysterious state loss during rollback. I’ve seen teams waste days debugging why a simple new variable caused everything to break.
The Core Difference
In Ren'Py’s store system, define runs during init phase—before the game starts and re‑evaluates from script on every run. It’s meant for constants: character objects, colors, transforms. Think of it as Python module‑level code that executes once per session.
default is lazy‑evaluated. It only assigns when that name doesn’t already exist in the current game state. This means it naturally handles save compatibility: if a save lacks the variable, default fills it in. If the save has it, default respects the saved value.
Worked Example: Adding a Trust Flag
Imagine you’re adding relationship tracking mid‑project:
# game/script.rpy - BEFORE adding the flag
label start:
# ... existing story ...
return
# Add this line anywhere in the file (not inside labels):
default trust = 0
label after_first_date:
if trust >= 5:
# ... happy ending branch ...
else:
# ... neutral branch ...
return
Why this works: A save made before trust existed will load without error. When the branch evaluates, trust gets initialized to 0 if missing from the save. No NameError, no broken saves.
Testing Your Setup
Verify this locally with a minimal project:
default test_flag = 0at file top level- Create a save from a point where
test_flagexists - Add a new
default new_var = "hello"used later in script - Load the old save—confirm no errors
- Open developer console (Shift+O) and
print(new_var)to verify value - Test rollback—confirm
default-declared values revert properly
The Trade‑off: Value Migration
Limitation: Changing a default value later won’t update existing saves. If you initially set default coins = 10 and later change it to default coins = 5, players with existing saves keep their original 10 coins.
Solution: Use migration hooks for critical changes:
label after_load:
if coins == 10:
$ coins = 5 # Migrate old value
return
Key Takeaways
- Use
defaultfor mutable story state: flags, counters, inventory - Use
definefor constants: characters, colors, config values - Avoid mutating
defined values—they’re not save‑aware - Test save compatibility after adding any variable
- Consider
persistentfor cross‑playthrough data: gallery unlocks, preferences
Check your Ren'Py version against official docs—behavior can shift between major branches. The in‑game developer console is invaluable for inspecting state after load and rollback operations.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.