Key takeaways
- The choice is made by the use case, not by preference. Ask how fast the decision must be, where the data comes from, and which interface carries the action.
- rApps run in the Non-RT RIC on the SMO, work on a time scale of seconds to hours, and act through O1, O2 and A1 policies. xApps run in the Near-RT RIC, work between 10 ms and 1 s, and act through E2.
- Many use cases end up as a pair: an rApp that sets the goal and an xApp that executes it. A1 is the seam between them.
- If a decision does not need to be fast, put it in an rApp. The slower loop is easier to build, test and reason about.
Two homes for the same idea
Almost every RAN optimization idea can be described in one sentence: observe something, decide something, change something. O-RAN gives that sentence two places to live. An rApp runs in the Non-RT RIC, inside the Service Management and Orchestration framework. An xApp runs in the Near-RT RIC, close to the RAN nodes.
The names suggest that the only difference is speed. Speed is the first filter, but it is not the only one. The data you can see, the actions you can take and the way the application is deployed and tested are all different. This post walks through the questions that settle the choice.
Question one: how fast must the decision be
The Non-RT RIC hosts control loops of one second or longer. In practice most rApp loops run on minutes or hours, because the performance data they consume arrives over O1 in granularity periods measured in minutes. The Near-RT RIC hosts loops between 10 ms and 1 s, fed by E2 indications that can be reported at millisecond intervals.
So the first question is simple. If the network state that matters changes within a second, and the reaction must follow within a second, you are in xApp territory. Handover decisions for individual UEs, per-flow resource allocation and interference reactions are examples. If the state changes over minutes, such as the load pattern of a cell, the health of a node or the energy profile of a site, an rApp is the natural home.
A warning applies to the middle ground. An rApp that tries to react within a few seconds is fighting its own data pipeline. An xApp that only needs to act every ten minutes is paying for a fast platform it does not use, and it has to carry the state and history that the Non-RT RIC would have given it for free.
Question two: where does the data come from
An rApp sees the network through R1 services. The data management and exposure functions deliver performance and fault data collected over O1, topology and inventory information, data from other rApps, and anything the SMO integrates from outside the RAN, such as weather, energy prices or planned events. The Non-RT RIC also offers AI/ML workflow services for training and model management.
An xApp sees the network through E2. It subscribes to RAN functions that the E2 node advertises, using service models such as E2SM-KPM for measurements and E2SM-RC for control. The view is detailed and current, but it is limited to what that node reports and to the Near-RT RIC's own analytics. Wider context reaches the xApp only as A1 enrichment information from the Non-RT RIC.
The practical test: list the inputs your decision needs and mark each one as O1, E2 or external. Mostly O1 and external points to an rApp. Mostly E2 points to an xApp. A mix points to a pair, which we come back to.
Question three: what action does the decision take
rApps act through configuration and guidance. A configuration change, such as adjusting a cell parameter, switching a carrier off or reconfiguring measurement collection, goes through the RAN OAM services on R1 and is applied over O1. Guidance to the fast loop goes out as an A1 policy. rApps can also drive O2 for cloud resources, for example scaling a CU deployment.
xApps act through E2 control and E2 policy. They can move a UE to another cell, change bearer parameters, or install a rule that the node applies by itself when a trigger fires. These actions land on the live traffic immediately.
This sets a boundary. An action that is an O1 configuration change belongs to an rApp, whatever the input was. A per-UE control action belongs to an xApp. The interfaces do not offer a way around this, and a design that needs one is usually a sign that the use case has two halves.
Question four: what happens when it is wrong
Every automated decision will sometimes be wrong. The two loops differ in how much damage a wrong decision does and how easily it is caught.
An rApp decision is slow, visible and reversible. It typically passes through SMO processes, can be reviewed, and its effect shows up in the next round of performance data. Operators often run new rApps in a recommendation mode first, where a human approves each change.
An xApp decision hits live sessions before anyone sees it. The Near-RT RIC includes conflict mitigation and subscription management to reduce the risk, but the application itself must be correct under all the conditions it can meet. That means heavier testing, careful handling of E2 subscription failures, and thought about what the node does if the xApp stops responding.
If the use case can tolerate a slow reaction, this question alone often decides it. The slow loop is the safer place to learn.
The common answer: both
Many mature use cases split naturally. Take traffic steering. The rApp watches load, quality and subscriber intent over minutes and decides that a group of UEs should prefer one carrier or avoid a cell. It writes that as an A1 policy. The xApp receives the policy, watches per-UE measurements over E2 and performs the actual handovers to satisfy it.
Energy saving follows the same shape. The rApp decides which cell can sleep and when, based on forecasts and O1 data. The xApp clears the cell of remaining UEs. The rApp then switches the cell off over O1. QoE optimization, slice assurance and interference management can all be drawn the same way.
The rule of thumb: the rApp owns the goal and the long memory, the xApp owns the execution and the short reaction. A1 is the seam. If you find yourself writing a single application that needs both a training pipeline and a 50 ms reaction time, you are probably writing two.

A short worked example
Consider the question of where to collect Minimization of Drive Tests data. The inputs are coverage estimates, model uncertainty and collection cost, all of which evolve over hours. The action is a trace and MDT configuration, which is an O1 management operation. Nothing here needs a sub-second loop. This is an rApp, and trying to place it in an xApp would give it neither the data nor the interface it needs.
Now consider protecting a latency-critical slice when a cell becomes congested. The input is per-UE and per-slice throughput reported over E2 within the second. The action is a resource control or a handover. This is an xApp. An rApp can still sit above it, setting the slice priority as an A1 policy, but the reaction itself has to live in the Near-RT RIC.
A checklist
Before you start building, write down four answers. The time scale of the decision. The interface each input arrives on. The interface the action leaves on. The cost of a wrong decision and how you would catch it.
If all four line up on the slow side, build an rApp. If all four line up on the fast side, build an xApp. If they split, design the pair and define the A1 policy between them first, because that contract is what both halves will be tested against.
The relevant specifications are the O-RAN WG1 Architecture Description for the control loops, the WG2 Non-RT RIC and R1 documents for rApps, the WG3 Near-RT RIC architecture and E2 documents for xApps, and the WG2 A1 policy type definitions for the seam between them. All are available from the O-RAN ALLIANCE website.

