Understanding How NPCs Actually Work in Roblox
NPCs in Roblox are non-player characters controlled by scripts rather than human input. The built-in system is limited, so most developers end up writing custom AI or using community modules to get anything functional. I spent months trying to build pathfinding that didn't look like a jittery mess before I figured out the right approach. The basic setup involves a Model with a Humanoid, a script that handles state logic, and usually some kind of navigation mesh or raycasting to avoid obstacles. You can create a simple patrol system in under 30 lines of code if you don't need complex behavior. The problem starts when you add multiple NPCs to the same area. They start colliding, stacking, and generally looking like they're on drugs. I had one game where four guard NPCs would converge on a single point and vibrate in place for twenty seconds straight because the pathfinding kept recalculating through each other's hitboxes. The fix was adding a simple radius check that made each NPC maintain distance from nearby entities before recalculating their path. That plus turning off the default collision between the NPCs themselves solved it.
Setting Up Basic Roblox Npcs
Start by creating a new Script inside your NPC model. Put this in StarterCharacterScripts or just parent it directly to the NPC. The absolute minimum you need is a Wander module and a Target module. Don't try to write one massive script that does everything. It gets unmaintainable fast. I had a 600-line NPC controller that broke every time I changed one variable because everything was tangled together. The most common approach is waypoint-based pathfinding. Define a series of Vector3 positions and cycle through them. Here's what I ended up using after a bunch of failed attempts: Create a folder called Waypoints as a child of your NPC. Populate it with Part objects positioned where you want the NPC to walk. The script reads those positions and uses FindPath or simple MoveTo calls to navigate between them. When the NPC reaches the last waypoint, loop back to the first one.
One thing people always miss is damping the speed changes. If you just tell an NPC to MoveTo the next point at full speed, it looks robotic. Set a lerp on the Humanoid.WalkSpeed or use a coroutine that gradually accelerates and decelerates. Takes about five extra lines and makes the difference between a prop and an actual character.
Get the Full Details

Aggro and Detection Ranges
For combat NPCs, you need a detection system. The naive approach is a Distance check every frame. That works fine for maybe five NPCs. After that you're burning CPU for nothing. I switched to a trigger volume system where invisible Part objects act as detection zones. When a player's root part enters the zone, the NPC checks distance and line-of-sight before switching to aggressive mode. The line-of-sight check is usually a Raycast from the NPC's head to the player's position. If it hits the player, they're visible. If it hits a wall first, the NPC doesn't care. I learned this the hard way when a player discovered they could stand behind a thin pillar and my NPCs would still pathfind directly into the wall trying to reach them. Added the raycast and the problem vanished instantly.
Common Pitfalls With Roblox Npcs
The biggest issue beginners run into is pathfinding reliability. Roblox's built-in PathfindingService works well on flat surfaces but struggles with stairs, moving platforms, and vertical navigation. I spent two days debugging an NPC that would walk up to a three-stair staircase and just stand there pressing against it. The solution was increasing the PathHeight and PathWidth properties and disabling the UseJumppoints flag if your NPC isn't supposed to jump. Another problem is NPC-to-NPC collision. By default, every NPC is a physical object that pushes others around. Set CanCollide to false on the NPC models or add them to a collision group that ignores other NPCs. This alone cuts down on most of the physics weirdness you'll encounter. If you need more advanced behavior than patrol and aggro, consider using a state machine. Each state handles its own update loop and transitions are clean and predictable. Idle, Patrol, Chase, Attack, Return. The transitions go in a single function that checks conditions each frame. It's a bit more code upfront but saves hours of headache later.
For the pathfinding implementation specifically, here's a simplified version of what I use now. It polls the waypoint list and handles errors gracefully instead of silently failing: local PathfindingService = game:GetService("PathfindingService") local function findPath(start, waypoints) local path = PathfindingService:CreatePath() path:ComputeAsync(start, waypoints[1]) if path.Status == Enum.PathStatus.Success then return path end return nil end

The key takeaway is that you're almost always going to need to write your own NPC logic rather than relying on plugins or free models. The ones that work well require tweaking for your specific map geometry. There's no universal solution that works across different terrain and building styles. Test each NPC on your actual map, not a blank baseplate.