[UE5] Carrying Data with Game Instance: The Storage That Survives Level Changes

Created: 2026-07-20

Your score reset to 0 after a level change. Game Instance is the one container in UE5 that lives for the whole session. Covers creating it, registering it in Project Settings, reading and writing via Get Game Instance and Cast, Init/Shutdown, what belongs there and what does not, and how it differs from Save Game and Subsystems.

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.

A single band running vertically through three level boxes, with the score riding on that band

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 InstanceCast To
  • When Init / Shutdown actually 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

Sponsored

Only Game Instance Survives

First, let's look at how long each container lives along a timeline.

A timeline from launch to quit where only the GameInstance band stretches end to end, while the Actor, Widget, GameMode, and PlayerState bands are cut off at each level
ContainerLifetimeOn level change
Game InstanceFrom app launch to app quitStays as-is
GameMode / GameStateFrom level start to level endRebuilt
PlayerStateSame as aboveRebuilt
Characters and placed ActorsSame as aboveDestroyed
WidgetFrom being added until destroyedDestroyed
Level Blueprint variablesOnly within that levelGone

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 .

The three steps: create a Blueprint Class in the Content Browser, pick GameInstance from ALL CLASSES, and register it as the Game Instance Class in Project Settings

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.

Sponsored

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.

Node graph running from Get Game Instance through Cast To BP_GameInstance into Set Total Score
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 .

A timeline of launch, Level A, Level B, and quit showing Init firing once at launch and Shutdown once at quit, with neither firing on level transitions
EventWhen it firesHow often
InitAt game launch. Before the first level is loadedExactly once
ShutdownWhen the game quitsExactly 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.

Sponsored

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.

Left: references to Actors and Widgets become None after a level change. Right: IDs and numbers survive intact
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 EnumA reference to a Component
Volume and key binding settingsCoordinates 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 InstanceSave Game
Where it livesMemoryA file on disk ( .sav )
LifetimeUntil the app closesUntil you delete it
Level transitionSurvivesSurvives
App restartGoneSurvives
Effort to read/writeJust touch the variablesPack 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.

Sponsored

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 InstanceGameInstance Subsystem
What it isOne place to keep things across levelsA mechanism for splitting by feature
How manyOne per projectAs many as you have features
CreationBlueprint only is enoughRequires C++
Getting itGet Game Instance → CastA dedicated Get node (no Cast)
LifetimeLaunch to quitSame

Decide in this order.

  1. Start with Game Instance. It's Blueprint-only and works as soon as you add one variable
  2. 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.

Flow showing 120 in Stage01, +80 to 200 in Stage02, +150 to 350 in Stage03, and the results screen reading TOTAL:350 CLEARED:3

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 nameWhat to place
L_Stage01One BP_StageGoal
L_Stage02One BP_StageGoal
L_Stage03One BP_StageGoal
L_ResultNothing

Variables on BP_GameInstance (parent class: GameInstance)

Variable nameTypeDefault value
TotalScoreInteger0
ClearedStagesName ( Array )(empty)

After creating it, set Edit > Project Settings > Project > Maps & Modes > Game Instance Class to BP_GameInstance .

BP_StageGoal (parent class: Actor)

ElementSetting
Box CollisionBox 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 inStageIDStageScoreNextLevel
L_Stage01Stage01120L_Stage02
L_Stage02Stage0280L_Stage03
L_Stage03Stage03150L_Result

Game Instance side: the ClearStage function

Create a new ClearStage function under Functions on BP_GameInstance and add two input pins.

Input pinType
StageIDName
ScoreInteger
Node graph of the ClearStage function: Add Unique appends to ClearedStages, Score is added to TotalScore, and the result is printed with Print String
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: 120TOTAL: 200TOTAL: 350
  • In L_Result , TOTAL: 350 and CLEARED: 3 display 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 → the IsTransitioning branch is missing and the overlap is running twice
  • CLEARED is greater than 3 → you're using Add instead of Add 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 NextLevel is 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: TotalScore is never Set directly from outside; it changes only through ClearStage . 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 Name and Integer . It's tempting to stuff "the goal Actors you cleared" into an array, but they'll all be None in 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.

Sponsored

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 TotalScore to 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 String at 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 InstanceCast To . Wiring a Print String to the Cast's failure pin catches a missing registration
  • Init fires 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 None in 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.