Pardon our dust while we move our docs here. The Godot (GDScript) docs are on this site, and the Yarn language, Unity, Godot (C#) and Unreal docs are still at docs.yarnspinner.dev.

Yarn variables, like $trust or $visitor_name, hold values that your dialogue can check and change. They’re kept in a Variable Storage, which your Yarn Scripts and your GDScript share. Yarn Scripts set variables with <<set>>, check them in <<if>>, and show them in lines with {$visitor_name}. Your game’s GDScript reads and changes the same variables, and can be told when they change.

A variable set by one side is seen by the other. Your game can set $visitor_name before a conversation, and the dialogue uses it. The dialogue can set $lamp_fixed, and your game lights the lamp.

flowchart LR
  yarn["Your Yarn Scripts<br>#60;#60;set#62;#62;, #60;#60;if#62;#62;, {$variable}"]
  storage[("Variable Storage<br>$trust = 2<br>$visitor_name = Sam")]
  game["Your GDScript<br>set_value, get_float,<br>subscribe"]
  save["Save file<br>in user://"]
  yarn <-->|read and change| storage
  game <-->|read and change| storage
  storage <-.->|save and load| save
Your Yarn Scripts and your GDScript both read and change the variables in the Variable Storage. The Dialogue Runner can save them to a file and load them back.
<<declare $trust = 0>>
<<declare $lamp_fixed = false>>
<<declare $visitor_name = "stranger">>
Rosa: Hello, {$visitor_name}.
<<set $trust to $trust + 2>>
<<if $trust >= 2>>
    Rosa: Thanks for the help.
<<endif>>
Three variables, declared with a default value, then set and checked.

Where variables are kept

Each Dialogue Runner has a Variable Storage. If you leave that setting empty, the Dialogue Runner makes a YarnInMemoryVariableStorage, which keeps variables in memory while the game runs. They’re lost when the game closes, unless you save them.

To choose the Variable Storage yourself, add one as a node in your scene, and set the Dialogue Runner’s Variable Storage to it:

GameNode2D
YarnDialogueRunner
VariableStorageYarnInMemoryVariableStorage
CanvasLayer
YarnLinePresenter
YarnOptionsPresenter
A Variable Storage node next to the Dialogue Runner. The Dialogue Runner’s Variable Storage setting points at it.
The Inspector for a YarnDialogueRunner, with the Variable Storage setting under Dialogue Setup highlighted, set to a node called VariableStorage
The Dialogue Runner's Variable Storage setting, under Dialogue Setup, set to a VariableStorage node in the scene.

When something asks for a variable’s value, the Variable Storage looks in three places, in this order:

  1. the value it’s storing, if the variable has been set,
  2. the variable’s expression, if it’s a smart variable,
  3. the default value from the variable’s <<declare>> in Yarn.

Reading a variable before it’s been set gives you its declared default.

Reading and changing variables from GDScript

Get the Variable Storage from the Dialogue Runner, and use the variable’s name, including the $:

var storage := dialogue_runner.variable_storage

storage.set_value("$visitor_name", "Sam")

var trust := storage.get_float("$trust")
var fixed := storage.get_bool("$lamp_fixed")
var visitor := storage.get_string("$visitor_name")
Line 1 The Dialogue Runner’s Variable Storage.
Line 3 Set a variable. Use its whole name, including the $.
Lines 5–7 Read variables as a float, bool or String. A variable that hasn’t been set gives its default from <<declare>>.
Reading and changing Yarn variables.

get_float(), get_bool() and get_string() return the value as that type. Each takes a second argument, the value to return if the variable doesn’t exist or has a different type: storage.get_float("$trust", 0.0). get_value() returns the value as it is.

Yarn variables can only hold numbers, text, and true or false. If you try to store anything else, like a Vector2 or a node, the Variable Storage logs an error and doesn’t store it. The built-in Variable Storage keeps every number as a float, so a whole number you set comes back as a float.

To give a variable a value the dialogue can use from its first line, set it before you start the dialogue. With the Dialogue Runner’s Auto Start on, the dialogue can start before your script’s _ready() runs, so turn Auto Start off and call dialogue_runner.start_dialogue() yourself.

Reacting when a variable changes

There are three ways to find out when a variable changes. Each one reports changes made by <<set>> in Yarn and changes made by your own code.

To keep something on screen up to date, like a counter, use subscribe_float(), subscribe_int(), subscribe_bool() or subscribe_string(). Your method gets the new value, as that type:

func _ready():
	var storage := dialogue_runner.variable_storage
	storage.subscribe_float(self, "$trust", _on_trust_changed)
	_on_trust_changed(storage.get_float("$trust"))


func _on_trust_changed(value: float) -> void:
	trust_label.text = "Trust: %d" % value
Line 3 Call _on_trust_changed with the new value whenever $trust changes. self is the listening node: when it leaves the scene tree, it’s unsubscribed.
Line 4 Show the starting value. Subscribing doesn’t call the method until the value changes.
Lines 7–8 Gets the new value as a float.
Updating a label whenever $trust changes.

The first argument is the node that’s listening. When it leaves the scene tree, it’s unsubscribed. subscribe_float() returns a number you can pass to storage.unsubscribe() to stop listening sooner.

Subscribing doesn’t call your method until the value changes, so call it yourself once, as above, to show the starting value.

To react to one variable without the node tracking, use add_change_listener(). Your method gets the new value. It returns a Callable: call it to stop listening.

var _stop_listening: Callable


func _ready():
	var storage := dialogue_runner.variable_storage
	_stop_listening = storage.add_change_listener(
			"$lamp_fixed", _on_lamp_fixed_changed)


func _on_lamp_fixed_changed(value: bool) -> void:
	if value:
		light_lamp()
Line 1 Keep the Callable that stops the listener. Call _stop_listening.call() when you want to stop.
Lines 5–7 Call _on_lamp_fixed_changed whenever $lamp_fixed changes.
Lines 10–12 Gets the new value as a bool.
Lighting the lamp when the Yarn Script sets $lamp_fixed.

To hear about every variable, connect to the Variable Storage’s variable_changed signal. It passes the variable’s name and its new value.

Smart variables don’t change by being set, so these don’t work for them. add_change_listener() logs an error if you try.

Saving and loading

The Dialogue Runner can save every variable in its Variable Storage to a file in Godot’s user:// folder, and load them back:

dialogue_runner.save_state_to_persistent_storage("dialogue_save.json")
dialogue_runner.load_state_from_persistent_storage("dialogue_save.json")
Saving and loading Yarn variables.

Both return true if they worked. Loading replaces all the current variables with the ones in the file.

Only the variables are saved, not where the dialogue is up to. To pick a conversation up again, save the name of the node you want to start from, and pass it to start_dialogue() after loading.

To save Yarn variables as part of your game’s own save file, use storage.get_all_variables(), which returns a Dictionary of every variable that’s been set, and storage.set_all_variables() to put them back.

Seeing variables while you test

A YarnInMemoryVariableStorage can show every variable on screen while the game runs:

  1. Add a YarnInMemoryVariableStorage node to your scene, and set it as the Dialogue Runner’s Variable Storage.
  2. Add a Label or RichTextLabel, and set it as the Variable Storage’s Debug Text View.
  3. Turn on the Variable Storage’s Show Debug.

The label shows one line per variable, like $trust = 2 (Single). It only lists variables that have been set, not ones still at their declared default.

Typed access with a generated class

Yarn Spinner can generate a Variable Storage class with a property for each variable, so you don’t have to type variable names as text. $trust becomes trust, $visitor_name becomes visitor_name, and each property has the matching GDScript type. See Generating a typed variables class.

Add a node of the generated class to your scene, and set it as the Dialogue Runner’s Variable Storage. Then:

var variables := dialogue_runner.variable_storage as YarnVariables
variables.visitor_name = "Sam"
if variables.trust >= 2:
	open_the_door()
Using the generated YarnVariables class.

Writing your own Variable Storage

To keep Yarn variables somewhere else, write a script that extends YarnVariableStorage. This one keeps them inside a Dictionary of save data, so they’re saved and loaded along with the rest of your game:

class_name SaveDataVariableStorage
extends YarnVariableStorage

## Your game's save data. Yarn variables are kept in it, so they're saved
## and loaded along with everything else.
var save_data: Dictionary = {"yarn": {}}


func set_value(variable_name: String, value: Variant) -> void:
	if not validate_value_type(variable_name, value):
		return
	var variables: Dictionary = save_data["yarn"]
	var old_value: Variant = variables.get(variable_name)
	variables[variable_name] = value
	_notify_listeners(variable_name, value, old_value)


func try_get_value(variable_name: String) -> Dictionary:
	var variables: Dictionary = save_data["yarn"]
	if variables.has(variable_name):
		return {found = true, value = variables[variable_name]}
	return {found = false, value = null}


func clear() -> void:
	save_data["yarn"].clear()


func get_all_variable_names() -> PackedStringArray:
	return PackedStringArray(save_data["yarn"].keys())


func get_all_variables() -> Dictionary:
	return save_data["yarn"].duplicate()
Lines 1–2 Extend YarnVariableStorage, and give the class a name so you can add it as a node.
Lines 4–6 Where the variables are kept. Here, a Dictionary inside the rest of the game’s save data.
Lines 9–11 set_value is called whenever a variable is set, from Yarn or from your code. validate_value_type logs an error and returns false if the value isn’t a number, text or true or false.
Lines 12–14 Store the value, remembering the old one first.
Line 15 Tell anything listening that the value changed. Without this, subscriptions, change listeners and variable_changed never fire.
Lines 18–22 try_get_value returns whether the variable has been stored, and its value. If it hasn’t, the Variable Storage falls back to smart variables and declared defaults.
Lines 25–26 clear removes every variable. Loading a save calls it before putting the saved values back.
Lines 29–34 The names and values of every variable that’s been set. Saving uses get_all_variables.
A Variable Storage that keeps Yarn variables in the game’s save data.

To use it, add a SaveDataVariableStorage node to your scene and set it as the Dialogue Runner’s Variable Storage.

A Variable Storage needs only those five methods. get_float() and the other readers, subscriptions, and saving and loading are built on them.

The demo scene

Before the dialogue starts, the game sets $visitor_name to “Sam”. Rosa greets the player by name, and the player’s choice raises $trust, which a label in the top right shows. Setting $lamp_fixed lights the lamp, the debug view in the top left lists every variable, and the variables are saved when the dialogue ends.

The demo scene running. The debug view in the top left lists each variable as it's set, and the Trust counter in the top right follows $trust.
GameNode2D
BackgroundColorRect
FloorColorRect
DoorColorRect
LampColorRect
GlowColorRect
RosaNode2D
BodyColorRect
NameLabel
YarnDialogueRunner
VariableStorageYarnInMemoryVariableStorage
UICanvasLayer
CallLogPanelPanelContainer
CallLogRichTextLabel
InventoryPanelPanelContainer
InventoryLabel
SavedLabel
YarnLinePresenter
YarnOptionsPresenter
The demo scene. The Dialogue Runner’s Variable Storage is set to the VariableStorage node, which shows its variables in CallLog.
title: VariablesDemo
---
<<declare $trust = 0>>
<<declare $lamp_fixed = false>>
<<declare $visitor_name = "stranger">>
Rosa: Hello, {$visitor_name}. What brings you here?
-> I can help with the lamp.
    <<set $trust to $trust + 2>>
    Rosa: That's kind of you.
-> Just looking around.
    <<set $trust to $trust + 1>>
    Rosa: Mind the stairs, then.
Rosa: Let me get the lamp going.
<<set $lamp_fixed to true>>
<<if $trust >= 2>>
    Rosa: Thanks for the help, {$visitor_name}.
<<else>>
    Rosa: See you around, {$visitor_name}.
<<endif>>
===
The Yarn Script.
extends Node2D

@export var dialogue_runner: YarnDialogueRunner
@export var trust_label: Label
@export var saved_label: Label
@export var lamp: ColorRect
@export var glow: ColorRect


func _ready():
	var storage := dialogue_runner.variable_storage

	# Set a Yarn variable from GDScript before the dialogue starts.
	storage.set_value("$visitor_name", "Sam")

	# Keep the trust counter up to date.
	storage.subscribe_float(self, "$trust", _on_trust_changed)
	_on_trust_changed(storage.get_float("$trust"))

	# Light the lamp when the Yarn Script sets $lamp_fixed.
	storage.add_change_listener("$lamp_fixed", _on_lamp_fixed_changed)

	dialogue_runner.dialogue_completed.connect(_on_dialogue_completed)
	dialogue_runner.start_dialogue("VariablesDemo")


func _on_trust_changed(value: float) -> void:
	trust_label.text = "Trust: %d" % value


func _on_lamp_fixed_changed(value: bool) -> void:
	if value:
		var tween := create_tween()
		tween.tween_property(lamp, "color", Color(1.0, 0.85, 0.35), 0.8)
		tween.parallel().tween_property(glow, "modulate:a", 1.0, 0.8)


func _on_dialogue_completed() -> void:
	if dialogue_runner.save_state_to_persistent_storage("variables_demo.json"):
		saved_label.text = "Saved to user://variables_demo.json"
Lines 3–7 Nodes in the scene, set in the Inspector.
Line 11 The Dialogue Runner’s Variable Storage. In this scene, it’s the VariableStorage node.
Lines 13–14 Set $visitor_name before the dialogue starts, so Rosa’s first line uses it.
Lines 16–18 Keep the trust counter up to date, and show the starting value.
Lines 20–21 Light the lamp when $lamp_fixed changes.
Lines 23–24 Save when the dialogue ends, then start it. Auto Start is off, so the dialogue starts here, after $visitor_name is set.
Lines 27–28 Gets the new value of $trust.
Lines 31–35 Gets the new value of $lamp_fixed, and fades the lamp on when it’s true.
Lines 38–40 Save every variable to user://, and show where.
The script on the Game node. The Dialogue Runner’s Auto Start is off, so this script sets $visitor_name first and then starts the dialogue.
Next step Smart Variables Variables that are worked out from other variables each time they're read.