~5 min read

Building and optimization

Export Presets, Profiler, the web target and WASM, a release checklist.

In Godot a build is an Export Preset (a per-platform config) + an Export Template (the engine binary without the editor). First-party platforms: Windows, macOS, Linux, Android, iOS, Web, visionOS (since 4.5).

Export Presets

Project → Export opens a window with the configs. Add a preset for the platform you need:

  • Platform (Windows Desktop, Android, Web, …).
  • Bundle Identifier / Package Name (for mobile/Mac/iOS).
  • Icon and Splash.
  • Permissions (Android — camera, location, etc.).
  • Encryption — encrypt the pack file.
  • Export Mode — All resources / Resources from group / By files.
  • Debug / Release — release produces an optimized build without the debugger.

Export Templates

These are the engine binaries for all target platforms (without the editor). Download them via Editor → Manage Export Templates → Download. Once per editor version (~1 GB).

Then on Export Project Godot assembles: your resources + the template = the finished game.

Platform specifics

Windows / macOS / Linux

  • Windows.exe. Sign it with signtool.exe (options in the preset’s Inspector).
  • macOS.app (or .dmg with automatic packaging). Notarization via an Apple Developer account for a silent launch. Requires a Mac for signing; cross-compilation is theoretically possible.
  • Linux.x86_64. PIE/non-PIE options for compatibility.

Android

  • Android SDK + JDK — you need to install them and set the paths in Editor Settings → Export → Android.
  • APK / AAB — chosen by the preset.
  • 16 KB page size — supported since 4.5 (a Google Play requirement as of November 1, 2025).
  • Architecturesarm64-v8a + x86_64 for emulators.

iOS

  • Requires a Mac + Xcode.
  • Export creates an Xcode project — you open it in Xcode, build it, and ship from there.
  • Signing and provisioning profile — standard, via an Apple Developer account.

Web (HTML5)

This is one of the trickiest targets. Specifics:

  • The Compatibility renderer is mandatory. Forward+/Mobile on WebGL2 are experimental.
  • Threading in WASM requires Cross-Origin Isolation: server headers:
    Cross-Origin-Opener-Policy: same-origin
    Cross-Origin-Embedder-Policy: require-corp
  • As of Godot 4.2/4.3 there is a single-threaded export (without SharedArrayBuffer). It works everywhere, including on default hosting (itch.io, S3). Enabled with the “Threads” → Off checkbox.
  • C# does not export to the web — an open issue, in progress.
  • Bundle size: an empty project is ~25 MB (after Brotli), real games are 50–150 MB.

The output of a web export:

index.html        ← the launch page
index.js          ← the JS loader
index.wasm        ← the engine and your code
index.pck         ← the packed assets
index.icon.png

Serve it through any web server.

PWA mode injects COOP/COEP

If you enable “PWA → Enabled” in the preset, Godot generates a Service Worker that injects the COOP/COEP headers. Then threads will work even on hosting that doesn’t support these headers (itch.io, GitHub Pages).

Profiler

Debugger → at the bottom of the editor → tabs:

  • Profiler — the CPU profiler. Enable it → run the game → it collects data. Shows the time spent in each method and node.
  • Visual Profiler — the GPU profiler. The time of each render pass.
  • Network Profiler — for multiplayer.
  • Monitors — real-time metric graphs: FPS, draw calls, objects, memory, video memory.
  • Remote Scene Tree — the live node tree of the running game; you can inspect values.

Frame budget

  • 60 FPS = 16.6 ms
  • 30 FPS = 33.3 ms
  • 120 FPS = 8.3 ms
  • VR 90 FPS = 11.1 ms, with no room for drops

A breakdown in a typical 3D scene:

  • 2–4 ms — rendering on the GPU.
  • 2–6 ms — physics + your scripts on the CPU.
  • The rest — buffer, VSync.

Main optimizations

Texture compression

In the Import dock for each texture — Compress Mode:

  • VRAM Compressed — for runtime (BCn for PC, ASTC for Android/iOS).
  • VRAM Uncompressed — uncompressed.
  • Basis Universal — cross-platform via super-compression, transcoded to the GPU target.
  • Lossless — PNG.

VRAM Compressed is mandatory for most projects; it saves video memory and draw time.

LOD — Level of Detail

Unlike Unity’s LODGroup, Godot applies mesh-level LOD automatically if a mesh contains several detail levels (generated at import time when “Generate LODs” is enabled). MeshInstance3D has a mesh_lod_threshold property (the px on screen at which to switch).

Occlusion Culling

Godot supports OccluderInstance3D — occluder nodes (static geometry) that tell the renderer “nothing is visible behind this wall.” Baked via Bake Occluders in the editor.

Static Lighting

Baking light with LightmapGI removes the realtime cost for static geometry. See the chapter on lighting.

Fewer draw calls — MultiMesh

For repeating objects (grass, props) use MultiMeshInstance3D — it renders N instances with a single draw call. The analog of Unity GPU Instancing.

Profiling GDScript

  • Static typing gives a 28–59% speedup on hot code. Use var x: int instead of just var x.
  • Every $Name access is a get_node, which isn’t free. Cache it in @onready.
  • Signals are cheaper than polling: instead of checking if hp != last_hp: every frame, emit a signal on change.

Release checklist

  • The profiler shows a stable 60 FPS on the target device.
  • Memory doesn’t grow over a long gameplay session (no leaks, Resource Monitor is stable).
  • Textures are compressed (VRAM Compressed), not raw PNGs.
  • LOD on heavy models.
  • Occlusion baked for interiors.
  • Lightmaps baked for static scenes.
  • Project Settings → Application: version, icon, splash configured.
  • The build is tested on the target device (not just on dev).
  • Print statements / debug code cleaned up or wrapped in if OS.is_debug_build().
  • The Settings menu (volume, graphics, keys) is saved via ConfigFile or user://.
  • For the web — the COOP/COEP headers or a single-threaded build are verified.
user:// — a sandbox for saves

Files in user:// go to a special location (Roaming AppData / Library / .local) for save files and user settings. Don’t write to res:// at runtime — it’s read-only after the build.


That wraps up the main section on 3D development in Godot. Next — a glossary of terms with web analogs and parallels to Unity.