Articles › Game development

Godot 4.6 makes Jolt the default 3D physics: do old projects switch?

Godot 4.6 sets Jolt Physics for new 3D projects; existing ones stay on GodotPhysics3D. The behaviour differences, the settings that matter, and how to migrate and test.

Intermediate 5 min read October 23, 2026

What you will learn
  • Godot 4.6 (26 Jan 2026) writes physics/3d/physics_engine = Jolt Physics into new projects; existing projects are untouched
  • DEFAULT currently means GodotPhysics3D, but the docs say that may change, so pin the engine explicitly in shipped projects
  • Jolt differs in single-body joints, collision margins, depenetration, ray-cast face index and the size of WorldBoundaryShape3D
  • Migrate on a branch, run every physics scene, and compare results with numbers, not by eye

Godot 4.6 shipped on 26 January 2026 with one big change for 3D games: Jolt Physics is the default physics engine for new 3D projects, replacing GodotPhysics3D. The common misunderstanding is that old projects move over automatically. They do not. This article explains the actual mechanism, the behaviour that differs, and a migration you can measure.

Facts checked against the Godot 4.6 release page, the stable Using Jolt Physics docs, ProjectSettings.xml at tag 4.6-stable, and PR #105737, which made Jolt the default, as of October 2026. (4.7 is out now, but this change started in 4.6.)

New project in 4.6+Jolt Physics written to fileuses Jolt at onceExisting projectsetting stays DEFAULT= GodotPhysics3Dswitch it yourself
Upgrading to 4.6 does not switch an existing project's engine

What changed and what did not

PR #105737 shows Godot did not change the setting’s default value. Instead, the project manager writes this into project.godot when you create a new project:

[physics]

3d/physics_engine="Jolt Physics"

The default of physics/3d/physics_engine is still DEFAULT, and the 4.6 ProjectSettings reference says DEFAULT is currently equivalent to GodotPhysics3D but may change in future releases; select an explicit engine if you want your project to stay put.

SituationIn project.godotEngine you get in 4.6
New project created in 4.6+"Jolt Physics"Jolt
Old project, never touched this settingno line → DEFAULTGodotPhysics3D (may change later)
Old project with GodotPhysics3D selected"GodotPhysics3D"GodotPhysics3D
touch project.godot, then open the editorthe editor fills in "Jolt Physics"Jolt

If you have a shipped 3D game that is not migrating yet, set GodotPhysics3D explicitly today so a future upgrade does not quietly swap engines under you.

How Jolt behaves differently

The Using Jolt Physics page lists the differences. The ones that bite real games most often:

  • Single-body joints. With a body on only one side of a joint, the other side counts as “the world”. Jolt and GodotPhysics3D disagree on which side that is, which inverts the joint’s limits. Fix with physics/jolt_physics_3d/joints/world_node, or move the body to the other slot
  • Unsupported joint properties such as bias, softness and relaxation on HingeJoint3D, and soft limits on Generic6DOFJoint3D. Non-default values emit a warning
  • Collision margins. Jolt uses a “convex radius”: it shrinks the shape, then adds the margin back as a shell, so the size does not grow but corners round off (GodotPhysics3D ignores margin entirely)
  • Overlapping bodies. GodotPhysics3D pushes them apart like a spring and can overshoot; Jolt corrects position only, so it never overshoots but can take longer
  • Ray-cast face_index is always -1 until you enable queries/enable_ray_cast_face_index
  • Kinematic-frozen RigidBody3D reports no contacts with static or kinematic bodies until you enable simulation/generate_all_kinematic_contacts
  • Area3D and SoftBody3D. Jolt emits body_entered for soft bodies; GodotPhysics3D does not
  • WorldBoundaryShape3D is no longer unbounded

Worked example: three defaults that change your game quietly

1. A WorldBoundaryShape3D floor that ends physics/jolt_physics_3d/limits/world_boundary_shape_size defaults to 2000.0: the plane sits in the middle of a 2000 m box.

  1. Half of 2000 = 1000
  2. Anything more than 1000 m from the centre along the plane does not collide with it An open-world or endless-runner game using a plane as the ground will see the player fall through once they go far enough.

2. Rounded box corners collision_margin_fraction defaults to 0.08, times the shape’s shortest axis, capped by Shape3D.margin (default 0.04).

  • A 2 × 0.5 × 1 m box → 0.08 × 0.5 = 0.04 m → within the cap → 4 cm
  • A 0.2 × 0.2 × 0.2 m box → 0.08 × 0.2 = 1.6 cm A 4 cm round on a person-sized crate is invisible, but stacking boxes precisely or rolling a ball off a table edge will show it.

3. How slowly overlaps resolve (a simplified model counting only Baumgarte) baumgarte_stabilization_factor defaults to 0.2: fix 20% of the penetration each step.

  1. A 10 cm overlap leaves 10 × 0.8ⁿ cm after n steps
  2. Below 1 cm needs 0.8ⁿ < 0.1 → n > ln 0.1 ÷ ln 0.8 ≈ 10.3 → 11 steps
  3. At physics_ticks_per_second = 60 → 11 × 16.7 ms ≈ 183 ms A character spawned inside a wall slides out over about a fifth of a second instead of being launched.

Migrating an existing project, step by step

  1. Branch in git first. Switching engines is one line, so it is easy to undo
  2. Project Settings > Physics > 3D > Physics Engine → Jolt Physics, then Save & Restart
  3. Read the Output panel for warnings about unsupported joint properties and fix them
  4. Check every single-body joint for inverted limits
  5. Search your code for face_index, get_contact_impulse(), and Area3D with soft bodies, and decide which settings to enable
  6. Run every scene with physics. 4.6 adds game speed controls in the editor; slow things down to watch collisions
  7. Measure. A tiny test scene that drops a body and logs its position over time, run under both engines:
# test_drop.gd — attach to a RigidBody3D, run under both engines, compare
extends RigidBody3D

var _ticks := 0

func _physics_process(_delta: float) -> void:
	_ticks += 1
	var hz := Engine.physics_ticks_per_second
	if _ticks % (hz / 2) == 0:  # print every half second; count ticks, don't sum floats
		print("%.2f s  y=%.3f  vy=%.3f" % [float(_ticks) / hz, global_position.y, linear_velocity.y])
	if _ticks >= hz * 3:
		get_tree().quit()

If your game depends heavily on physics timing, read fixed timestep game loops alongside this: _physics_process runs on a fixed 60 ticks a second by default, whichever engine you use.

Common mistakes

  • Assuming upgrading to 4.6 gives you Jolt. Old projects stay on DEFAULT = GodotPhysics3D
  • Leaving it on DEFAULT. The day DEFAULT changes, your game changes engine without anyone deciding to. Pin it
  • Setting collision margin fraction to 0 for sharp edges. The docs warn values near 0 reduce accuracy for convex shapes
  • Computing damage from get_contact_impulse(). In Jolt it is estimated ahead of time and only accurate when the two bodies touch nothing else
  • Moving from the Godot Jolt extension with old setting names. The category moved from physics/jolt_3d to physics/jolt_physics_3d, and several values changed from percent to fraction
  • Turning on Run On Separate Thread. The docs call it lightly tested; treat it as experimental

Sources

FAQ

If I open a 4.5 project in 4.6, do I get Jolt automatically?

No. The 4.6 release notes say existing projects are not affected. Only projects created in 4.6 or later get the Jolt line written into project.godot.

Does 2D physics change too?

No. This is 3D only; the setting is physics/3d/physics_engine. 2D has its own separate setting.

Can I keep using the Godot Jolt extension?

Yes, but the docs say it is in maintenance mode; the module built into Godot since 4.4 is the main one. Settings moved from physics/jolt_3d to physics/jolt_physics_3d, and the extension's Jolt-specific joint nodes are not in the built-in module.

Commands and settings were tested on sample systems. Try them on a test machine before production.