They are designed to store specific information, such as configurations, properties, or custom data, which can be accessed or modified by nodes or other systems. Resources can be saved as files (usually with the .tres extension for textual resources or .res for binary ones) and loaded into the project using ResourceLoader. This allows resources to be shared across scenes or even projects, as they are not tied to a specific scene and can be referenced by any node or script.
Advantages of using resources include:
- Modularity: Facilitates data reuse without duplication.
- Organization: Helps keep data separate from code or scenes.
- Flexibility: You can modify a resource and the changes will be reflected in all nodes that use it.
Godot comes with many predefined resources, but you can also create your own by extending the Resource class. For example, in a project I'm developing in Godot C#, I created the following resource:
![]() |
Custom Resource Example in Godot C# |
As you can see, it's straightforward. You just inherit from Resource and define the fields/properties you want the resource to have. What deserves special mention are the attributes.
As in any other Godot script, the [Export] attribute makes the decorated field editable in the inspector when the resource is used.
The [GlobalClass] attribute on line 7 is needed to make your custom resource available in the editor's search tool when you want to use it.
The [Tool] attribute is only necessary if you need to access the contents of your resources from code that runs in the editor (not just in the game).
This particular resource is used to create an array of them in another node and store links to other nodes present in the scene (that link is precisely the NodePath field). I could have added methods to the resource—nothing prevents you from doing so—for example, to validate the data stored in the resource, but in my case, it wasn’t necessary.
![]() |
Example of Using My Custom Resource |
When you click on each resource, it expands and you can view and edit its contents.
![]() |
Editing Resource Contents |
If you come from the Unity world, resources are equivalent to ScriptableObjects since they also allow saving their instances as assets in the project.
They also fill the role of Unity’s serializable classes. Although Godot C# has access to C#’s [Serializable] attribute, unlike Unity, Godot cannot display them in the inspector. Therefore, the alternative is to create a class that inherits from Resource with the fields you would have put in the serialized class in Unity. I have a Unity version of the entire example above, and there I solved it by making WeightedBehavior a serializable class.
Resources are ubiquitous in Godot—you’ll find them everywhere. For example, whenever you want to use an Area2D node to create a detection area, that node requires attaching another node of type CollisionShape2D to define the boundaries of the detection area.
![]() |
An Area2D Node Uses a CollisionShape2D Node to Define Its Area |
Interestingly, you can’t define the shape of the CollisionShape2D until you create a new resource in its Shape field.
![]() |
A CollisionShape2D Node with an Associated RectangleShape2D Resource |
This reflects Godot’s obsession with separating responsibilities. In this case, the CollisionShape2D node simply implements functionality in an area, but the shape of that area is stored in a resource (in this case, RectangleShape2D).
If you expand the combo box, you’ll see that RectangleShape2D is not the only resource you can associate with that field.
![]() |
Different Resources That Can Be Associated with the Shape Field |
If you’re familiar with Unity’s ScriptableObjects, you’ll intuit the usefulness of Godot’s resources. If not, you’ll realize it as you use the engine. Ultimately, you’ll likely model resources in your mind as “little boxes of data.”
One of the uses of these “little boxes” is that multiple nodes can read data from the same box instead of duplicating that data in each node. This is an efficiency measure that Godot follows by default, transparently to the user.
Usually, this is fine, but sometimes it can cause surprises if you’re not aware of this behavior. Here’s an example I just experienced firsthand.
In my project, I developed a cone sensor. It’s essentially a vision cone. The scene that makes up the sensor includes the following nodes:
![]() |
Nodes That Make Up My Sensor |
The earlier screenshots of CollisionShape2D were taken from this scene.
The general functionality is that the definition of the cone’s range and angle parameters (defined from another node) causes the BoxRangeManager node to resize the CollisionShape2D so that only objects within its area are detected. Then, a finer filtering is done by angle and distance, but the first “coarse” filtering is whether the detected object is inside the box.
![]() |
An Agent in My Project with the Sensor Added |
In the screenshot above, the blue box is the area of the RectangleShape2D. With just one agent, everything worked perfectly. The problem started when I added a second agent with another cone sensor.
![]() |
Example of a Problem When Instantiating Scenes with Resources |
To my surprise, the respective RectangleShape2D resources (note the italics) insisted on having the same size. When I changed the dimensions in one agent, both areas adopted that agent’s dimensions. When I changed them in the other agent, both areas adopted the new dimensions.
It took me a while to realize the problem. The issue was that there weren’t two independent RectangleShape2D resources. Since RectangleShape2D is a resource, all sensor instances were using and modifying the same resource. Hence the italics earlier—there weren’t “respective” RectangleShape2D resources, but a single one shared by both agents’ sensors.
How Do You Fix This? Are We Doomed to Use a Single Sensor Instance? Obviously not, but the solution isn’t immediately obvious.
The key is to go back to the CollisionShape2D node’s configuration and click on the RectangleShape2D resource to configure it internally.
![]() |
Internal Configuration of the RectangleShape2D Resource |
Inside that configuration, the Size field is obvious and corresponds to the resource’s dimensions. The key field is within the Resource section and is called Local To Scene. By default, it’s unchecked, meaning all instances of the current scene will share this resource. In other cases, this configuration might be beneficial, but in my case, it caused the problem I just described.
Therefore, the solution was to check the Local To Scene field. Doing so causes each scene instance to create its own copy of the resource and work with it. After checking it and saving the scene, both agents correctly displayed their respective (now truly) RectangleShape2D configurations.
![]() |
Problem Solved |
So be careful when using resources in your Godot scenes. Keep in mind that Godot’s default behavior is to share resources among different scene instances. Therefore, if you detect a case where instances need to customize the resource’s values, you should anticipate problems and check the Local To Scene option so that each instance has its own copy of the resource.
I hope this article helps you avoid problems like the one I had.