[UE5] Blueprint Variables 101: Class Variables vs Local Variables

Created: 2025-12-12Last updated: 2026-07-19

Should a Blueprint variable be a Class Variable or a Local Variable? A visual breakdown by scope and lifetime, plus a hands-on section where you deliberately cause a loop accumulation bug and then fix it.

As a Blueprint grows, the Variables panel fills up until you can no longer tell which variables actually matter. The usual cause is creating Class Variables even for temporary calculation results .

Blueprints have two kinds of variables, with different lifetimes and different reach: Class Variables and Local Variables. Only one question decides between them: "is this state, or is this a work-in-progress value?" This article explains the difference between the two, then walks through deliberately causing and fixing the "call the function twice and the value doubles" bug.

A figure holding a large backpack and a small sticky note, representing the two kinds of variables

What You'll Learn

  • The two variable types differ in scope (how far they reach) and lifetime
  • The rule of thumb: state goes in Class, intermediate values go in Local
  • Local Variables can only be created inside a Function (not in the Event Graph)
  • Hands-on: deliberately cause and fix the "doubles on the second call" bug

Sponsored

Two Variable Types: Scope and Lifetime

A Blueprint variable behaves completely differently depending on where you create it.

  1. Class Variables (member variables): the regular variables you create in the "Variables" section of the My Blueprint panel
  2. Local Variables: variables you can only create inside a Function . The "Local Variables" section appears in the My Blueprint panel only while a function is open

The differences fall along two axes. The first is scope (where it can be reached from) .

A Class Variable is reachable from any logic, while a Local Variable stays inside the function. Narrower reach means safer
Class VariableLocal Variable
ScopeReadable and writable from every function and event in the Blueprint (and from outside if set to Public)Only inside the function that defines it. Completely invisible from outside
LifetimeFrom instance creation to destructionFrom the start of the function to its end
Typical useAn object's state , settings, referencesTemporary calculation results , intermediate data

The second axis is lifetime (how long it lives) .

A Class Variable lives from spawn to destruction, while a Local Variable appears only while the function runs and then disappears

A Class Variable keeps its value for as long as the actor is alive. A Local Variable is born the moment the function is called and vanishes without a trace when the function ends. That "disappears immediately" property is the key to the bug prevention we cover below.

Important note: Local Variables can only be defined inside a Function. You cannot create them in the Event Graph. If you find yourself wanting a temporary value in the Event Graph, that's a sign the logic should be extracted into a Function (see Function vs Macro).

Sponsored

The Rule: State in Class, Intermediate Values in Local

The guiding principle is minimizing scope . The narrower a variable's reach, the safer it is.

State and settings (health, flags, config values) go in Class Variables, while intermediate calculations go in Local Variables

What Belongs in a Class Variable: An Object's "State"

Think about a player's CurrentHP, MaxHP, and IsDead. They go down on a damage event, go up in a heal function, and get read by the UI update. In other words, they are "current state" that multiple pieces of logic reference and update . That's exactly what Class Variables are for.

Event ReceiveDamage
  → Subtract Damage from CurrentHP (Class Variable) and Set
  → If CurrentHP <= 0 → Set IsDead (Class Variable) to True

What Belongs in a Local Variable: Intermediate Values Contained in a Function

Now consider the "base damage × buff multiplier" intermediate result inside a damage calculation function. That value is only needed for the few milliseconds the calculation takes . Nobody outside the function needs to know it. That's what Local Variables are for.

Function: CalculateFinalDamage (Return Value: Float)
  → Set the result of BaseDamage × BuffMultiplier into Local Variable: IntermediateDamage
  → Return IntermediateDamage × CriticalMultiplier as the Return Value

When the function ends, IntermediateDamage is gone. It never clutters the Variables panel and never affects anything else.

Sponsored

What Happens When Everything Is a Class Variable

The mine beginners step on most often is making even temporary calculation results into Class Variables. There are three main problems.

  • A bloated variable list: the state variables that actually matter get buried under a pile of throwaway variables
  • Debugging becomes a maze: when a variable can be written from anywhere, the suspect list for "why did this value change?" is every piece of logic in the Blueprint. With a Local Variable the only suspect is that one function, so the search narrows instantly (see Debugging with Print String)
  • Leftover value bugs: this is the biggest trap. A Class Variable remembers its previous value . Let's step on it for real in the next section
Sponsored

Hands-On: Causing and Fixing the "Doubles on the Second Call" Bug

Total score in an RPG, combo tallies in a shmup, total carry weight in an inventory. "Loop over an array and sum it up" shows up in every genre. It is also the clearest possible teaching example of what goes wrong when you pick the wrong kind of variable. This time we'll get it wrong on purpose, witness the bug, and then fix it .

The first call correctly returns 300, but the second returns 600 because the Class variable still holds the previous value

Setting up the repro. In any Actor Blueprint (BP_ScoreTester, for example), create the following variables.

Variable NameTypeDefault ValueWhere It Lives
ScoreArrayInteger array100, 100, 100Variables panel (Class Variable)
TotalScoreInteger0Variables panel (this is the deliberately wrong place)
  1. Build the deliberately wrong function: create the Function CalculateTotalScore (return value: Total / Integer) and wire it like this

    Function: CalculateTotalScore (Return Value: Total / Integer)
      → For Each Loop (Array: ScoreArray)
          Loop Body → Set TotalScore (= Add (A: TotalScore, B: Array Element))
          Completed → Return Node (Total ← TotalScore)
    
  2. Call it twice and watch: in the Event Graph, call it twice in a row

    Event BeginPlay
      → CalculateTotalScore → Print String (Append("1st: ", ToString(Total)))
      → CalculateTotalScore → Print String (Append("2nd: ", ToString(Total)))
    

    Hit Play and you get 1st: 300. Correct. But then 2nd: 600. The array hasn't changed at all, yet the total doubled

  3. Name the culprit: because TotalScore is a Class Variable, the 300 from the first call survived the end of the function , and the second call's additions piled on top of it

  4. Fix it: delete TotalScore from the Variables panel, then with CalculateTotalScore open, create RunningTotal (Integer) under Local Variables in the My Blueprint panel. All you do is swap it in

    Function: CalculateTotalScore (Return Value: Total / Integer)
      → For Each Loop (Array: ScoreArray)
          Loop Body → Set RunningTotal (= Add (A: RunningTotal, B: Array Element))  ← changed to Local
          Completed → Return Node (Total ← RunningTotal)
    

    Hit Play and you get 1st: 300 / 2nd: 300. It stays 300 no matter how many times you call it, because a Local Variable starts from a clean 0 on every call

    The only thing that changed in the graph is where the variable lives. That alone changes the result.

    Side-by-side node graph comparison of the broken version (Class variable, 600 on the second call) and the fixed version (Local variable, 300 on the second call)
A Local Variable is a fresh notepad every time, a Class Variable is a notepad that still has last time's numbers on it. Loop totals belong on the fresh notepad

Some of you are thinking "couldn't I just add a reset node and keep the Class Variable?" You're right, setting it to 0 at the top of the function works. But that also means signing up to manage "variables that need resetting every time" yourself, forever. With a Local Variable, the reset is guaranteed by the system. Relying on the mechanism rather than on human attention is the shortcut to Blueprints with fewer bugs.

Two things to take away.

  • Ask yourself "do I still need this value after the function ends?": if the answer is no, go Local without hesitating. That single question sorts about 90% of your variables correctly
  • Learn to infer the culprit from the symptom: "the value is wrong starting from the second time," "the previous run's state was still there after I retried." When you see those symptoms, suspect a leftover Class Variable first. This instinct keeps paying off

Bonus: Good to Know for Later

  • Function Input/Output pins are in the same family: use Input pins to pass values into a function and the Return node to pass them back. Passing values through arguments and return values is the cleanest style of all, and it often removes the need for Local Variables entirely. Local Variables fit best for intermediate values you reuse several times inside a function
  • Class Variables have organization tools: once you have a lot of variables, you can group them with Category in the Details panel. Sorting them into Stats, Config, and so on makes the Variables panel much easier to scan
  • If you want different values per instance: turn on Instance Editable on a Class Variable and you can change the value per placed instance in the Details panel. That's how you get "same enemy Blueprint, but this one has extra HP"

Summary: A Variable Selection Checklist

QuestionIf YES
Does it hold an object's state or settings? (HP, flags, references)Class Variable
Is it referenced from multiple functions or events?Class Variable
Is the value still needed after the logic finishes?Class Variable
Is it temporary data used only inside one function?Local Variable
Can it be thrown away once the logic finishes?Local Variable

The phrase to remember: state goes in Class Variables, process goes in Local Variables . Just making this call every time you create a variable will visibly improve how readable and bug-resistant your Blueprints are.

After variables comes organizing your logic. Pick up the skill of extracting logic into functions in Function vs Macro, and learn to tidy up whole graphs in 10 Techniques for Organizing Blueprint Graphs.

Scroll through your own Blueprint's Variables panel right now. How many "values you don't need once the function ends" are hiding in there?