Unreal Engine·Unreal Data Table

UE5 Data Tables: Create and Read Rows in Blueprint and C++

Learn how to use Data Tables in Unreal Engine 5 to store and manage game data. Step-by-step guide covering setup, row structs, and querying data at runtime.

Unreal has several tools for storing game data. A Data Table stores it in rows with the same structure, so we can edit the values and look them up when needed.

Let’s create a table, add some data and read it from Blueprint and C++.

What Are Data Tables in Unreal Engine?

You can think of a Data Table as a spreadsheet. Each row represents an object or an entry, and the columns hold its properties. This works for game settings, level layouts, character stats and other data that fits a table.

Unreal also has other assets like Data Assets, but we may check that out in another article in the future.

Create a Data Table Row Struct with FTableRowBase

Before you can create a Data Table you need a row struct: a struct that describes the columns. Every row in the table is one instance of this struct, and every property on the struct becomes a column.

The only hard requirement is that the struct inherits from FTableRowBase. Here is a small one for an item table:

USTRUCT(BlueprintType)
struct FItemTableRow : public FTableRowBase
{
    GENERATED_BODY()

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    FText DisplayName;

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    int32 Cost = 0;

    UPROPERTY(EditAnywhere, BlueprintReadWrite)
    float Weight = 0.f;
};

BlueprintType lets you use the struct, and the rows you read from it, in Blueprint. Once the struct compiles, Unreal offers it in the row-structure list when you create the Data Table.

If you only work in Blueprint you can build the same thing with a Blueprint Structure asset ( right-click in the Content Browser, Blueprint > Structure ). A Data Table will accept it as a row type the same way.

How to Create a Data Table Asset in UE5

To create a new Data Table in Unreal Engine, right-click in the Content Browser and select “Data Table” from the “Miscellaneous” section of the context menu.

Unreal will ask you to pick a Row Structure. This is where your row struct comes in: choose the struct you defined above ( or a Blueprint Structure ), and the table takes its columns from that struct.

Double-click the asset to open the Data Table Editor. Here you edit rows. To add a “Mana” or “Defense” column, add that property to the row struct and recompile; columns can not be added in the table editor.

How to Add and Edit Rows in a Data Table

Click Add Row in the Data Table Editor for each entry you want to store. For a character stats table, you could add one row per character and fill its columns with that character’s stats.

Import a Data Table from CSV or JSON

You can also skip manual entry and import the whole table from a CSV or JSON file, which is handy when a designer keeps the data in a spreadsheet.

For a CSV, the first column is the row name. Its header can be Name ( or left as --- ), and every other column header has to match a property name on your row struct, spelled the same way. A file for the item struct above would look like this:

Name,DisplayName,Cost,Weight
Sword,Iron Sword,120,3.5
Shield,Wooden Shield,60,5.0

JSON works too, as an array of objects where each object has a Name field plus the struct properties:

[
    { "Name": "Sword", "DisplayName": "Iron Sword", "Cost": 120, "Weight": 3.5 },
    { "Name": "Shield", "DisplayName": "Wooden Shield", "Cost": 60, "Weight": 5.0 }
]

To bring a file in, right-click in the Content Browser and choose Import, or use Reimport on an existing Data Table to pull in updated data while keeping the same asset. If a column name in the file doesn’t match a struct property, Unreal skips it and warns you in the Message Log, so check there when a column comes in empty.

Get Data Table Row in Blueprint

In Blueprint the node you want is Get Data Table Row. You give it the Data Table and a Row Name, and you get back two things: an exec output that splits into Row Found and Row Not Found, and an Out Row output.

The Out Row is a wildcard that resolves to your row struct once you pick the table, so you drag off it and Break the struct to read the fields ( DisplayName, Cost, Weight ).

The Row Not Found branch matters. If the row name is wrong you get an invalid row and no error, so wire up that path instead of assuming the lookup worked.

Two related nodes are handy: Get Data Table Row Names to loop over every row, and Does Data Table Row Exist when you only need to check for a name.

Read Data Table Rows in C++ with FindRow and GetAllRows

To read the table from C++, first load it into memory. One way is to store it in a class property, though you can load it however your project needs.

UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta=(RowType ="QuodComboData"))
UDataTable* ComboDataTable;

Once loaded, we can look up an entry by its row name, as we did with Get Data Table Row in Blueprint. For a character stats table, that might be the character’s name or ID. Here is a lookup from an attack table:

// Get the datatable asset from where you store it
const UDataTable* ComboDataTable = UQuodDynamicAssetLoaderGlobals::GetAssetByName(GetOwner(), AttackDataTableName);

// Find a specific row in the datatable
const FQuodAttackData * attackDataEntry = ComboDataTable->FindRow(TEXT("Attack01"), TEXT("UQuodAttackDataComponent::GetAttackData"));

// Get all rows if you need them all
TArray AllRows;
ComboDataTable->GetAllRows(TEXT("UQuodComboUtils::GetAttackData"), AllRows);

The returned row uses the struct type the table was created with.

FindRow is a template, so in your own code you pass the row type explicitly, like ComboDataTable->FindRow<FItemTableRow>("Sword", Context). It returns a pointer to the row, or nullptr if the name isn’t there, so null-check it before you use it. The second argument is a context string that shows up in the log when a lookup fails, which makes a missing row much easier to track down. GetAllRows takes the same row type and fills an array of pointers.

Under the hood the lookup is a map keyed by the row name, so FindRow is fast even on a big table. It stays fast as long as the names line up, which is the thing that usually goes wrong.

Missing Rows and Changes to the Row Struct

When a table lookup does not give the result you expect, check these:

  • Check the row name first. Lookups use FName; a typo returns nothing, without a crash or red error.
  • Changing the row struct invalidates data. Renaming a property, changing a type, or reordering fields can drop or reset values in every table built on that struct. After a struct change, open the affected tables and reimport or re-check them, and keep the source CSV or JSON so you can reimport cleanly.
  • Names come from the file on import. When you import a CSV or JSON, the row names come from the Name column, so a rename in the spreadsheet creates a new row instead of renaming the old one, and reimporting can leave stale rows behind.
  • Data Tables are static, read-only data. Treat a Data Table as constant at runtime. You look data up from it, you don’t write back to it, so use it for definitions ( item stats, combo data, level layouts ), not for save state.

For data composed from several sources or loaded on demand, Data Assets, Composite Data Tables and the Data Registry are other options. I have kept this post to Data Tables. Async loading and soft references also need consideration once a table gets large.

Recap

  • A Data Table’s columns come from a row struct that inherits from FTableRowBase. You can’t add columns in the table editor, you change the struct.
  • Read a row with Get Data Table Row in Blueprint or FindRow in C++. Both are keyed by the row name, and both fail quietly when the name is wrong, so always handle the not-found case.
  • Import from CSV or JSON with Name as the first column, and keep the source file so you can reimport after a struct change.

Keep reading

Dashes and Knockbacks with Root Motion Sources

Dashes and Knockbacks with Root Motion Sources

No root motion in the clip. The task builds the motion from plain numbers and hands it to the movement component, the animation is just cosmetic.
PlayMontageAndWait in GAS: Montage Replication

PlayMontageAndWait in GAS: Montage Replication

Montage_Play works on your screen and nowhere else. The ASC is the one that tells everybody else.
How Enemies Decide to Dodge

How Enemies Decide to Dodge

Dodge chance is a GAS attribute, pressure is a stacking effect on top of it, and the AI simply rolls dice.