New Our agentic pipeline is live — the agent researches an object before it builds it. Read the post →
RIGYD
Launch app
Comparison

PyBullet vs MuJoCo

Both are free, Python-first physics engines aimed at robotics and reinforcement learning, and for years the choice between them was mostly taste. It is less even now. The two differ on how contact is formulated, on how they scale, and — the part most comparisons skip — on how actively each one is still being released.

Updated 2026-09-07

The short answer

PyBullet is the Python binding to the Bullet Physics SDK: an LCP-family rigid-body engine that reads URDF, SDF and MJCF, renders cameras on CPU or GPU, and runs as a client to a physics server. MuJoCo is Google DeepMind's engine for articulated systems in contact, built on a convex relaxation of contact rather than a complementarity problem, with a JAX implementation (MJX) for massively parallel training. Choose MuJoCo for contact-rich manipulation and locomotion, for large-scale RL, and for anything you will still be maintaining in three years. Choose PyBullet when you need its format breadth, its client-server architecture, or its zlib licence — and accept that its release cadence has slowed sharply.

Side-by-side comparison

DimensionPyBulletBullet Physics, from PythonMuJoCoConvex contact, actively released
What it isPython bindings to the Bullet Physics SDK, a general-purpose rigid- and soft-body engineA physics engine for multi-joint dynamics with contact, with its own Python module
MaintainerErwin Coumans, Yunfei Bai and Jasmine Hsu, per the package metadataGoogle DeepMind; originally written by Roboti LLC
LicencezlibApache 2.0
Latest release on PyPI3.2.7, January 20253.12.0, August 2026
Recent release cadenceTwo releases since mid-2022; the repository's issue tracker is closedEight releases between March and August 2026
Contact formulationLCP family — sequential impulse, projected Gauss-Seidel and Dantzig solvers are selectableConvex relaxation that drops strict complementarity; Newton by default, plus CG and a generalized PGS
Articulated bodiesFeatherstone's algorithm via btMultiBody, with an opt-in maximal-coordinate pathGeneralized coordinates throughout
Formats it readsURDF, SDF, MJCF, Bullet's own .bullet worlds, and soft bodies from OBJMJCF natively; URDF, MJZ archives and OpenUSD (documented as experimental)
Parallel and GPUNo batched-GPU physics in the Python module; scale by running more DIRECT clients or processesMJX runs the engine under JAX on NVIDIA and AMD GPUs, Apple Silicon and Cloud TPUs
Process modelClient-server: DIRECT, GUI and shared-memory modes let several clients attach to one serverIn-process library; parallel sampling by sharing one mjModel across many mjData instances
Camera renderinggetCameraImage via a pure-software TinyRenderer or hardware OpenGL, with segmentation masksNative OpenGL visualiser with debug overlays — contact forces, inertia boxes, joint and actuator axes
SensorsrayTest and rayTestBatch, contact and closest-point queries, joint force/torqueDeclarative sensors — touch, accelerometer, gyro, velocimeter, force, torque, magnetometer, rangefinder — with noise, cutoff and delay attributes
ROS / ROS 2Not mentioned in the project's README or Python module; community bridges onlyNot mentioned anywhere in the project's documentation; community bridges only
Curated model librarySample robots and scenes ship with the package and its example environmentsMuJoCo Menagerie, a curated model collection maintained by Google DeepMind

Two different bets on how contact works

The clearest technical difference between these engines is how each formulates contact, and both projects are unusually explicit about it. Bullet sits in the LCP family: PyBullet exposes CONSTRAINT_SOLVER_LCP_SI, CONSTRAINT_SOLVER_LCP_PGS and CONSTRAINT_SOLVER_LCP_DANTZIG as selectable constraint solvers in its module definition, and its articulated bodies run Featherstone's algorithm with that solver attached. MuJoCo took the other road. Its computation chapter describes dropping the strict complementarity constraint “at the heart of the LCP formulation”, which turns contact into a convex optimization problem with a uniquely defined inverse; the overview names the resulting algorithms as a Newton solver by default, with a conjugate gradient method and a generalized projected Gauss-Seidel that handles elliptic friction cones. What is worth noticing is that MuJoCo's own documentation does not sell this as a straight win — it says dropping complementarity means “force and velocity in the contact normal direction can be simultaneously positive, and frictional forces may not be maximally dissipative”, calls those effects “numerically small yet undesirable”, and states that the authors “see both LCP models and convex models as different approximations to physical reality, each with its strengths and weaknesses”. The case for the convex model is that real contact surfaces deform, so soft contact is the more honest approximation. If your work depends on strict complementarity at the contact, that is a genuine reason to stay with an LCP engine.

Check the maintenance gap before anything else

This is the part of the comparison that has changed most since the two were last a coin flip, and it is easy to verify yourself. PyPI lists pybullet at version 3.2.7, published in January 2025, with only one release before it going back to May 2022. The Bullet repository's README states plainly that “the Issue tracker was flooded with support questions and is closed until it is cleaned up”, directing users to the forums instead. mujoco on PyPI, by contrast, is at 3.12.0, published in August 2026 — the eighth release since March of the same year. None of that means PyBullet is broken, and it is worth being fair about what a slow release cadence actually costs. An engine that stops changing also stops breaking your scripts, and the large body of published PyBullet baselines still runs as it did. But it does change what to expect over the next few years: fixes arrive on nobody's schedule, support for new hardware and new Python versions is not guaranteed, and your questions get answered by other users rather than by maintainers. For a weekend project that is irrelevant. For a robot programme with a three-year horizon it outweighs most of the rows in the table above.

Scale is where the two genuinely diverge

If you are training policies, the deciding factor is usually how many environment steps you can afford, and here the architectures are not comparable. MuJoCo ships MJX, a separate mujoco-mjx package that provides a JAX API to MuJoCo and runs on “all compute hardware supported by the XLA compiler” — NVIDIA and AMD GPUs, Apple Silicon, and Google Cloud TPUs — so a batch of environments steps as one vectorised call, with a Warp implementation targeting NVIDIA GPUs specifically. PyBullet has no equivalent in its Python module: Bullet's README describes the SDK's OpenCL GPU path as experimental and incomplete, and it is not what PyBullet uses, so you scale the older way — many DIRECT clients across processes and cores. Two caveats keep this from being a clean sweep. MJX does not have full feature parity with MuJoCo: its documentation lists unsupported geom types and collision pairs, restricts the available integrators, and will refuse to move a model onto the device if that model uses something unsupported. And PyBullet's client-server design buys something MJX does not — GUI, DIRECT and shared-memory connection modes mean a viewer, a controller and the physics server can be separate processes, which is convenient for teleoperation and hardware-in-the-loop rigs. We have no benchmark of our own to cite, and published step-rate figures depend so heavily on model, contact count and hardware that quoting someone else's would mislead. Measure it on your model.

PyBullet reads more formats — including MuJoCo's own

This is the asymmetry a three-way simulator comparison never has room for, and it decides more migrations than the solver does. PyBullet's module definition exposes loadURDF, loadSDF, loadMJCF, loadBullet and loadSoftBody, so a MuJoCo model file can be pointed at PyBullet directly. MuJoCo's modeling guide lists MJCF as native and URDF, MJZ archives and OpenUSD as the other formats it loads; SDFormat is not among them. The door swings one way. Loading is not matching, though: the same MJCF stepped by an LCP solver and by a convex solver will not produce the same trajectory, and MuJoCo's guide is explicit that URDF “can only represent a subset of the model elements available in MuJoCo” and that URDF files, unlike MJCF, are not checked against a schema, so mis-typed attributes are silently ignored. Treat a cross-format load as a starting point for re-tuning rather than a port. The other direction worth knowing about is OpenUSD: MuJoCo now documents USD import and export, built on the standard UsdPhysics schemas with mjcPhysics extensions for what UsdPhysics does not cover, plus a file-format plugin that lets a native USD application treat an MJCF file as a USD layer. Its own documentation labels that support experimental and subject to frequent change, so plan accordingly — but the direction of travel is clear, and PyBullet has nothing comparable. MuJoCo also has Menagerie, a curated collection of high-quality models maintained by Google DeepMind, which for many teams is worth as much as any engine feature.

When to choose each

PyBullet

Projects that need its format breadth — SDF and .bullet worlds in particular — teleoperation and hardware-in-the-loop rigs that suit the client-server design, reproducing existing PyBullet baselines, and codebases where the zlib licence is easier to clear than Apache 2.0.

MuJoCo

Contact-rich manipulation and locomotion, reinforcement learning at scale via MJX, work that needs modelled sensor noise and delay or analytically invertible dynamics, and any project whose maintenance horizon is measured in years rather than months.

Where Rigyd fits

Rigyd turns a 3D model, an image, or a text description into validated OpenUSD and MJCF, with collision geometry and mass properties derived once and written into both. That lines up cleanly with MuJoCo: MJCF is its native format, and its experimental USD support means the other output is not wasted either. It lines up less cleanly with PyBullet. PyBullet can read MJCF, but URDF is the format its ecosystem is actually built around, and Rigyd does not emit URDF — so if your pipeline is URDF-first PyBullet, our output is not a drop-in and you would be converting. Worth saying plainly rather than implying otherwise. The problem we do remove is the one that shows up when a team runs both engines: the same object described twice, by hand, with physics properties that quietly drift apart until the two simulations disagree and nobody can say which one is right.

FAQ

Frequently asked questions

Should I use PyBullet or MuJoCo?

For most new robotics and reinforcement-learning work, MuJoCo. It is under active development — eight releases between March and August 2026, against PyBullet's two since mid-2022 — its contact model is designed specifically for articulated systems in contact, and MJX gives it a GPU and TPU path for large-scale training that PyBullet has no equivalent to. PyBullet is still the better answer in three specific cases: when you need it to read SDF or .bullet files, when its client-server process model suits a teleoperation or hardware-in-the-loop setup, or when you are reproducing existing PyBullet results.

Is PyBullet still maintained?

It is still available and still works, but the pace has dropped a long way. PyPI shows the latest pybullet release as 3.2.7 in January 2025, with only one release before it going back to May 2022, and the Bullet repository's README says the GitHub issue tracker is closed because it was flooded with support questions. Treat it as stable rather than actively developed: existing scripts keep running, but do not plan around new features or timely fixes.

Can PyBullet load MuJoCo MJCF models?

Yes — PyBullet exposes a loadMJCF function alongside loadURDF and loadSDF, so you can point it at an MJCF file directly. What you will not get is matching behaviour. The two engines formulate contact differently, so the same model stepped by each will diverge, and any MuJoCo-specific modelling that has no Bullet equivalent will not survive the trip. It is a useful starting point for a port, not a port.

Which one is faster?

For a single environment on CPU it depends entirely on your model, your contact count and your timestep, and there is no benchmark we can honestly point you at — published step-rate numbers vary so much with those variables that quoting one would mislead. For many environments in parallel the question has a clearer shape: MJX compiles MuJoCo through JAX and runs batched environments on GPUs and TPUs, while PyBullet scales by launching more processes. Benchmark your own model before committing either way.

Are PyBullet and MuJoCo free for commercial use?

Both are free and open source. Bullet, and therefore PyBullet, is under the zlib licence, which asks only that you not misrepresent the origin of the software and that you keep the notice in source distributions. MuJoCo is under Apache 2.0, which adds an explicit patent grant and a requirement to state your changes. Neither charges for commercial use; if your organisation runs a licence review, zlib is usually the shorter conversation.

Does either work with ROS 2 out of the box?

Neither does. ROS is not mentioned in MuJoCo's documentation, nor in Bullet's README or PyBullet's Python module — both are physics engines rather than robot middleware, and neither project ships a ROS 2 integration of its own. Community bridges exist for both, but you are adopting and maintaining a third-party package either way. If native ROS 2 support is the requirement, the tool to compare against is Gazebo, not the other engine on this page.

Build with Rigyd

Turn a 3D model, image, or text description into validated OpenUSD and MJCF.