Blog
RTOS vs Bare Metal: Which One Should You Choose?
May 26, 2026
Bare metal is best for simple, single-task, resource-constrained systems where every microsecond and byte matters. RTOS is the right choice when your system manages multiple concurrent tasks, requires deterministic scheduling, or needs to scale over time. Read on to find out exactly where your project falls — and why getting this decision wrong costs teams years of technical debt.
Most embedded teams spend less time choosing their firmware architecture than they spend choosing lunch — then live with the consequences for five to ten years. This single decision shapes almost everything downstream: your hardware abstraction layer, your debugging workflow, which engineers you can hire, and how painful your next chip revision or component shortage will be.
Whether you're building an IoT sensor, a pacemaker, an automotive ECU, or an industrial robot, the wrong foundation doesn't just slow you down — it can make your system fundamentally unfit for purpose. This guide gives you the technical depth and practical framework to make the right call, with real-world context from the embedded engineering community as of 2025.
Bare metal programming means writing firmware that runs directly on the microcontroller hardware — no operating system, no abstraction layer beyond what you write yourself. Your code interacts with device registers, manages peripheral clocks, handles interrupts, and implements all scheduling logic from scratch.
The classic bare metal pattern is the super loop (or "infinite loop"): a main loop that polls peripherals and calls handler functions in sequence, with interrupt service routines (ISRs) handling time-critical events asynchronously.
// Classic bare metal super loop int main(void) { HAL_Init(); GPIO_Init(); UART_Init(); while (1) { read_sensors(); process_data(); update_outputs(); } }
This approach has powered billions of embedded devices across consumer electronics, appliances, and simple industrial controllers.
What bare metal is NOT: It doesn't mean writing every driver from scratch. Most modern bare metal projects use a vendor-provided Hardware Abstraction Layer (HAL) — such as STM32 HAL, ESP-IDF (without FreeRTOS), or Microchip's MCC — while still retaining direct control over task scheduling.
A Real-Time Operating System (RTOS) introduces a thin software layer between your application code and the hardware. That layer provides a preemptive, priority-based task scheduler that can pause one task and switch to another based on priority, timing, or events — all within microseconds.
Unlike a general-purpose OS (Linux, Windows), an RTOS is not designed to run many unrelated applications simultaneously. Its defining feature is determinism: guaranteed, predictable task execution within bounded time windows.
// FreeRTOS example: two concurrent tasks void sensor_task(void *pvParameters) { while (1) { read_and_process_sensor(); vTaskDelay(pdMS_TO_TICKS(10)); // run every 10ms } } void comms_task(void *pvParameters) { while (1) { send_data_over_uart(); vTaskDelay(pdMS_TO_TICKS(100)); } } int main(void) { xTaskCreate(sensor_task, "Sensor", 256, NULL, 2, NULL); xTaskCreate(comms_task, "Comms", 256, NULL, 1, NULL); vTaskStartScheduler(); }
| Attribute | Bare Metal | RTOS |
|---|---|---|
| Execution model | Super loop + ISRs | Preemptive multitasking |
| Determinism | Achievable with discipline | Built-in, guaranteed |
| Memory overhead | ~0 KB (just your code) | 5–50 KB (kernel + stacks) |
| CPU overhead | None | 1–5% for context switching |
| Task isolation | Manual | Automatic per-task stacks |
| Concurrency handling | Developer-managed | Built-in primitives |
| Debugging complexity | Simple | Requires RTOS-aware tools |
| Scalability | Poor (grows linearly) | Good (add tasks/priorities) |
| Learning curve | Low (for simple systems) | Moderate |
| Certification support | Manual process | SafeRTOS, INTEGRITY, etc. |
| Best for | Simple, single-task devices | Multi-task, time-critical systems |
This is where the debate gets nuanced — and where many engineers draw the wrong conclusions.
In a pure throughput benchmark on a constrained microcontroller, bare metal code will almost always edge out an RTOS-based equivalent. There's no scheduler tick, no context switch, no kernel overhead consuming your CPU. Every cycle goes to your application.
For very simple, single-function devices — a temperature sensor polling every second, a basic PWM controller — bare metal's zero-overhead advantage is real and relevant.
Here's the counterintuitive truth: for systems with multiple responsibilities, a well-configured RTOS can deliver better real-world responsiveness than bare metal.
In a bare metal super loop, a low-priority task (say, updating a display) can block a high-priority one (say, processing an alarm condition) simply because it runs first in the loop iteration. An event-driven RTOS with priority-based scheduling ensures that a high-priority task always preempts lower ones — regardless of where the loop pointer happens to be.
As the embedded community notes, using an event-driven RTOS instead of a polling-based super-loop architecture for large, complex embedded applications can result in a more efficient design, sometimes with a smaller effective memory footprint because you eliminate redundant polling code and state machines.
Modern RTOS kernels like FreeRTOS and Zephyr achieve context switch times in the sub-microsecond to single-digit microsecond range on ARM Cortex-M processors. For the vast majority of embedded applications, this is negligible. Where it matters is in hard real-time systems with sub-100 µs deadlines — and even there, a properly configured RTOS with interrupt-driven task activation can meet those requirements.
Memory is often the deciding factor on deeply embedded systems.
On an 8-bit or 16-bit microcontroller with 2–8 KB of RAM, bare metal isn't just a preference — it's often the only viable option.
As a general rule of thumb from experienced embedded engineers:
Note that each RTOS task has its own stack, so profiling stack usage is critical. RTOS-aware tools like SEGGER's SystemView or Percepio's Tracealyzer are invaluable here.
"Real-time" is one of the most misunderstood terms in embedded engineering. It does not mean "fast." It means predictable — a guarantee that a task will complete within a defined time bound.
Hard real-time: Missing a deadline is catastrophic. Examples include pacemaker pulse timing, automotive airbag deployment, fly-by-wire flight controls. A single missed deadline can cause physical harm or system failure.
Soft real-time: Missing a deadline degrades quality but doesn't cause failure. Examples include video streaming (dropped frames), audio processing (brief glitches), or UI updates.
Both bare metal and RTOS can support real-time constraints, but they achieve it differently:
One pitfall exclusive to RTOS environments is priority inversion — where a high-priority task is blocked waiting for a resource held by a low-priority task, while a medium-priority task runs instead. This is what famously caused the NASA Mars Pathfinder mission's recurring resets in 1997.
Modern RTOSes address this with priority inheritance protocols. Developers must understand concurrency hazards including deadlocks, priority inversion, and task starvation — these don't exist in bare metal but must be managed in any RTOS environment.
Getting started with bare metal is deceptively straightforward. You initialize peripherals, write a loop, handle interrupts. For a single developer building a simple device, this is the path of least resistance.
The complexity explodes as you add features. A bare metal project that manages three peripherals, a communication protocol, a display update, and a safety watchdog is not three projects in a loop — it's a carefully orchestrated state machine that's extremely hard to test, debug, and extend without breaking existing behavior.
The embedded community wisdom: Many embedded projects start with a super loop on bare metal and evolve into ad-hoc schedulers. If you're managing multiple peripherals, need background tasks (e.g., UART reception), or want predictable timing, it's often better to use an RTOS from the start.
An RTOS brings structure, but structure has a cost. Developers new to RTOS programming must understand:
RTOS-aware debuggers like SEGGER Ozone (with Cortex-M support) and Percepio Tracealyzer significantly reduce the debugging burden by providing task-level timeline visualization.
Teams that start bare metal and try to bolt on RTOS-like features later consistently report it as one of their most painful engineering experiences. Retrofitting task isolation, converting polling loops to event-driven architectures, and introducing synchronization primitives into an existing codebase almost always costs more than starting with an RTOS would have.
In battery-powered IoT devices, power efficiency isn't a feature — it's a requirement.
Bare metal gives you the finest-grained control over power states. You decide exactly when to enter sleep modes, what to wake the processor, and how long to stay in each power state. There's no scheduler tick consuming CPU cycles when nothing needs to happen.
For devices that do one thing every 30 seconds — wake, measure, transmit, sleep — bare metal's direct control over power modes can yield the absolute minimum power consumption.
The RTOS scheduler introduces a periodic tick interrupt (typically every 1 ms for FreeRTOS at default settings). This prevents the processor from staying in deep sleep during the tick interval. However, most modern RTOSes support tickless idle mode, which suppresses the tick when no tasks are ready to run, allowing the processor to stay in deep sleep until the next scheduled task.
With tickless idle enabled, the power consumption difference between bare metal and an RTOS is minimal in most real-world duty cycles. The RTOS itself consumes more resources — which means more active power — but during idle periods, the behavior converges.
Bottom line on power: For ultra-low-power single-function devices (think coin-cell sensors), bare metal's direct control is advantageous. For devices with multiple tasks and duty cycles, a properly configured RTOS with tickless idle is competitive.
Security in embedded systems has moved from an afterthought to a regulatory requirement, driven by legislation like the EU Cyber Resilience Act (2025) and NIST's embedded security frameworks.
Bare metal systems have a smaller attack surface by default — there's no OS layer with its associated vulnerabilities, no filesystem, no network stack unless you add one. A read-only flash image with no update mechanism is inherently difficult to compromise remotely.
However, bare metal also means no built-in security features. Memory protection, privilege separation, cryptographic APIs, and secure boot must all be implemented manually — a significant engineering burden.
Modern RTOS platforms increasingly ship with security-oriented features:
The critical caveat: the presence of security features doesn't guarantee security. Proper configuration, continuous monitoring, and regular updates are essential regardless of the chosen paradigm.
Simple IoT Sensors and Actuators A smart thermostat that reads a temperature sensor and controls a relay has no need for task scheduling. The polling interval is known, the workload is fixed, and every milliamp of idle current matters. This is bare metal's sweet spot.
Automotive ECUs (Engine and Brake) Counterintuitively, some of the most critical automotive embedded systems use bare metal. An engine control unit or brake ECU handles a precisely defined set of inputs and outputs with microsecond-level timing requirements. The determinism is achieved through hardware timing and ISR design, not software scheduling.
8-bit and 16-bit Microcontrollers A significant portion of the embedded world — devices using PIC, AVR, MSP430, and similar parts — doesn't have the memory headroom for an RTOS. These remain overwhelmingly bare metal. Companies like Microchip continue releasing new 8-bit devices because the market for simple, cheap, reliable controllers remains enormous.
Ultra-Low-Power Wearables Devices designed for multi-year coin-cell battery life, where the CPU wakes for milliseconds every few minutes, benefit from bare metal's zero-overhead idle behavior.
Automotive ADAS and Infotainment Advanced Driver Assistance Systems must simultaneously process camera feeds, radar data, GPS, and CAN bus communications — all with deterministic timing. RTOS is used widely in automotive ECUs, ADAS, infotainment, and diagnostics systems where real-time scheduling and functional safety are critical. AUTOSAR OS (based on OSEK) and platforms like INTEGRITY and QNX dominate here.
Medical Devices A patient monitor managing ECG acquisition, SpO2 measurement, alarms, display updates, and wireless transmission cannot afford priority inversion or missed deadlines. RTOSes with formal safety certification (SafeRTOS for IEC 62304) are standard in Class II and III medical devices.
Industrial Automation and Robotics Factory robots performing motion control while monitoring safety sensors, communicating with PLCs, and logging data require the concurrent task management that only an RTOS cleanly provides. Micrium OS and VxWorks are trusted workhorses in industrial automation.
IoT Gateways and Smart Home Devices Devices managing multiple wireless protocols (Bluetooth LE, Wi-Fi, Thread, Zigbee) and handling concurrent connections from multiple endpoints need the concurrency model an RTOS provides. Zephyr has become particularly popular here, with native support for Bluetooth LE, Thread, Wi-Fi, and Matter.
Aerospace and Defense VxWorks is trusted in aerospace, defense, and other safety-critical systems requiring high certification standards such as DO-178C Level A.
Not all RTOSes are equal. Here's an honest overview of the major options you'll encounter:
Best for: Teams wanting a lightweight, flexible kernel with minimal opinions Maintained by: Amazon Web Services (since 2017) Key facts: Open-source, MIT licensed. The most widely deployed RTOS kernel in the embedded world. Provides just the scheduling core — no device driver framework, no standardized project structure. This makes it lean and flexible but means two FreeRTOS projects at the same company can look completely different. FreeRTOS Plus extensions add TCP/IP, filesystem, and OTA update support.
Best for: Industrial applications requiring modularity and determinism Key facts: Industrial-grade with a modular architecture. Available from Silicon Labs. Strong in factory automation and process control applications.
Best for: Aerospace, defense, high-reliability systems Key facts: The gold standard for safety-critical real-time systems. Proprietary, with extensive safety certifications. Used in Mars rovers, F-35 avionics, and medical imaging systems. Commercial licensing makes it expensive for commercial IoT products.
Best for: Medical devices, automotive ASIL applications Key facts: Derived from FreeRTOS but independently verified and certified. Holds IEC 61508 SIL 3, ISO 26262 ASIL D, and IEC 62304 Class C. The go-to choice when regulatory certification is non-negotiable.
Best for: Azure IoT ecosystem integration Key facts: Well-optimized with a strong networking stack. Worth evaluating if your IoT backend is Azure-based.
Stop looking at comparison tables — they tell you what each option is, not which one fits your project. Here's a practical decision framework used by experienced embedded teams:
List every distinct thing your system must do. If the answer is one thing (or one thing at a time in a predictable sequence), bare metal is likely sufficient.
If the answer involves tasks that must happen simultaneously or at independent rates — sensor acquisition every 1ms, display update every 16ms, network transmission every 100ms, watchdog refresh every 500ms — you need task management. An RTOS gives you that cleanly.
Solo developer, one-off product, 6-month lifespan? Bare metal's simplicity serves you well.
Team of 3+, product with 5-year support lifecycle, multiple hardware revisions planned? An RTOS pays dividends in maintainability, portability, and the ability to onboard new engineers who understand RTOS concepts better than bespoke super-loop state machines.
| Your Situation | Recommendation |
|---|---|
| One task, fixed timing | Bare Metal |
| Simple sensor/actuator, battery-powered | Bare Metal |
| 2+ independent tasks with different rates | FreeRTOS |
| Complex IoT with BLE/Wi-Fi/Matter | Zephyr |
| Industrial/automotive, safety-critical | SafeRTOS / VxWorks |
| Aerospace / defense | VxWorks / INTEGRITY |
| Azure IoT backend | Eclipse ThreadX |
| Starting bare metal, considering migration | Start RTOS now |
Mistake 1: Starting bare metal "to keep it simple" on a complex product If you anticipate more than two independent workloads, budget for an RTOS from day one. Retrofitting task scheduling into mature bare metal code is one of the most expensive refactors in embedded engineering.
Mistake 2: Picking an RTOS without profiling stack sizes Each RTOS task has its own stack. Undersizing a stack causes silent memory corruption that manifests as intermittent, hard-to-reproduce bugs. Always use your RTOS's stack high-watermark APIs during development.
Mistake 3: Calling blocking RTOS APIs from ISRs Most RTOS APIs have separate "FromISR" variants for use in interrupt context. Calling the standard API from an ISR is undefined behavior in most RTOSes and a common source of crashes.
Mistake 4: Misusing mutexes and semaphores A mutex held too long creates priority inversion. A semaphore used where a mutex is needed creates unbounded blocking. Understanding the difference — and using each correctly — is fundamental to RTOS proficiency.
Mistake 5: Ignoring tickless idle on battery-powered RTOS devices The default 1ms tick interrupt prevents deep sleep. Enable tickless idle (configUSE_TICKLESS_IDLE = 1 in FreeRTOS) or Zephyr's power management subsystem to achieve real low-power performance.
Mistake 6: Choosing based on what your MCU vendor bundles "Our MCU vendor bundles FreeRTOS, so I guess we're using FreeRTOS" is not a strategy. Evaluate Zephyr if your product needs multi-protocol connectivity, long-term maintenance, or portability across hardware generations.
After synthesizing technical benchmarks, real-world engineering experience, and the current state of the embedded ecosystem in 2025, here is a clear-eyed verdict:
Choose bare metal when: your device has a single, well-defined function; resources are severely constrained; power consumption is critical and workloads are completely predictable; or you need the absolute minimum code complexity with no external dependencies.
Choose an RTOS when: your system manages two or more concurrent tasks with independent timing; you need deterministic scheduling without hand-crafting a scheduler; your team will grow or your product will evolve; or you're targeting a safety-regulated domain where a certified RTOS reduces qualification burden.
The most important insight: Bare metal and RTOS are not opposites — they're points on a spectrum. FreeRTOS is described by many engineers as "essentially an extensible scheduler rather than a full OS" — it's almost bare metal with structured task management bolted on. Zephyr is a full embedded platform. Embedded Linux is above that. Choose the point on the spectrum that matches your system's complexity today and its likely growth over its lifetime.
The embedded engineers who consistently ship on time are not the ones who make the "perfect" architectural choice — they're the ones who make an intentional one, early, and then build consistently within that foundation.
Yes. Many multi-core microcontrollers (like the STM32H7 dual-core series or Nordic nRF5340) run an RTOS on the application core and bare metal on the secondary core for time-critical peripheral handling. This is a common architecture in high-performance embedded products.
Yes. FreeRTOS is MIT licensed, meaning there's no royalty or attribution requirement for commercial products. This has been the case since Amazon rewrote the license in 2018.
A minimal Zephyr configuration targeting Cortex-M4 with just the kernel and UART logging typically compiles to around 20–30 KB of flash. Enabling Bluetooth LE or Wi-Fi adds significantly more.
No — but it can simulate it with cooperative scheduling, state machines, and careful interrupt design. The difference is that the developer bears full responsibility for ensuring correctness, which becomes exponentially harder as complexity grows.
FreeRTOS remains the most widely deployed RTOS by total device count. Zephyr is the fastest-growing by contributor activity and is increasingly preferred for new commercial IoT products. VxWorks and QNX dominate aerospace, defense, and automotive safety.
Arduino is a hardware abstraction framework. Most Arduino boards run bare metal (though the ESP32 Arduino port runs on top of FreeRTOS). Arduino's simplicity is its strength for prototyping and learning, but it has significant limitations for production IoT systems — single-threaded by default, limited real-time guarantees, and no formal support for concurrency.
When your system needs a rich UI, multimedia processing, a full networking stack (HTTPS, MQTT, etc.), OTA updates with a signed bootloader, a filesystem, or the ability to run general-purpose applications. Embedded Linux requires an MMU-capable processor (typically Cortex-A series), a minimum of 32–64 MB RAM, and a bootloader (U-Boot). It's the right choice for IoT gateways, smart displays, and edge computing nodes — not for simple sensor nodes or control loops.
The embedded systems market is growing from $110.3 billion to an estimated $190 billion by 2032, driven largely by IoT expansion across automotive, industrial, medical, and consumer segments. As devices grow more connected and complex, the pressure to choose the right firmware architecture early — and to choose intentionally — has never been higher.
Don't let your toolchain, your MCU vendor's bundled SDK, or a Hacker News comment make this decision for you. Use the framework in this article, prototype on your actual target hardware, and choose the foundation that your system — and your team — can grow within.