Pathfinding and Navigation in Godot

Updated June 2026
Godot's navigation system is built on the NavigationServer, which manages navigation meshes, computes paths, and handles obstacle avoidance for AI characters in both 2D and 3D. This guide covers setting up navigation regions, baking meshes, using NavigationAgent nodes for path following, adding dynamic obstacles, working with navigation layers for different agent types, and optimizing pathfinding performance for games with many AI characters.

Pathfinding is what separates AI that walks in straight lines and bumps into walls from AI that intelligently navigates around obstacles, through doorways, and along the most efficient route to its destination. Godot's NavigationServer provides a robust, production-ready pathfinding system that works identically in 2D and 3D, with the only differences being the node names and coordinate dimensions. The same concepts of navigation regions, meshes, agents, and obstacles apply to both.

Set Up Navigation Regions

Navigation begins with NavigationRegion nodes that define where AI characters can move. In 2D, add a NavigationRegion2D to your level scene and create a NavigationPolygon resource for it. The NavigationPolygon is a set of polygon outlines that define walkable floor areas. You draw these in the editor using the polygon editing tools, tracing the walkable space in your level while leaving holes around obstacles.

In 3D, add a NavigationRegion3D and create a NavigationMesh resource. Unlike 2D where you manually draw polygons, the 3D mesh is typically baked automatically from your level's collision geometry. The baking process analyzes StaticBody3D collision shapes and generates a walkable surface mesh that accounts for agent size, step height, and slope limits.

Multiple NavigationRegion nodes can exist in a single scene. The NavigationServer automatically connects regions whose edges align, creating a seamless navigation graph. This is essential for modular level design where rooms, corridors, and outdoor areas are separate scenes that connect at shared boundaries. Each region can be independently enabled or disabled at runtime, which is useful for opening and closing paths dynamically, like unlocking a door that opens a new route.

Bake the Navigation Mesh

For 2D, "baking" is simply drawing the navigation polygon vertices in the editor. Click the NavigationRegion2D, select the NavigationPolygon resource, and use the polygon editing tools to outline the walkable area. You can create multiple polygons within a single region and add holes to cut out obstacle areas. The polygon should represent the actual walkable floor space with a margin from walls equal to the agent's radius.

For 3D, click the NavigationRegion3D, open the NavigationMesh resource, and configure the baking parameters. The most important settings are agent radius (how far from walls the mesh generates), agent height (minimum ceiling clearance), max climb (maximum step height), and max slope (steepest walkable angle). After setting these, click "Bake NavigationMesh" in the toolbar. The baker processes all collision shapes within the region and outputs a walkable mesh.

Common baking issues include the mesh not generating where expected (often because the geometry lacks collision shapes), the mesh being too narrow near walls (agent radius too large), or the mesh not connecting through doorways (doorway too narrow for the agent radius). The navigation mesh is visible in the editor as a colored overlay on your level, making it easy to spot gaps and connection problems. Adjust parameters and rebake until the mesh covers all intended walkable areas with continuous, connected surfaces.

For procedurally generated levels, bake the navigation mesh at runtime using navigation_region.bake_navigation_mesh(). This triggers an asynchronous bake operation. Connect to the bake_finished signal to know when the mesh is ready for pathfinding queries. Runtime baking is more expensive than editor baking, so limit it to level generation events rather than running it frequently during gameplay.

Add NavigationAgent to Characters

NavigationAgent2D and NavigationAgent3D are the nodes that AI characters use to interact with the NavigationServer. Add one as a child of your CharacterBody2D or CharacterBody3D. The agent handles path requests, path following, and optionally obstacle avoidance, abstracting the NavigationServer's lower-level API into a convenient node-based interface.

Configure the agent's core properties. path_desired_distance controls how close the agent must be to a path point before advancing to the next one; smaller values produce tighter path following while larger values create smoother curves at corners. target_desired_distance determines how close to the final destination counts as "arrived." path_max_distance sets how far the agent can deviate from its path before automatically requesting a repath.

The max_speed property is used by the avoidance system to limit the agent's adjusted velocity. Set this to match your character's actual maximum movement speed. If avoidance is disabled, this property has no effect on movement, and your script controls speed directly through the velocity you assign to the character.

Request and Follow Paths

To navigate an AI character, set the agent's target_position to where you want it to go. The NavigationServer computes the optimal path asynchronously (though it is fast enough to appear instant for most maps). In your _physics_process function, call navigation_agent.get_next_path_position() to get the next point along the path that the character should move toward.

Calculate the direction from the character's current position to the next path position, normalize it, multiply by the desired speed, and assign the result to the character's velocity before calling move_and_slide(). Check navigation_agent.is_navigation_finished() each frame to know when the agent has reached its destination. When true, stop movement or begin the next behavior.

The agent emits several useful signals. velocity_computed fires when avoidance-adjusted velocity is ready, which is how you integrate avoidance without polling. navigation_finished fires once when the agent reaches its target. path_changed fires when a new path is computed, which is useful for updating visual path indicators or triggering sounds. target_reached fires when the agent is within target_desired_distance of the goal for the first time.

Avoid setting target_position every single physics frame when chasing a moving target like the player. Each assignment triggers a path recomputation, which is unnecessary if the target has only moved slightly. Instead, update the target on a timer (every 0.2 to 0.5 seconds) or when the target has moved more than a threshold distance from its last known position. This reduces NavigationServer load significantly in scenes with many pursuing agents.

Configure Obstacle Avoidance

NavigationAgent's avoidance system prevents AI characters from walking through each other by adjusting their velocities to steer around nearby agents. Enable avoidance by setting avoidance_enabled = true on the agent. Configure the radius (how much space the agent needs), max_speed, and avoidance_priority (lower priority agents yield to higher priority ones).

When avoidance is enabled, do not directly use get_next_path_position() for movement. Instead, set the agent's velocity property to your desired velocity (direction to path point times speed), and connect to the velocity_computed signal. The NavigationServer calculates an avoidance-safe velocity and provides it through this signal. Use the safe velocity for your character's actual movement. This two-step process lets the avoidance system modify your intended velocity to prevent collisions while keeping the character generally on its path.

NavigationObstacle2D and NavigationObstacle3D represent dynamic obstacles that AI should navigate around. A closing door, a pushed crate, or a temporary barricade can be a NavigationObstacle that affects nearby agents' avoidance calculations. Static obstacles should be incorporated into the navigation mesh itself for better performance, since avoidance calculations happen every frame while navigation mesh obstacles are processed once during baking.

Use Navigation Layers and Links

Navigation layers let you create separate navigation meshes for different agent types on the same map. A small enemy might walk through narrow passages that a large enemy cannot. A flying enemy might navigate through open air that ground enemies avoid. Each NavigationRegion can be assigned to specific layers, and each NavigationAgent has a navigation layer mask that determines which layers it considers when pathfinding.

Set up layers in the Project Settings under Navigation. Assign descriptive names like "ground," "flying," "large_enemies," and "small_enemies." Then configure your NavigationRegion nodes to generate meshes on the appropriate layers. A ground-level region might be on layers 1 and 2 (for both small and large ground enemies), while an elevated walkway might be on layer 1 only (too narrow for large enemies). Agents with different layer masks will find different paths through the same level.

NavigationLink2D and NavigationLink3D create bidirectional or one-way connections between disconnected navigation mesh areas. Use links for jump points, teleporters, ladders, or any transition that is not represented by continuous walkable surface. A link has a start position and an end position, and the NavigationServer includes it as a potential path segment during route calculation. When an agent's path includes a link, you detect this by checking if the next path point is on a link and trigger the appropriate special movement, like playing a jump animation or teleporting the character.

Optimize for Performance

The NavigationServer handles pathfinding efficiently, but with many agents all requesting paths simultaneously, the CPU cost can spike. The primary optimization is staggering path requests across frames. Instead of all 30 enemies requesting new paths on the same frame, spread them out using a modulo index or rotating timer so only a few agents update per frame. Each individual path computation is fast, but batching 30 of them on one frame creates a noticeable spike.

Reduce path update frequency for distant agents. Enemies near the player need frequent path updates for responsive behavior, but enemies across the map can update their paths much less often. A tiered system with update rates of every frame (near), every 5 frames (medium distance), and every 30 frames (far away) keeps distant AI functional while focusing CPU budget on the enemies the player is actually interacting with.

Navigation mesh complexity affects both baking time and runtime performance. Avoid unnecessarily detailed meshes by using appropriate cell size settings during baking. Simpler meshes with fewer polygons produce faster path queries. For large open areas, the mesh should be relatively simple, while complex interiors with many obstacles naturally produce denser meshes. You can manually simplify meshes by adjusting the bake parameters, increasing cell size for less detail or decreasing it for more precision.

For truly large maps, consider dividing the world into chunks with separate NavigationRegion nodes that are loaded and unloaded as the player moves. The NavigationServer handles region connections automatically, so adding or removing regions at runtime dynamically extends or contracts the navigable world without requiring a full repath of all agents.

Key Takeaway

Godot's NavigationServer provides a complete pathfinding solution with navigation meshes, agent-based path following, obstacle avoidance, and layer-based routing that works in both 2D and 3D, requiring only proper mesh setup and sensible update frequency management to perform well with many AI characters.