Every embedded project we join eventually hits the same meeting. Someone opens a whiteboard, writes "RTOS?" at the top, and the room splits into three camps: the person who has shipped FreeRTOS four times and sees no reason to change, the person who read about Zephyr and wants the driver model, and the person quietly insisting the whole thing runs fine in a superloop. All three are sometimes right. That is what makes the decision harder than it looks.
So let's do this properly. Not a feature matrix scraped from four project websites, but the actual trade-offs that show up six months into development — when your flash budget is tight, your BLE stack wants its own thread, and someone from compliance asks whether your kernel has a certification artifact. This is the conversation we have with clients before a single line of firmware gets written.
Start by asking whether you need an RTOS at all
A real-time operating system buys you one thing above all else: the ability to write concurrent code as if each activity had the CPU to itself. If your product has two or three activities that genuinely need to run independently and block on different events, that is worth a lot. If it doesn't, you are paying kernel overhead and debugging complexity for a convenience you won't use.
Bare-metal with a well-structured event loop and a state machine per subsystem is still the correct answer for a large class of products. We reach for it when:
- The device does one thing on a fixed cadence — sample, process, transmit, sleep — and the timing is deterministic by construction.
- Flash and RAM are measured in single-digit kilobytes and every byte is contested.
- The certification path is easier to argue when there is no scheduler to reason about, only a single flow of control.
- The team is small and long-term maintenance matters more than architectural elegance.
- Power budget is dominated by sleep, and you want absolute control over when the core wakes.
Where bare-metal breaks down is protocol stacks. The moment you add a networking stack, a BLE host, USB device classes, or a filesystem, you inherit code that was written assuming it can block. You can drive some of these from an event loop, but you will spend your time fighting the library's assumptions rather than building your product. That is usually the signal that an RTOS has become the cheaper option.
FreeRTOS: the default that is hard to argue with
FreeRTOS is a kernel, not a platform. That is both its greatest strength and the source of most complaints about it. You get tasks, queues, semaphores, mutexes, timers, event groups, and a tickless idle mode. You do not get drivers, a device tree, a build system, or a networking stack unless you add them — and the vendor SDK you're already using probably supplies those.
It is small. A minimal kernel footprint typically lands in the range of a few kilobytes of flash, with per-task RAM cost being roughly your stack allocation plus a small task control block. That makes it viable on parts where heavier options simply don't fit.
It is also everywhere. Virtually every silicon vendor ships a FreeRTOS port in their SDK, usually pre-integrated with their HAL and their middleware. When something goes wrong at 2am, the odds that someone has hit your exact problem and written about it are very high. For a commercial team, that ecosystem depth is a real engineering cost saving, not a soft benefit.
The honest downsides: the scheduler is straightforward priority-based preemption with optional round-robin at equal priority, which is fine for most work but gives you no help with more sophisticated scheduling policies. Portability across vendors is at the kernel level only — move from one MCU family to another and you rewrite the driver layer entirely. And because it is a kernel rather than a platform, architectural discipline is your responsibility. We have inherited FreeRTOS codebases with fourteen tasks, most of which existed because a task felt like the natural place to put a function.
Zephyr: a platform, with the costs a platform brings
Zephyr is a different proposition. It gives you a preemptive kernel with cooperative and preemptive thread classes, but around it sits a device tree, a Kconfig-driven build system, a unified driver model, a POSIX-ish subsystem, power management infrastructure, a networking stack, Bluetooth host and controller, filesystems, logging, shell, settings storage, and device firmware update support. It behaves less like a kernel and more like a small Linux-influenced operating system for microcontrollers.
That pays off when hardware abstraction genuinely matters to you. If you expect to ship the same firmware across two or three MCU families, or you know a supply chain problem might force a part swap mid-programme, Zephyr's driver model and device tree mean the change is a board file and a rebuild rather than a port. In the years since the semiconductor shortage, we have seen that argument win more meetings than any technical feature.
The cost is learning curve and build complexity. Device tree overlays, Kconfig fragments, and the west tool are not intuitive on day one. Expect a genuine ramp for a team new to it — measured in weeks, not days, before people are productive rather than merely functional. Footprint is configurable and can be trimmed hard, but a realistic build with Bluetooth and DFU is not going to fit where a lean FreeRTOS build would. And the project moves quickly; pinning a release and planning your upgrade cadence deliberately is not optional.
We recommend Zephyr most often for connected products with a multi-year roadmap, where the up-front investment amortises across features you know are coming.
ThreadX and the commercially supported tier
ThreadX — now under the Eclipse Foundation as Eclipse ThreadX, after Microsoft's Azure RTOS was contributed to open source — sits in a different category again. Its historic appeal was a compact, deterministic kernel with a coherent middleware family around it: a networking stack, USB host and device, a FAT-compatible filesystem, and a GUI library, all designed together rather than bolted together.
Its other historic appeal was pre-certification evidence for safety standards, which matters enormously in medical, industrial, and transport work. If you are heading toward IEC 61508, ISO 26262, IEC 62304, or DO-178C, buying a kernel that already has assessment artifacts can remove a substantial slice of qualification effort from your schedule.
The critical thing to verify in 2026 is what the governance change means for your specific certification path. Certification evidence is tied to specific versions, toolchains, and support arrangements. Do not assume a historic certificate transfers to the version you pull from a repository today. Ask, in writing, before you commit. The same caution applies to SAFERTOS, which is the commercially certified sibling to FreeRTOS and a very reasonable route if you like the FreeRTOS programming model but need the paperwork.
The technical criteria that actually decide it
Once you have narrowed to two candidates, these are the questions worth spending real time on. In our experience they matter far more than tick-box feature comparisons.
Latency determinism, not raw speed
Every mainstream RTOS is fast enough. What you care about is worst-case interrupt latency and worst-case context switch time, and whether those numbers are bounded and measurable on your part with your compiler settings. Measure them yourself on target hardware. Published figures are best-case, on a specific core, with caches in a specific state.
Priority inversion handling
If two tasks of different priority share a resource, you need mutexes with priority inheritance, and you need to understand exactly what your kernel implements. This is the single most common source of intermittent, impossible-to-reproduce timing bugs we get called in to diagnose.
Memory model and static allocation
For anything safety-adjacent, you want the option to allocate every kernel object statically at compile time. Both FreeRTOS and Zephyr support this. Verify that your middleware does too — a kernel with static allocation and a networking stack that calls malloc at runtime has not solved your problem.
Power management integration
Battery products live or die here. Tickless idle is table stakes; what you need to check is how well the RTOS power subsystem cooperates with your MCU's low-power modes and peripheral clock gating, and whether the vendor's port actually implements the deep sleep states you budgeted for. This is a frequent source of nasty surprises late in a project.
Debug and observability tooling
Thread-aware debugging, kernel event tracing, and stack high-water marking will save you more calendar time than any performance difference between kernels. Check that your debugger, your trace tool, and your RTOS actually work together on your silicon before you commit.
Security and update path
Regulatory pressure on connected device security keeps rising — the EU Cyber Resilience Act being the obvious driver for anyone shipping into Europe. You need a secure boot story, a signed firmware update mechanism with rollback, and a maintainable software bill of materials. Zephyr's integration with MCUboot gives you a well-trodden path here. With a kernel-only choice, you are assembling that yourself or leaning on the vendor SDK.
A decision path we actually use
Simplified, but this is close to how the conversation goes:
- Is the behaviour a single deterministic loop with no blocking third-party stacks? Ship bare-metal. Revisit only if requirements change.
- Are you certifying to a functional safety standard? Start with the commercially supported, pre-assessed kernels and let that constraint drive the rest of your architecture. Retrofitting certification is far more expensive than designing for it.
- Is your product connected, multi-year, and likely to span more than one MCU family? Zephyr, and budget the ramp-up honestly.
- Are you on a single well-supported vendor part with a mature SDK, a firm timeline, and a team that already knows the tooling? FreeRTOS. It is the pragmatic choice and there is no shame in it.
- Do you have hard multi-core, MMU, or full Linux userspace requirements? You are past RTOS territory — consider embedded Linux, or a hybrid where a Cortex-M core runs an RTOS alongside an application core running Linux.
One thing that is not on this list: developer preference. It should be. A team that is fluent in one RTOS will ship a better product on it than on a technically superior alternative they are learning as they go. If the constraints don't force your hand, let experience decide. If you need to add that experience quickly, a dedicated engineering team that has already made these mistakes on someone else's schedule is usually cheaper than making them on yours.
Where the decision meets the rest of the system
Embedded choices ripple outward. Your RTOS shapes how easily you can add on-device inference later — if you are planning quantised models on an MCU, check the thread and memory model you will need for your inference runtime before you finalise the kernel, not after. We spend a lot of time at that boundary between firmware and AI and ML development, and the projects that go smoothly are the ones where someone thought about the memory arena in month one.
The same is true of your data path. How the device buffers, batches, and retries telemetry is a firmware decision with consequences for your cloud bill and your support burden. Decide it early, with someone who understands both ends. You can see the kinds of systems we have built end to end in our work.
If you are at the whiteboard stage on a new product and want a second opinion from people who have shipped on all of these, get in touch. Bring your constraints — flash budget, certification target, timeline, team experience — and we will tell you honestly which way we would go, including when the answer is the simple one you already suspected.