Pick a ROS 2 distribution by three constraints: the Ubuntu version your hardware vendor locks you to, how long you need security and bugfix support, and whether your stack needs a feature that only exists in a newer release. Everything else, including nodes, topics, and launch files, behaves the same across all four distros. This guide gives you the decision rules, the support dates, and the migration steps.
Quick Takeaways
- Lyrical Luth (LTS) is the default for new projects on Ubuntu 26.04 or Windows 11. It is a long-term support release with Tier 1 support for Windows 11 and Ubuntu 26.04 until May 2031.
- Jazzy Jalisco (LTS) is the safe production choice on Ubuntu 24.04. Its support runs to May 2029.
- Humble Hawksbill (LTS) is the legacy choice for Ubuntu 22.04 and older NVIDIA Jetson images. Support ends May 2027. Plan the exit now.
- Kilted Kaiju is a non-LTS release. The official distribution page lists its EOL as November 2026, and some trackers show December 2026. Do not start new production work on it.
ROS 2 Distribution Comparison Table
| Attribute | Humble | Jazzy | Kilted | Lyrical |
|---|---|---|---|---|
| Release | May 2022 | May 2024 | May 2025 | May 22, 2026 |
| Type | LTS | LTS | Non-LTS | LTS |
| EOL | May 2027 | May 2029 | Nov–Dec 2026 | May 2031 |
| Primary OS | Ubuntu 22.04 | Ubuntu 24.04 | Ubuntu 24.04 | Ubuntu 26.04, Windows 11 |
| C++ standard | C++17 | C++17 | C++17 | C++20 |
| Python (system) | 3.10 | 3.12 | 3.12 | Ubuntu 26.04 default |
| Default RMW | Fast DDS | Fast DDS | Fast DDS | Fast DDS (rmw_fastrtps_cpp) |
| Gazebo pairing | Fortress | Harmonic | Ionic | Jetty* |
| Best for | Jetson JetPack 6 fleets, legacy stacks | Production robots today | Short experiments | New builds, long-lived products |
*Confirm the exact simulator pairing in REP 2000 before you pin versions.
How ROS 2 Release Cadence Works
A new ROS 2 distribution ships every year on May 23rd. Odd-year releases are normal releases supported for 1.5 years, and each release is supported on exactly one Ubuntu LTS. That rule explains the lineup:
- Even years (2022, 2024, 2026): LTS releases with five years of support.
- Odd years (2023, 2025): Short-lived releases (Iron, Kilted) that share an Ubuntu base with the previous LTS.
- Next up: Makoa Mata-mata is scheduled for May 2027. That is another non-LTS release.
Production teams should track the LTS line (Humble, Jazzy, Lyrical) and treat odd-year releases as previews.
Distribution-by-Distribution Breakdown
Humble Hawksbill: The Legacy Workhorse
Humble runs on Ubuntu 22.04 with C++17 and Python 3.10. It has the largest pool of third-party packages, Stack Overflow answers, and vendor drivers. Many robot SDKs still ship Humble images, and NVIDIA Jetson boards on JetPack 6.x run Ubuntu 22.04.
Its weaknesses are age and the clock. Support ends in May 2027, and Ubuntu 22.04 standard support ends around the same time. Newer ros2_control and Nav2 features land on Humble late or not at all.
Stay on Humble only if a hardware vendor blocks you. Otherwise, start planning the move to Jazzy or Lyrical.
Jazzy Jalisco: The Stable Production Default
Jazzy targets Ubuntu 24.04 and gives you support until May 2029. Compared to Humble, you get:
- Gazebo Harmonic through the
ros_gzbridge instead of Fortress. - A newer
ros2_controlstack.diff_drive_controllerexpects TwistStamped commands by default, which breakscmd_velpublishers written for Humble. - Improved
rosbag2tooling and a more mature Zenoh-based middleware option.
Jazzy is the lowest-risk LTS today. Its package ecosystem is mature, and its EOL leaves you almost three years of runway.
Kilted Kaiju: The Short-Lived Release
Kilted is a non-LTS release on Ubuntu 24.04. It brought Gazebo Ionic and promoted rmw_zenoh toward first-class status. Its support window is short, ending in late 2026.
Use it to test features that will appear in Lyrical. Do not ship products on it.
Lyrical Luth: The New LTS
Lyrical is the twelfth ROS 2 release. Open Robotics highlights C++20 support, new ROS IDL buffers for vendor-neutral GPU transport, await semantics in the AsyncIO rclpy client, a new executor that sharply reduces CPU usage, and ergonomic improvements for launching, bagging, logging, and parameters.
Platform tiers matter for deployment:
| Platform | amd64 | arm64 |
|---|---|---|
| Ubuntu 26.04 | Tier 1 | Tier 1 |
| Windows 11 (VS2022) | Tier 1 | Tier 3 |
| RHEL 10 | Tier 2 | Tier 3 |
| Ubuntu 24.04 | Tier 3 (source build) | Tier 3 |
Ubuntu 24.04 is only Tier 3 for Lyrical. If your fleet runs 24.04, stay on Jazzy or build Lyrical from source. If your robot computer image is 26.04, go straight to Lyrical.
Why Distro Choice Affects Control Loop Performance
The executor and middleware add latency and jitter to every sensor-to-actuator path. A simplified budget for one control cycle:
T_loop = T_sense + T_dds + T_exec + T_compute + T_actuate
At 500 Hz: T_loop must stay below 2.0 ms.
Jitter in T_exec directly erodes phase margin. A delay τ at crossover frequency ω_c costs:
Δφ = ω_c · τ (radians)
Example: ω_c = 2π · 20 Hz = 125.7 rad/s, τ = 2 ms
Δφ = 125.7 · 0.002 = 0.251 rad ≈ 14.4°
That is 14.4° of phase margin gone. A well-tuned loop with 45° margin drops to about 31°, and overshoot rises noticeably. The discrete PID law shows where the delay bites:
u[k] = Kp·e[k] + Ki·Ts·Σ e[i] + Kd·(e[k] − e[k−1]) / Ts
If Ts drifts because the executor schedules your timer late, the Kd term amplifies the error. This is why Lyrical’s lower-overhead executor matters for high-rate loops. Keep hard real-time loops (above roughly 1 kHz) inside ros2_control on a PREEMPT_RT kernel, not in a plain rclpy timer, regardless of distro.
Practical Workflow: Running Multiple Distros with Docker
Pin the distro in a container so one workstation can build for Humble, Jazzy, and Lyrical.
# Dockerfile: build with --build-arg ROS_DISTRO=jazzy
ARG ROS_DISTRO=jazzy
FROM ros:${ROS_DISTRO}-ros-base
ARG ROS_DISTRO
ENV ROS_DISTRO=${ROS_DISTRO}
# Install build tooling and common robotics packages for the chosen distro
RUN apt-get update && apt-get install -y --no-install-recommends \
python3-colcon-common-extensions \
ros-${ROS_DISTRO}-navigation2 \
ros-${ROS_DISTRO}-ros2-control \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /ws
COPY src ./src
# Resolve dependencies from package.xml files, then build
RUN rosdep install --from-paths src --ignore-src -y \
&& . /opt/ros/${ROS_DISTRO}/setup.sh \
&& colcon build --symlink-install
Build and test one image per distro:
docker build --build-arg ROS_DISTRO=humble -t robot:humble .
docker build --build-arg ROS_DISTRO=jazzy -t robot:jazzy .
docker build --build-arg ROS_DISTRO=lyrical -t robot:lyrical .
If a build fails on one distro, you have found a migration problem before it reaches the robot.
Writing Distro-Aware Code
Use the ROS_DISTRO environment variable to handle API differences cleanly. This node publishes Twist on Humble and TwistStamped on newer distros:
#!/usr/bin/env python3
import os
import rclpy
from rclpy.node import Node
from geometry_msgs.msg import Twist, TwistStamped
# ROS_DISTRO is set by sourcing /opt/ros/<distro>/setup.bash
DISTRO = os.environ.get("ROS_DISTRO", "unknown")
# Humble controllers expect Twist; Jazzy+ diff_drive_controller expects TwistStamped
USE_STAMPED = DISTRO != "humble"
class CmdVelPublisher(Node):
def __init__(self):
super().__init__("cmd_vel_publisher")
msg_type = TwistStamped if USE_STAMPED else Twist
# QoS depth of 10 buffers short bursts without blocking the publisher
self.pub = self.create_publisher(msg_type, "/cmd_vel", 10)
# 0.02 s period = 50 Hz command rate
self.timer = self.create_timer(0.02, self.tick)
self.get_logger().info(f"Distro={DISTRO}, stamped={USE_STAMPED}")
def tick(self):
if USE_STAMPED:
msg = TwistStamped()
msg.header.stamp = self.get_clock().now().to_msg() # required timestamp
msg.header.frame_id = "base_link"
msg.twist.linear.x = 0.2 # forward velocity, m/s
msg.twist.angular.z = 0.0 # yaw rate, rad/s
else:
msg = Twist()
msg.linear.x = 0.2
msg.angular.z = 0.0
self.pub.publish(msg)
def main():
rclpy.init()
node = CmdVelPublisher()
try:
rclpy.spin(node)
finally:
node.destroy_node()
rclpy.shutdown()
if __name__ == "__main__":
main()
Select distro-specific parameter files in a launch file:
import os
from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
distro = os.environ.get("ROS_DISTRO", "jazzy")
pkg = get_package_share_directory("my_robot_bringup")
# One YAML per distro: params_humble.yaml, params_jazzy.yaml, params_lyrical.yaml
params = os.path.join(pkg, "config", f"params_{distro}.yaml")
return LaunchDescription([
Node(
package="my_robot_driver",
executable="driver_node",
parameters=[params], # loads controller gains and topic names for this distro
output="screen",
),
])
Decision Matrix: Which ROS 2 Distro Should You Use?
| Your situation | Use | Reason |
|---|---|---|
| New project, Ubuntu 26.04 or Windows 11 | Lyrical | Longest support, C++20, new executor |
| New project, Ubuntu 24.04 | Jazzy | Tier 1 on 24.04, support to 2029 |
| Jetson with JetPack 6.x (Ubuntu 22.04) | Humble | Matches the OS; migrate when JetPack moves to 24.04 |
| Teaching or hobby robot | Jazzy or Lyrical | Best docs and longest useful lifetime |
| Testing upcoming features | Kilted or Rolling | Short-lived; not for products |
| Fleet that must outlive 2027 | Jazzy or Lyrical | Humble EOL arrives in May 2027 |
Migration Checklist: Humble to Jazzy or Lyrical
Run these steps on a branch, one distro hop at a time.
# 1. Install the target distro in a clean container or VM
# 2. Rebuild your workspace against it
rosdep update
rosdep install --from-paths src --ignore-src -y
colcon build --symlink-install --event-handlers console_cohesion+
# 3. Run the test suite and surface warnings
colcon test --return-code-on-test-failure
colcon test-result --verbose
# 4. Check the environment for QoS, network, and package mismatches
ros2 doctor --report
Then work through the known breakage points:
| Area | Typical change | Action |
|---|---|---|
| Simulation | Gazebo version bump (Fortress → Harmonic or later) | Update SDF worlds and ros_gz bridge configs |
| ros2_control | Stamped velocity commands | Update cmd_vel publishers or set the controller’s stamped option |
| Launch files | Deprecated substitutions and arguments | Read the distro changelog; fix deprecation warnings |
| Custom messages | Rebuild required for IDL changes | Run a clean colcon build |
| C++ code | New compiler and standard defaults | Fix new warnings; adopt C++20 on Lyrical only when all targets support it |
Read the official Complete Changelog for each distro before you merge. Fix deprecation warnings on the old distro first, so each hop stays small.
Real-World Deployment Scenario: Mobile Robot Fleet
A team runs 12 differential-drive robots on Humble with Nav2, a 2D LiDAR, and an IMU. They need support past 2027. Their plan:
- Months 1–2: Build a Jazzy Docker image and run the existing stack in Gazebo Harmonic. Fix
cmd_velstamping and simulation assets. - Month 3: Deploy Jazzy to two test robots. Log
rosbag2data and compare path-tracking error against Humble baselines. - Months 4–5: Roll out to the fleet in batches, keeping the Humble image as a rollback.
- Later: Evaluate Lyrical when the robot computers move to Ubuntu 26.04, using the same container workflow.
The outcome is a predictable path with a rollback at every stage.
FAQ
Which ROS 2 distro is best for beginners?
Use Jazzy on Ubuntu 24.04 or Lyrical on Ubuntu 26.04. Both are LTS releases with current tutorials and long support windows. Avoid Kilted because its support ends in late 2026.
Is ROS 2 Humble still supported?
Yes. Humble is supported until May 2027. It still receives security and bugfix updates, but new features land in newer distros. Start migrating to Jazzy or Lyrical well before the EOL date.
What is the difference between ROS 2 LTS and non-LTS releases?
LTS releases ship in even-numbered years and get five years of support. Odd-year releases are supported for only 1.5 years. Choose LTS for products and fleets, and non-LTS only for experiments.
Can I run Lyrical on Ubuntu 24.04?
Only as a Tier 3 source build. Lyrical’s Tier 1 Linux platform is Ubuntu 26.04. On Ubuntu 24.04, use Jazzy for binary packages and official support.




