I've been working with Godot since version 3.0, and when 4.0 was announced, I was excited but cautious. A complete rendering rewrite, new scripting features, and breaking changes meant migration wouldn't be trivial. After porting three projects from 3.x to 4.x, here's what I learned.
The Big Picture: What Changed
Godot 4 isn't just an incremental update—it's a fundamental rewrite:
- Vulkan renderer: Replacing GLES3/GLES2 with forward+ and mobile backends
- New lighting system: SDFGI for real-time GI, better shadows
- Typed GDScript: Better performance and error checking
- Improved physics: Completely rewritten 3D physics
- Better 2D: Enhanced tilemaps, better texture management
- Node renames: Many nodes got new names for consistency
The Automated Migration Tool
Godot 4 includes an automatic conversion tool when you open a 3.x project. It handles:
- Node renames (Spatial → Node3D, Position2D → Marker2D)
- Method renames (instance() → instantiate())
- Property changes
- Basic script conversions
But it's not magic. Expect to fix:
- Shader syntax (completely different)
- Signal connections with custom arguments
- Export keyword → @export decorator
- Custom rendering or advanced features
Shader Migration: The Big One
This was my biggest pain point. Godot 4's shader language changed significantly:
// Godot 3.x
shader_type canvas_item;
void fragment() {
COLOR = texture(TEXTURE, UV);
COLOR.a *= MODULATE.a;
}
// Godot 4.x
shader_type canvas_item;
void fragment() {
COLOR = texture(TEXTURE, UV);
COLOR *= COLOR.a; // Modulate is gone, use COLOR directly
}
Key shader changes:
MODULATEremoved, useCOLORmultiplicationSCREEN_TEXTURE→SCREEN_TEXTURE(same name, different usage)- Lighting functions completely changed
- Custom render modes work differently
Script Migration Patterns
Here are the most common script changes you'll need:
Export Variables
# Godot 3.x
export var speed = 10.0
export(String, "walk", "run", "sprint") var move_mode
export(NodePath) var target_path
# Godot 4.x
@export var speed: float = 10.0
@export_enum("walk", "run", "sprint") var move_mode: String
@export var target_path: NodePath
Signal Connections
# Godot 3.x
connect("body_entered", self, "_on_body_entered")
# Godot 4.x
body_entered.connect(_on_body_entered)
Node Instantiation
# Godot 3.x
var scene = preload("res://scene.tscn")
var instance = scene.instance()
add_child(instance)
# Godot 4.x
var scene = preload("res://scene.tscn")
var instance = scene.instantiate()
add_child(instance)
Physics Changes
3D physics got a complete rewrite. If you used custom physics queries or advanced features:
# Godot 3.x
var space_state = get_world().direct_space_state
var result = space_state.intersect_ray(from, to)
# Godot 4.x
var space_state = get_world_3d().direct_space_state
var query = PhysicsRayQueryParameters3D.create(from, to)
var result = space_state.intersect_ray(query)
This pattern applies to all physics queries. The new system is more flexible but requires more setup.
Performance Improvements
Despite the migration pain, Godot 4 brought real performance gains:
- Typed GDScript: 2-4x faster in many cases
- Better batching: Draw calls reduced significantly
- Improved threading: WorkerThreadPool is amazing
- Faster startup: Projects load noticeably faster
In Tumblefire, I saw frame rates improve by 30% just from the migration, with no code changes.
New Features Worth Using
Once you're migrated, take advantage of new features:
WorkerThreadPool
# Easy background processing
func generate_terrain():
WorkerThreadPool.add_task(_generate_terrain_async)
func _generate_terrain_async():
# Runs on background thread
var terrain = heavy_generation_function()
# Call back to main thread
call_deferred("_on_terrain_ready", terrain)
Improved Signals
# Signals with types
signal health_changed(new_health: int, max_health: int)
# Lambda connections
button.pressed.connect(func(): print("Pressed!"))
Better Animation Tools
AnimationTree got major improvements. The state machine is clearer, and blend trees are more intuitive.
Common Gotchas
Watch out for these issues that bite everyone:
- TileMap changes: Tilemaps were completely redesigned. You'll need to recreate them.
- Light3D vs OmniLight3D: Different light types now, not just properties
- Input changes: Some input event properties renamed
- ResourceLoader: Now requires full paths more strictly
- FileAccess: Replaces File class with different API
Migration Strategy
Here's how I approached migration:
- Make a branch: Never migrate your main branch directly
- Run the auto-converter: Let Godot do the easy work
- Fix compilation errors: Start with scripts that won't compile
- Update shaders: This takes the longest, do it incrementally
- Test thoroughly: Bugs can hide in subtle behavior changes
- Check plugins: Make sure all addons have 4.x versions
Plugin Compatibility
This was painful. Many popular plugins weren't ready when 4.0 launched:
- Check the asset library for 4.x versions
- Some plugins needed complete rewrites
- Consider alternatives if your plugin isn't maintained
- Simple plugins are often easy to fix yourself
Should You Migrate?
Depends on your project status:
Migrate if:
- You're starting a new project (use 4.x from the start)
- Your project is early in development
- You need 4.x-specific features
- You want better performance
Stay on 3.x if:
- You're close to release
- Your project heavily uses unavailable plugins
- You need GLES2 for older hardware support
- You don't have time for potential debugging
Godot 4.3+ Improvements
If you're migrating now, good news: later 4.x versions fixed many early issues:
- 4.1: Major performance improvements, bug fixes
- 4.2: Better 2D rendering, improved Android export
- 4.3: Enhanced animation tools, better editor performance
- 4.4+: Continued refinements and feature additions
Final Thoughts
Migration was painful but worth it. The new renderer is fantastic, the performance improvements are real, and the engine feels more mature. If you're on the fence, I'd recommend migrating—but budget time for it.
My projects run faster, look better, and the codebase is cleaner thanks to typed GDScript. The pain was temporary, the benefits are permanent.