Skip to content

Folder Layout & res:// Paths

What you'll learn

  • The four top-level folders an idle/incremental project commits to early — scenes/, scripts/, resources/, assets/ — and what each one means.
  • What res:// actually resolves to, and why almost every path you type into Godot starts with it.
  • How the FileSystem dock relates to the folders on disk, and why those two views must stay in lockstep.
  • Why folder layout is a coordinate-system decision in the same way the stretch settings were — picked once, expensive to change later.

How it applies

  • Asset handoff with non-programmers. A sound designer handing you a folder of .wav clips needs to know where to drop them. "Put them in assets/audio/sfx/" is a one-line answer. Without a layout, every new asset arrives in the project root and you spend the rest of the session re-filing them by hand.
  • Bug triage by folder. When a QA report says "the upgrade panel shows the wrong icon," knowing the panel's scene lives under scenes/ui/ and the icon lives under assets/icons/upgrades/ cuts the file-search time. A flat project means scrolling a wall of files looking for the right .tres.
  • Diff readability in source control. git diff over a per-folder structure tells the reviewer at a glance what changed: a scenes/ui/ change is UI; a scripts/autoloads/ change is global state. A flat structure produces diff reports that all look the same — UI fixes, balance changes, save-system rewrites all blend together in code review.
  • Export filtering for shipped builds. Godot's export presets let you include or exclude folders. A assets/raw/ folder of source-quality art (50× larger than the in-game versions) can be excluded from the released build — but only if there is a folder boundary to exclude on. Flat projects ship every loose file.
  • Refactor blast radius. When you eventually rename a folder — and you will, mid-project — every res:// path that pointed inside it must update. Godot 4.6's UID system (uid://...) absorbs most of this for .tscn/.tres references, but raw text paths (signals connected to scripts, save-file path strings, exported variables holding paths) do not get UIDs. The fewer renames, the fewer manual fix-ups. Pick the folder names you can live with.
  • Onboarding the next person. Idle games are often hobby projects passed between collaborators. A predictable folder layout is the difference between a new contributor finding the click-button scene in 30 seconds and bouncing off the project after 20 minutes of cold reading.

Concepts

The FileSystem dock and res://

Every Godot project has a single root directory on disk — the directory containing project.godot. For our project, that is C:\Users\danyf\source\repos\godot-idle-learning\. The FileSystem dock, the panel in the bottom-left of the editor by default, is a live view of that directory. Files added on disk show up in the dock; files dragged in the dock get moved on disk.

Inside the engine, that root directory is referred to as res://. Any file path you type into Godot — a scene reference, a script reference, a sound clip path — starts with res:// and is interpreted relative to the project root. res://scenes/main.tscn is the file <project root>\scenes\main.tscn on disk. The engine never lets you reach files outside res:// from runtime code; the prefix is also a sandbox boundary.

There is also user://, which resolves to a per-OS user-data directory (something like %APPDATA%\Godot\app_userdata\Blood Knight Grove\ on Windows). That is for save files and runtime-written data. We will use it in M7.

Example

You write preload("res://scripts/autoloads/tick.gd") in a future script. The engine looks at the project root, descends into scripts/, then autoloads/, then loads tick.gd. If you move that file to scripts/systems/tick.gd later, every preload and load call referencing the old path silently fails at run time — no compile-time check catches it. The UID system covers .tscn and .tres references but does not cover preload calls against .gd files.

Example

A common confusion: the FileSystem dock and Windows Explorer are looking at the same files. If you open the project root in Explorer and create a folder called notes/ there, that folder shows up in the FileSystem dock the next time the editor refocuses. If you create the folder via the FileSystem dock instead, Windows Explorer sees it on the next refresh. They are two windows onto the same disk state — never out of sync for long.

The four top-level folders

For Blood Knight Grove and any other idle/incremental project, the project root grows four top-level folders early. Each one has a single purpose:

  • scenes/.tscn files. The composition trees of nodes that make up the game's screens, panels, rows, popups. Sub-folders by purpose: scenes/ui/ for menus and HUD, eventually scenes/buildings/ for per-generator scenes if those scale up.
  • scripts/.gd files. The behavior code attached to scenes, plus autoloads. Sub-folders: scripts/autoloads/ for global singletons, eventually scripts/systems/ for cross-cutting logic.
  • resources/.tres files. Custom data containers — your UpgradeData, BuildingData, etc. These are pure data, not scenes; they will drive the upgrade and building systems in M4 and M5. Sub-folders: resources/buildings/, resources/upgrades/.
  • assets/ — raw inputs the engine consumes: .png, .wav, .ogg, fonts, shaders. Sub-folders: assets/sprites/, assets/audio/sfx/, assets/audio/music/, assets/fonts/. The convention is "anything an artist or sound designer can drop in" lives here.

The discipline behind the split: scenes describe structure, scripts describe behavior, resources describe data, assets are raw inputs. When you cannot decide where a file goes, you almost always have not asked which of those four it is.

Example

A new .tres file containing the click upgrade's name, cost, and effect multiplier goes in resources/upgrades/click_power_1.tres. It is data — not a scene, not behavior, not raw asset input.

Example

A .gd script that defines the UpgradeData class (the schema for what fields any upgrade resource has) goes in scripts/upgrade_data.gd. The script is behavior + schema; the individual .tres files that conform to that schema are data. Putting the class definition under resources/ would be wrong — resources/ is for instances, not for the type itself.

Example

A new button click sound. The .wav file goes in assets/audio/sfx/click.wav. The Godot AudioStream asset that wraps it (auto-generated when the engine imports the file) lives alongside it. The scene that plays the sound — an AudioStreamPlayer node — is part of whatever UI scene needs the click, so it lives in scenes/ui/.

Folder layout as a coordinate system

In M1.1 you committed to a base resolution and stretch behavior. Every later anchor and font-size decision was calibrated against 1280×720. The folder layout is the same kind of commitment, on the file-system axis instead of the pixel axis.

Once you start writing preload("res://scripts/autoloads/tick.gd") in M3, that path string is hard-coded into the codebase. So is the .tres path the resource browser remembers when you assign an UpgradeData to a slot in the inspector. Renaming scripts/autoloads/ to scripts/globals/ later is a search-and-replace operation across every file that referenced the old name — and as noted, the UID system covers some references but not all of them. Picking the names you can live with at the start of M1 is the cheap version of this decision; picking them at the start of M5 is the expensive version.

This is also why the convention is conservative — scenes/, scripts/, resources/, assets/ are the names every Godot tutorial and template uses. Inventing your own (game_logic/, data_structures/, art/) makes your project harder to read for anyone with Godot experience, including future-you in six months.

Example

A project that starts with code/ for scripts and art/ for assets is internally consistent but reads as "non-standard" to anyone else. When you eventually pull a snippet from a Godot forum or paste a community plugin, both will assume scripts/ and assets/ exist. You will end up either renaming yours or maintaining two parallel conventions. The cost is small but real.

Sub-folder-as-you-go

The four top-level folders are committed to at the start. Sub-folders inside them are added as the project needs them. Right now M1 needs no sub-folders — scenes/main.tscn is the only file that will live anywhere, and it goes directly under scenes/. By M3 you will have scripts/autoloads/tick.gd, so scripts/autoloads/ is born. By M5 you may have a dozen BuildingData resources, so resources/buildings/ is born.

Do not pre-create empty sub-folders for files that do not exist yet. Empty folders read as forgotten work-in-progress; they bloat the FileSystem dock; they survive in git only if you remember to add a .gitkeep. Wait until the second file is about to land in a top-level folder, and then group the existing one into a sub-folder.

Example

M1 ends with exactly one scene: scenes/main.tscn. There is no scenes/ui/ folder yet, even though M1.4 will populate that scene with UI nodes. The folder is created in M2 when the second UI scene (the click button, broken out of Main) needs a home.

Walkthrough

You will perform these in your own Godot editor, with the godot-idle-learning project open.

  1. Locate the FileSystem dock. It is the panel in the bottom-left of the editor by default. The top entry is res://; expanding it shows the project root.
  2. Right-click on res:// in the FileSystem dock. From the context menu, choose New Folder…. A small modal opens with a text field.
  3. Type scenes (lowercase, no trailing slash) and press Enter. The folder appears under res://.
  4. Repeat steps 2–3 for scripts, resources, and assets. The FileSystem dock should now show four sibling folders under res://.
  5. Switch to Windows Explorer, navigate to the project root (C:\Users\danyf\source\repos\godot-idle-learning\), and confirm the four directories exist on disk. They should. (If they don't, you created them somewhere else — drag them into place in the FileSystem dock.)
  6. Back in the editor, do not create any sub-folders yet. There are no files to put in them.
  7. Save-state check: the four top-level folders are not yet committed to source control. They are also empty, which means git status shows no change — git only tracks files. This is fine. The first scene you save in M1.3 will land under scenes/, and that file will pull the folder along with it.

Optional sanity check. From the FileSystem dock, click on res://scenes to select it. The bottom of the dock shows the path as res://scenes. Now click on the folder in the main viewport area — there is no main-viewport effect because folders are not scenes. The dock is the only place the folder is visible inside the editor; that is normal.

Self-check quiz

Q1 — In Godot, what does the path res://scripts/autoloads/tick.gd actually resolve to on disk for this project?

A. The Godot engine's installation directory plus scripts/autoloads/tick.gd. B. The project root (the folder containing project.godot) plus scripts/autoloads/tick.gd. C. The user data directory (%APPDATA%\Godot\...) plus scripts/autoloads/tick.gd. D. The current working directory the engine was launched from, plus scripts/autoloads/tick.gd.

Reveal answer

B — the project root. res:// is always the directory containing project.godot, regardless of where the engine binary lives or how it was launched. A is wrong: the engine install dir is unrelated to user projects. C confuses res:// with user://, which is the per-user appdata path used for save files. D is what res:// would mean in a poorly-designed engine; Godot intentionally pins res:// to the project so that running the same project from a different shell produces the same paths.

Q2 — You finish writing the GDScript class that defines what fields every UpgradeData resource has. Where does that .gd file go?

A. resources/upgrades/upgrade_data.gd — it goes with the upgrade resources. B. scripts/upgrade_data.gd — it is behavior/schema code, even though instances of it live elsewhere. C. assets/upgrade_data.gd — it is a project asset. D. scenes/ui/upgrade_data.gd — the upgrade UI uses it most.

Reveal answer

B — scripts/upgrade_data.gd. The class definition is GDScript code; it goes under scripts/. The instances of that class — the individual .tres files for the click-power upgrade, the prestige upgrade, etc. — go under resources/upgrades/. A is the most common confusion: pure data files live with their kind, but the schema describing the data lives with the code. C is wrong because assets/ is for raw inputs (PNGs, WAVs, fonts) — not scripts. D conflates the script with the consumer; many UI scenes will reference UpgradeData, and putting the schema in any one of them would force the others to depend on UI code.

Q3 — At the end of M1, the project has exactly one scene file (scenes/main.tscn). Should you also create scenes/ui/, scripts/autoloads/, resources/upgrades/, and assets/sprites/ now to 'have them ready'?

A. Yes — pre-creating the full sub-folder tree gives the project a finished feel and prevents forgetting. B. Yes for scripts/autoloads/ (which the editor needs for autoload registration), no for the others. C. No — empty folders bloat the dock, are not tracked by git, and signal forgotten work-in-progress. Create each sub-folder when the second file is about to land in its parent. D. Only if you commit a .gitkeep in each so git does track them.

Reveal answer

C — create sub-folders only when there is something to put in them. The dock and git both stay clean. B is plausible-sounding but wrong: the autoload registration mechanism (Project Settings → Globals → Autoload) lets you point at any path; it does not require scripts/autoloads/ to pre-exist. D is a workaround for a problem that does not need solving — the .gitkeep convention exists for cases where an empty directory is a deliverable (e.g., a runtime cache directory), which does not apply here.

Integration question

Q4 — open

In M1.1 you committed to base resolution 1280×720 and Aspect = keep. In M1.2 you committed to four top-level folders. Both decisions are described in this textbook as coordinate-system commitments. What property do they share, and what is the cost of getting either of them wrong now versus later?

Reveal expected answer

Both decisions become the meaning of countless later expressions. The stretch settings define what every anchor numeric (anchor_top = 0.4) means in the player's window; the folder layout defines what every res:// path string means on disk. Once any later module starts referencing those values — anchors in M1.4, paths in M2.1 — every file that uses them is calibrated against the original choice. A late change to either requires re-checking every reference. Doing it now is a five-second decision; doing it after M5 is a multi-hour search-and-replace, with the additional risk that some references (string literals in save files, paths in comments) will be missed and silently break.

Glossary

Glossary

FileSystem dock
The editor panel (bottom-left by default) showing a live view of the project root directory. Files added on disk appear here; drags within the dock move files on disk.
res://
The path prefix that resolves to the project root (the directory containing project.godot). All in-game asset paths start with this. Sandboxed — runtime code cannot reach above it.
user://
The path prefix resolving to a per-OS user-data directory (e.g., %APPDATA%\Godot\app_userdata\Blood Knight Grove\ on Windows). For save files and any runtime-written data. Distinct from res://, which is read-only at runtime.
.tscn file
On-disk format of a Godot scene. Text-based, human-readable, diff-friendly. Stores a tree of nodes plus their properties. One scene per file.
.tres file
On-disk format of a Godot Resource. Text-based. Stores instances of any class extending Resource — typically custom data containers like UpgradeData, BuildingData. Pure data, not behavior.
.gd file
GDScript source file. Behavior code attached to nodes via the script slot, plus autoload globals.
autoload
Globally-available singleton configured in Project Settings → Globals → Autoload. Loaded once at game start, accessible from any scene by name (e.g., Tick.tick_rate). For cross-scene state and systems.
preload(...)
GDScript built-in that loads a resource at parse time (when the script is first compiled), not at runtime. Path is a string literal — fails silently if the target is renamed without updating the call. Distinct from load(), which runs at the call site.
UID system
Godot 4.x's stable-identifier indirection. Each .tscn/.tres gets a uid:// reference stored in a .uid sidecar file. Scene/resource references survive renames because the engine resolves the UID rather than the path. Does not cover .gd preload()s or string-literal paths.
### Ask Claude (side-channel) Try one of these in a Claude Code session if a piece did not land: - `Re-explain res:// using a non-game-engine analogy. Maybe how a web server resolves URL paths against a document root.` - `Show me a real Godot project's folder structure on GitHub and contrast it with the four-folder convention here.` - `What's the difference between res:// and user:// in one paragraph each?` - `Open the Godot 4.6 class reference for ResourceLoader and find the method that loads a file by uid:// path. How does it differ from loading by res:// path?`