Migrating from Godot 3 to Godot 4

Opening a Godot 3 project in Godot 4 offers to convert it (back up first!).

41.1 The converter

Opening a Godot 3 project in Godot 4 offers to convert it (back up first!). It can also be run from the command line:

The converter renames most classes, methods, properties, and syntax, but always requires manual cleanup. Migrating from 3.x to the latest 4.x stable is easiest via the newest 4.x release.

godot --path ./old_project --convert-3to4          # convert
godot --path ./old_project --validate-conversion-3to4   # dry run

41.2 Common renames

Spatial, MeshInstance, Camera Node3D, MeshInstance3D, Camera3D Node2D with y_sort_enabled Navigation2D + get_simple_path()

NavigationServer2D, NavigationAgent2D TileMap (4.0–4.2), then TileMapLayer (4.3+) PoolStringArray, PoolVector2Array

PackedStringArray, PackedVector2Array File, Directory FileAccess, DirAccess rand_range(), stepify() randf_range(), snapped() deg2rad(), rad2deg() deg_to_rad(), rad_to_deg() update() (CanvasItem) rect_position, rect_size (Control) position, size JSON.print() / JSON.parse()

JSON.stringify() / JSON.parse_string()

41.3 Syntax changes

export(int) var x @export var x: int export(int, 0, 10) var x @export_range(0, 10) var x: int onready var x = $X @onready var x = $X var x setget set_x, get_x var x: set = set_x, get = get_x yield(timer, "timeout") await timer.timeout

connect("sig", self, "_on_sig", [arg]) emit_signal("sig", a) .method() (call parent) super.method() / super() funcref(obj, "m") Callable(obj, "m") or obj.m remote func f() / rpc("f") @rpc("any_peer") func f() / f.rpc() move_and_slide(vel, Vector2.UP) velocity = vel; move_and_slide()

41.4 Behavior changes to watch

Parent _ready()/_process() are no longer called automatically when a child script overrides them — call super().

Rotation-related properties are in radians (rotation), with rotation_degrees available.

Camera2D zoom is inverted (larger = closer).

Physics: default gravity/units are similar, but body and joint behavior differs; retune.

Lighting/rendering looks different (new Vulkan renderer, tonemapping, glow); re-tune environments and materials.

Shaders: hint_color → source_color; SCREEN_TEXTURE/DEPTH_TEXTURE → uniforms with hints; WORLD_MATRIX → MODEL_MATRIX.

Signals connected in scenes using strings still work, but bound args and flags may need fixing.

String functions renamed: find_last → rfind, http_escape → uri_encode, etc.

41.5 Strategy

Upgrade the 3.x project to 3.6 (latest 3.x) and fix warnings.

Commit, then run the converter on a copy.

Fix parse errors script by script (the Output panel lists them), starting with autoloads and base classes.

Re-test each scene; re-tune physics, lighting, UI anchors.

Gradually adopt Godot 4 idioms: static typing, typed arrays, first-class signals, await, TileMapLayer.

🧪 Part III Exercises

Build a 3D first-person controller with sprinting, crouching (shrinking the capsule), and mouse-look; pick up physics objects by raycasting from the camera.

Make enemies chase the player across a baked navigation mesh with avoidance enabled; draw their paths with Line2D for debugging.

Implement grid pathfinding on a TileMapLayer with AStarGrid2D, including solid tiles from custom data and weighted swamp tiles.

Convert an enum-based enemy FSM into a node-based state machine with Idle, Patrol, Chase, Attack, and Hurt states.

Write a hit-flash canvas shader and a dissolve spatial shader; animate both from GDScript using tweens on shader_parameter/... paths.

Create a two-player LAN game: host/join menu, MultiplayerSpawner for players, MultiplayerSynchronizer for positions, and an @rpc chat.

Generate a 256×256 noise height map with WorkerThreadPool.add_group_task and display it as an ImageTexture; compare timing with a single-threaded loop.

Write a @tool script that arranges child nodes in a circle with an exported radius and count, plus a configuration warning when there are no children.

Write GUT or gdUnit4 tests for an Inventory class (add, remove, stack limits, signals) and run them headless from the command line.

Spawn 10,000 sprites three ways — nodes, MultiMeshInstance2D, and RenderingServer canvas items — and compare FPS and memory in the Monitors tab.