You collect 30 coins in stage 1 and step through the door. The moment the next stage begins, the counter on screen reads 0. You definitely stored the variable on the Player, yet the value has gone somewhere.
It didn't disappear. The Player itself was rebuilt. There's exactly one container in UE5 that survives across levels, and that's the Game Instance . This article covers creating a Game Instance Blueprint and registering it in Project Settings, reading and writing through Get Game Instance , when Init and Shutdown fire, and what does and doesn't belong in there.
What You'll Learn
- What gets rebuilt and what survives when you change levels
- How to create a Game Instance Blueprint, plus the Project Settings registration that makes nothing work if you forget it
- The standard read/write pattern:
Get Game Instance→Cast To- When
Init/Shutdownactually fire- What belongs in a Game Instance, and what doesn't
- How the roles differ from Save Game and Subsystems
- Hands-on: carry a score and clear record across three stages
Only Game Instance Survives
First, let's look at how long each container lives along a timeline.

| Container | Lifetime | On level change |
|---|---|---|
| Game Instance | From app launch to app quit | Stays as-is |
| GameMode / GameState | From level start to level end | Rebuilt |
| PlayerState | Same as above | Rebuilt |
| Characters and placed Actors | Same as above | Destroyed |
| Widget | From being added until destroyed | Destroyed |
| Level Blueprint variables | Only within that level | Gone |
Game Instance is in a class of its own. It's created before the first level is even loaded and continues to exist as a single object until you close the app. Because it sits outside levels, swapping levels doesn't affect it.
Put the other way around: put a variable anywhere except the Game Instance and it returns to its default the moment you change levels. A common stumble is "I figured PlayerState would be safe", but PlayerState is also a per-level container (→ the level transition article).
One sentence settles the decision. Values you want remembered until you stop Play belong in the Game Instance.
Create It, Then Register It
Three steps, and forgetting the third means nothing happens at all .

1. Create a Blueprint Class
Right-click in the Content Browser → Blueprint Class . In the parent class dialog, open ALL CLASSES , type GameInstance into the search box, and select it. It isn't in the row of common-class buttons, so pick it from the search. Name it BP_GameInstance .
2. Add the variables you want to carry
Open it and add variables from the My Blueprint panel. Set defaults in Class Defaults . Unlike Actors, this is never placed in a level, so the details panel's Instance Editable doesn't apply.
3. Register it in Project Settings
Open Edit > Project Settings > Project > Maps & Modes and set Game Instance Class in the Game Instance category to BP_GameInstance .
That third step is by far the biggest source of trouble in this article. Without registering it, the engine keeps using the default GameInstance . Your class is never created, so the Cast in the next section fails every time and all your variable reads and writes silently do nothing. No error, no warning.
If you feel like "I made a Game Instance but values aren't persisting", open this before you suspect your logic.
Note: the setting is per-project. After changing it, stop Play and start it again before checking. It won't apply to a PIE session already running.
Read and Write via Get Game Instance and Cast
You can reach it from any Blueprint in two nodes. Actors, Widgets, and Level Blueprints all work the same way.

Get Game Instance
→ Cast To BP_GameInstance
As BP Game Instance →
Set Total Score (Value: Total Score + 10)
Get Game Instance returns the base Game Instance type, so the variables you added aren't visible on it. Insert Cast To BP_GameInstance and your variables and functions appear.
Wire up the Cast's failure pin and you'll notice a missing registration on the spot.
Get Game Instance
→ Cast To BP_GameInstance
Cast Failed → Print String ("Game Instance Class is not set")
You may be worried that Casting is expensive, but there's no concern here. BP_GameInstance is guaranteed to be loaded already because it's specified in Project Settings , so the Cast never drags in extra assets. When Casting does become a problem is covered in the Cast and Blueprint Interface article.
If writing Get Game Instance → Cast every time still gets tedious, you have two options.
- Add functions to the Game Instance: define a function like
AddScore(Amount)on the Game Instance Blueprint, and callers only need "Cast → call one function". The scoring rule lives in one place, so a later change like "apply a multiplier during a double-points event" is a one-place edit - Move it to a Subsystem: Subsystems come with a dedicated Get node, so no Cast is needed (covered below)
Init and Shutdown
Right-click in the Game Instance Blueprint's event graph and you can add Event Init and Event Shutdown .

| Event | When it fires | How often |
|---|---|---|
| Init | At game launch. Before the first level is loaded | Exactly once |
| Shutdown | When the game quits | Exactly once |
They don't fire on level changes. That's the decisive difference from an Actor's Event BeginPlay . BeginPlay runs each time the level changes; Init runs once at launch.
When testing in the editor, think of it as Init running when you press Play and Shutdown running when you stop Play , because the Game Instance is rebuilt for each PIE session.
Good candidates for Init are "things done exactly once at launch", such as:
- Checking for save data and loading it if present
- Reading settings such as volume and key bindings
- Deciding the random seed
One caution though. At Init time, neither the level nor the player exists yet. Get Player Character returns None . Anything that touches the player belongs in a level-side BeginPlay, not Init.
What Belongs There and What Doesn't
Game Instance is convenient, so everything with no obvious home ends up there. There's one clear line to draw. Store values, not references.

| Fine to store (values) | Don't store (references) |
|---|---|
| Score, gold, lives (Integer / Float) | A reference to the player Character |
| IDs of cleared stages (Name array) | A reference to an Actor placed in the level |
| Held item IDs and counts (Map) | A reference to a Widget on screen |
| Difficulty or selected character as an Enum | A reference to a Component |
| Volume and key binding settings | Coordinates or room numbers that only exist in that level |
The reason is simple: what the reference points at doesn't exist in the next level . A variable pointing at an Actor destroyed by a level transition becomes None , and calling a function on it gives you an Accessed None error.
The nasty part is that it works fine while you're testing within one level . It only breaks after a transition, which delays finding the cause. If what you want to carry over is "that enemy", store an ID you can rebuild that enemy from , not an Actor reference.
There's another line worth drawing: don't overstuff it. There's only one Game Instance, so every variable you add puts another unrelated feature in the same class. Judge by "does it cross levels?" and keep out anything that doesn't ; that's how you keep it readable later.
How It Differs from Save Game
These get confused often, but they cover completely different ground.
| Game Instance | Save Game | |
|---|---|---|
| Where it lives | Memory | A file on disk ( .sav ) |
| Lifetime | Until the app closes | Until you delete it |
| Level transition | Survives | Survives |
| App restart | Gone | Survives |
| Effort to read/write | Just touch the variables | Pack into a box, write out, read back and Cast |
Game Instance is "memory for this play session"; Save Game is "a record handed to the next one". They don't compete; you use them together.
The common shape is this: do your in-game accumulation on the Game Instance and write out to Save Game at natural checkpoints. Read it back in Init at launch and load it into the Game Instance. That way in-game logic never touches a file.
Game Instance vs Subsystem
A GameInstance Subsystem is a container with exactly the same lifetime as the Game Instance. Created at launch, unaffected by level transitions, destroyed at quit.
The only difference is the granularity of how you store things .
| Game Instance | GameInstance Subsystem | |
|---|---|---|
| What it is | One place to keep things across levels | A mechanism for splitting by feature |
| How many | One per project | As many as you have features |
| Creation | Blueprint only is enough | Requires C++ |
| Getting it | Get Game Instance → Cast | A dedicated Get node (no Cast) |
| Lifetime | Launch to quit | Same |
Decide in this order.
- Start with Game Instance. It's Blueprint-only and works as soon as you add one variable
- Once unrelated features start sharing it , such as score, volume, save management, and achievements, split them out into Subsystems per feature
In other words, this article is about the storage location , and the Subsystem article is about the mechanism for splitting that storage by feature . It's fine to get something working with a Game Instance first and move to Subsystems when the need arrives. And if you've gathered the logic into functions on the Game Instance, you can carry the contents over as-is.
Hands-On: Carrying a Score Across Three Stages
Cumulative score in a stage-clear action game, a run's earnings in a roguelike, a streak record in a puzzle game. "A total across multiple levels" comes up regardless of genre. Here we'll accumulate a score across three stages and also record which ones were cleared.
What it looks like running
Touch the goal in each of the three stages in order and the score builds up 120 → 200 → 350 , with the total and clear count shown on the results screen.

Setup to follow along
Create a new project from the Third Person template and prepare the following.
Four levels (create them via File > New Level > Basic and save into Content/Maps . Place a Player Start in each and set World Settings' GameMode Override to BP_ThirdPersonGameMode )
| Level name | What to place |
|---|---|
L_Stage01 | One BP_StageGoal |
L_Stage02 | One BP_StageGoal |
L_Stage03 | One BP_StageGoal |
L_Result | Nothing |
Variables on BP_GameInstance (parent class: GameInstance)
| Variable name | Type | Default value |
|---|---|---|
TotalScore | Integer | 0 |
ClearedStages | Name ( Array ) | (empty) |
After creating it, set Edit > Project Settings > Project > Maps & Modes > Game Instance Class to BP_GameInstance .
BP_StageGoal (parent class: Actor)
| Element | Setting |
|---|---|
| Box Collision | Box Extent 100 / 100 / 100 , Collision Preset OverlapAllDynamic |
Variable StageID (Name / Instance Editable ) | Default Stage01 |
Variable StageScore (Integer / Instance Editable ) | Default 0 |
Variable NextLevel (Level (Object Reference) / Instance Editable ) | Unset |
Variable IsTransitioning (Boolean) | false |
Making them Instance Editable is the key. You place the one BP_StageGoal in all three levels and change the values per placed instance from the details panel.
| Placed in | StageID | StageScore | NextLevel |
|---|---|---|---|
L_Stage01 | Stage01 | 120 | L_Stage02 |
L_Stage02 | Stage02 | 80 | L_Stage03 |
L_Stage03 | Stage03 | 150 | L_Result |
Game Instance side: the ClearStage function
Create a new ClearStage function under Functions on BP_GameInstance and add two input pins.
| Input pin | Type |
|---|---|
StageID | Name |
Score | Integer |

Function: ClearStage (inputs: StageID / Name, Score / Integer)
→ Add Unique (Target: ClearedStages, New Item: StageID)
→ Set Total Score (Value: Add (A: Total Score, B: Score))
→ Print String (Append: "TOTAL: " + Total Score as string)
Note it uses Add Unique rather than Add . That prevents double-counting the clear record when a stage is replayed. Add Unique does nothing and just returns the index if the value is already present.
Concentrate the score addition here. Pinning down a single place where TotalScore is modified saves you from hunting for "something out there is resetting it to 0" later.
Goal side
Hook On Component Begin Overlap on BP_StageGoal 's Box Collision.
BP_StageGoal
On Component Begin Overlap (Box)
→ Cast To BP_ThirdPersonCharacter (Object: Other Actor)
→ Branch (Condition: IsTransitioning)
True → (do nothing)
False ↓
→ Set IsTransitioning (true)
→ Get Game Instance
→ Cast To BP_GameInstance
As BP Game Instance →
ClearStage (StageID: StageID, Score: StageScore)
→ Open Level (by Object Reference) (Level: NextLevel)
Calling ClearStage before Open Level matters. Nodes wired after Open Level end up running right as the current level is being torn down, which breaks anything order-dependent (→ the level transition article).
The IsTransitioning branch prevents double firing. Overlaps can come in more than once in a single frame, and without this the score is added twice.
Results side
Read the values in L_Result 's Level Blueprint.
Event BeginPlay
→ Get Game Instance
→ Cast To BP_GameInstance
As BP Game Instance →
Print String (Append: "TOTAL: " + Total Score, Duration: 10.0)
→ Length (Target: Cleared Stages)
→ Print String (Append: "CLEARED: " + result, Duration: 10.0)
Verifying it
Open L_Stage01 , Play, and touch the goal to run all three stages.
- Each time you touch a goal, the screen shows
TOTAL: 120→TOTAL: 200→TOTAL: 350 - In
L_Result,TOTAL: 350andCLEARED: 3display for 10 seconds - If you log something in
Init, it appears in the Output Log exactly once when Play starts and never on level changes
Troubleshooting if it doesn't work.
- The result is always 0 and the mid-run Print Strings never appear → Game Instance Class isn't set in Project Settings. The default GameInstance is in use and the Cast is failing
- Each stage shows the right value but only the result is 0 → the results side is reading a Level Blueprint variable in that level instead of the Game Instance
- The score doubles, e.g.
TOTAL: 240→ theIsTransitioningbranch is missing and the overlap is running twice CLEAREDis greater than 3 → you're usingAddinstead ofAdd Unique, so re-clearing a stage stacks up- Touching the goal does nothing → the Box Collision's Collision Preset isn't
OverlapAllDynamic - It doesn't move to the next level → the placed instance's
NextLevelis unset (with Instance Editable off, the field doesn't even appear)
Now try this once: set Game Instance Class in Project Settings back to empty and Play. Touching the goal displays nothing and no score is added. The Cast just quietly fails, with no error. Seeing this behavior once means that next time you hit "I made it but it does nothing", you'll open the right place first.
Two things to take away.
- Confine writes to a single function:
TotalScoreis neverSetdirectly from outside; it changes only throughClearStage. The more universally reachable a storage location is, the more worthwhile a narrow entrance becomes. Adding multiplier events or achievement checks stays inside that one function - You carry values, not references: what's recorded is only
NameandInteger. It's tempting to stuff "the goal Actors you cleared" into an array, but they'll all beNonein the next level. Hold IDs and, when you need the real thing, look it back up from a Data Asset
To keep this total for the next launch, continue to the save/load article; to turn the results screen from Print String into real UI, continue to the UMG article.
Bonus: Good to Know for Later
- A Game Instance has no visual presence: it isn't an Actor, so it can't be placed in a level and has no position. Design on the assumption that you can't add Components either. If the "feature you want to carry around" is shaped like a Component, it's more natural to attach it as a Component on the player and hand only the values to the Game Instance
- Plan on not using Tick: running per-frame logic on the Game Instance keeps it running regardless of what the level is doing. If you need to measure time, drive the value updates from events instead (→ designing with less Tick)
- Don't forget to reset on retry: you need something that returns
TotalScoreto 0 for a second run. Its home is the title screen. Reset it on the results screen and the results screen will wipe the value it's displaying - The editor and a packaged build can look like they behave differently: in the editor the Game Instance is rebuilt every time you stop Play, while in a packaged build it persists until the app closes. That's where "it resets every time in the editor but the shipped build keeps the old value" comes from (→ the packaging article)
- Debug by printing values: Game Instance variables don't belong to any Actor in the level, so you can't select something in the World Outliner and inspect them in the details panel. Getting in the habit of dropping
Print Stringat key points or logging to the Output Log makes it much easier to follow (→ the Print String and logging article)
Summary
- On a level change, Actors, Widgets, GameMode, and PlayerState are all rebuilt . The only survivor is the Game Instance
- Creation is three steps. Forget the third, registering it under Project Settings > Maps & Modes > Game Instance Class , and nothing happens with no error to tell you
- Read and write with
Get Game Instance→Cast To. Wiring aPrint Stringto the Cast's failure pin catches a missing registration Initfires exactly once at launch . It doesn't fire on level changes, and at that moment neither the player nor the level exists- Store values . Actor and Widget references turn into
Nonein the next level - Game Instance is memory for this session, Save Game is a record for the next one. When you want things split per feature, move to Subsystems
In the game you're building now, how many numbers should be remembered until the player returns to the title? That list is your BP_GameInstance variable list.