Organizing files in Godot
Thu Oct 03 2024
When you first start a project, file organization isn't really an issue. With a handful of files, you don't even need subfolders where to put them. Then the project grows, and it gets increasingly difficult to find your way around it.
It's easier if you have a system. Then you can find things where you expect them to be. And in this article, I want to share my system with you.
Structuring by type
I'll start with an example. A Godot project usually consists of files of multiple types, like scripts, sprites, and scenes, so one obvious way is to group them by their type:
.
├── scenes/
│ ├── player.tscn
│ └── enemy.tscn
├── scripts/
│ ├── player.gd
│ └── enemy.gd
└── sprites/
├── player.png
└── enemy.png
This does the job just fine, and I have seen this way of organizing project files many times, but, personally, I don't like it. This simple example makes it easy to reason about what the role of each file is, but as soon as you start adding files with generic names like head.png
, it starts to become hard to understand where things belong. Of course, you can be strict about your naming conventions and, for example, systematically prefix sprite names to further describe what they belong to, e.g., zombie_head.png
. Also, if you decide that the game no longer needs zombies, you need to go and hunt for all the related files in the separate scripts
, sprites
and scenes
subfolders.
Structuring by entity
My original background is web development. In modern web development projects, files related to a particular entity (the web people call them "components") are grouped together. So, after restructuring our sample files using this entity-based structuring paradigm, I'd end up with a structure like this:
.
├── enemy/
│ ├── enemy.gd
│ ├── enemy.png
│ └── enemy.tscn
└── player/
├── player.gd
├── player.png
└── player.tscn
You can disagree, but I think that this is an improvement. Everything that belongs to the player entity is stored in the player
subfolder. Everything that belongs to the enemy is in the enemy
subfolder. If we decide that our game won't be violent, we can just remove the enemy entity and all its related assets by deleting the enemy
subfolder from the project.
If we want to add this enemy as part of an expansion to our game or a DLC, it's easier to split it from the main game's content when exporting and then supply it as a separate "pck" download.
Of course, it's perfectly fine to categorize assets in their subfolders, which you can very well split by type:
.
└── player/
├── player.gd
├── player.tscn
├── sounds/
│ ├── attack.wav
│ └── footstep.wav
└── sprites/
├── body.png
├── head.png
└── legs.png
Also, you absolutely don't have to restrict yourself to the depth of a single folder, but create a hierarchy of folders representing sub-entities of your entities in more complex cases:
.
└── player/
├── player.gd
├── player.tscn
├── armor/
│ ├── armor_list.res
│ ├── sprites/
│ │ ├── tier1.png
│ │ ├── tier2.png
│ │ └── tier3.png
│ └── shaders/
│ ├── magic.gdshader
│ └── frost.gdshader
└── weapons/
├── weapon_list.res
├── hammer/
│ ├── hammer.gd
│ └── hammer.png
└── sword/
├── sword.gd
└── sword.png
The "shared" folder
This is a good point to ask—what if I want to reuse stuff like weapons or shaders? This is where I use the shared
folder. Now, the shared
folder is a bit of a Wild West. Most of the things are organized by type; for example, little utility scripts meant for reuse have nowhere else to go other than a lone scripts
folder, but there might also be reusable entities like UI components. That might result in a structure like this:
.
├── player/
│ └── ...
├── enemy/
│ └── ...
└── shared/
├── ambiences/
│ ├── forest.ogg
│ └── cave.ogg
├── fonts/
│ ├── heading.ttf
│ └── body.ttf
├── scripts/
│ ├── utils.gd
│ └── state_machine.gd
├── sounds/
│ ├── footstep.wav
│ └── burning.wav
├── themes/
│ └── default.theme
├── ui/
│ ├── button/
│ │ ├── button.gd
│ │ ├── button.tscn
│ │ ├── click.wav
│ │ └── select.wav
│ ├── panel/
│ │ ├── panel.stylebox
│ │ └── panel_alt.stylebox
│ └── popup/
│ ├── popup.gd
│ └── popup.tscn
└── world/
└── door/
├── door.gd
├── door.tscn
└── door.png
There are no hard rules regarding the shared
folder, as I mentioned before, just that all things that should be reused go in there. Of course there's nuance. For instance, you could argue that the ui
folder doesn't really need to be in the shared
folder, but you can build many things just by composing panels and buttons for a HUD, and I'd put the HUD in a hud
folder at the project root. I did mention before that I don't restrict myself to the depth of one subfolder, but also I try to take care not to create a deep hierarchy of subfolders, which is hard to navigate. Then again, if you notice that you have been creating folders with equal postfixes, like pause_menu
, main_menu
and so on, it's probably a good idea to create a menus
folder, drop the _menu
postfix, and put those folders in there.
Another rule I have is that once a resource or scene needs to be reused and is therefore "promoted" to the shared
folder, it doesn't get moved out of it, unless I am certain that not more than one resource or scene depends on it, and then I can move the shared resource alongside that resource.
A more complete example
I've shared two of the basic building blocks in the structure of my Godot projects, and now I want to show a more complete example. We'll take an RPG game as our use case:
.
├── export_templates
├── src/
│ ├── acts/
│ │ ├── 01_moor/
│ │ │ ├── enemies/
│ │ │ │ ├── demon/
│ │ │ │ │ ├── demon.gd
│ │ │ │ │ ├── demon.png
│ │ │ │ │ ├── demon.tscn
│ │ │ │ │ ├── demon_attack.wav
│ │ │ │ │ └── ...
│ │ │ │ ├── shaman/
│ │ │ │ │ └── ...
│ │ │ │ └── zombie/
│ │ │ │ └── ...
│ │ │ ├── npc/
│ │ │ │ ├── blacksmith/
│ │ │ │ │ ├── blacksmith.gd
│ │ │ │ │ └── blacksmith.tscn
│ │ │ │ └── ...
│ │ │ ├── moor.gd
│ │ │ ├── moor.tscn
│ │ │ └── quests.res
│ │ ├── 02_desert/
│ │ │ └── ...
│ │ ├── 03_jungle/
│ │ │ └── ...
│ │ └── 04_heat/
│ │ └── ...
│ ├── addons/
│ │ ├── dialogic
│ │ ├── gdUnit4
│ │ └── ...
│ ├── autoload/
│ │ ├── storage_manager.gd
│ │ ├── quest_manager.gd
│ │ └── ...
│ ├── characters/
│ │ ├── warrior/
│ │ │ └── ...
│ │ ├── holy_warrior/
│ │ │ └── ...
│ │ ├── wizardress
│ │ └── ...
│ ├── script_templates/
│ │ └── node2d/
│ │ └── npc.gd
│ ├── shared/
│ │ ├── items/
│ │ │ └── ...
│ │ ├── weapons/
│ │ │ └── ...
│ │ └── ...
│ ├── ui/
│ │ └── ...
│ └── project.godot
├── storefront_assets
├── scripts
├── .gitignore
├── README.md
└── ...other non-godot related files
I might have gotten carried away a little here (this is still a very incomplete list), so let's stop and break this stuff down, starting with the top-most folder.
The src
folder contains the actual Godot project itself. It's a very common practice not to keep the project sources in the topmost folder. That allows the rest of the folder to contain files that aren't directly related to the Godot project. Even though Godot won't import unsupported files, I think it's just nicer that the stuff we don't need for the game directly is outside of the game folder. For example:
README.md
is a document that contains some basic information for future me and for potential collaborators about what the game is, what version of Godot it requires, and which version, as well as any additional information to get the thing going.storefront_assets
can contain any media, like screenshots, for the particular storefront where I distribute the game, e.g., Steam or itch.io.- I can put various little non-gdscript utilities in
scripts
, intended for some data manipulation or other purposes.
The .gitignore
is there so that no unnecessary junk pollutes my git repository. I keep every single experiment and prototype in git. You never know when you might need some code you wrote on a productive Sunday afternoon months ago. In case you were wondering, the .gitignore
for Godot 4 is very simple:
.godot/
*.translation
Now let's delve into the src
folder, the Godot project. Overall, you can see the entity-based folder structure I outlined earlier. The same applies for the given shared
folder. Since all classes in Diablo 2 this hypothetical RPG game share weapons and items (we'll conveniently ignore class-specific stuff), they are good candidates to go in the shared
folder.
I went with the acts
folder as a more complete example of the hierarchy I usually have in mind when I create a folder structure. The acts themselves are prefixed with a number so future me or a teammate knows the order they are played in, and this order will also be reflected when these folders are sorted by name ascendingly (which is the default in the FileSystem tab of Godot's editor). The act itself contains folders for the enemies and NPCs the player encounters, as well as a script and a scene file for the respective act. Maybe the act won't even require a script file because it will be assembled from various reusable components located in the shared
folder. An obvious omission for brevity's sake are the various assets each act requires.
Continuing, we have the addons
folder, which, as you probably already know, is the home of 3rd party plugins for the Godot engine. Both "dialogic" and "gdUnit4" are addons I like using a lot.
Next up, we have the autoloads
folder. These are all folders that are added as Autoloads in my "Project Settings". So, all kinds of manager singletons, global constants, maybe a signal bus, that kind of stuff.
The characters
folder has all the playable classes a player can pick. As they have little in common between themselves, they exist outside of the shared
folder. This folder could also be stored inside a player
folder, because there's definitely more that belongs to the "player" entity than just character classes, but as long as I can, I try to keep a flatter folder structure.
The script_templates
folder is where you can store templates for scripts. These appear as a selection in the "Attach Node Script" dialog. This allows you to easily create similar scripts for, let's say, NPC behavior without having to setup the boilerplate every time. You can read more about them in Godot's documentation.
I did outline the shared
folder earlier, so we got that out of the way.
And last, but not least, we have the ui
folder. It would basically be a hierarchy of scenes for conversation dialogs, the inventory, and other screens, composed out of UI components found in a hypothetical shared/ui
folder. In a scenario where you'd have class-specific UIs, like in Starcraft, where each race has its own HUD style, I'd put that in the characters
folder I mentioned earlier and would reserve the top-level ui
folder for more generic things like a main menu.
Conclusion
If you've reached this point in the article, thank you for reading! I've been wanting to write this for a while now. I think it's a fun exercise to try and formalize something as trivial as putting files into folders into some form of theory.
I want to give a shoutout to @pyxus. We talked about project structuring a while ago someplace on Discord, and they showed me a Notion document they were keeping that had a documented style guide for a Godot project structure. That, essentially, planted the seed for this article. I also got the opportunity to think about this stuff before starting to work on The Rise of the Golden Idol and that game's folder structure also loosely adheres to the principles outlined here.
I hope this will give you some ideas on how you can improve the way you structure your Godot projects. If you want to chat about files, let me know on X or mastodon!
UPDATE: After I posted the article, @njamster, pointed out to me that his approach is kinda similar to mine. I'd say it's even better, considering it's so simple to explain that it fits in a mastodon post!