WARNING — Alpha software, read for awareness, not for production. Everything in this chapter describes OWL 3, a version currently published as
3.0.0-alpha.45in the odoo/owl repository. The official design document says outright: "the design is still a work in progress." There is no stable release date. Nothing here should be used in a real project today — the APIs you learned in the rest of this book (OWL 2.0) are what ships in current Odoo versions, including Odoo 19. This chapter exists so that, when OWL 3 does arrive, none of it surprises you.Why this chapter? Because the OWL you've just spent seventeen chapters mastering is not the end state — a major rewrite is already underway, and knowing its shape now means you won't have to relearn everything from scratch later. What is Odoo trying to solve with this? OWL 2.0's reactivity is tied to component instances in a way that limits how state can be shared, derived, or observed outside a render cycle — OWL 3 is a ground-up rework meant to remove that limitation. Real-world application: None yet, and that's the point — this is preparation, not a technique to bring into a client project. The realistic application today is recognizing the vocabulary (signals, Plugins,
useProps()) when it starts showing up in release notes, so a future migration isn't a surprise.
Every framework eventually rewrites the parts of itself that turned out to be limiting. React did it going from class components to hooks. Vue did it going from Options API to Composition API. OWL is now doing something similar with its reactivity system — and the ripple effects touch props, services, lifecycle hooks, and even the template compiler.
This chapter is a guided tour of the biggest changes, based directly on OWL's own design document and draft migration guide in the odoo/owl repository. Think of it as a preview, not a tutorial — you won't build anything here, you'll just learn to recognize what's coming.
Why a New Major Version?
In OWL 2.0, reactivity is built on useState, which wraps an object in a Proxy (Chapter 7). That proxy is tied to the component that created it: OWL tracks "this component read this property, so re-render it when the property changes." It works well, but it has a structural limit — reactive values are hard to share, compute, or observe outside of a component's render cycle.
OWL 3 rebuilds reactivity around signals: small reactive containers that are not tied to any particular component. Anything that reads a signal — a component's render, a computed value, an effect — automatically subscribes to it, regardless of where that code lives. That single change is the root of almost everything else in this chapter.
The Reactivity Model: From Proxies to Signals
Where OWL 2.0 gives you useState() and reactive(), OWL 3 gives you four building blocks:
signal(value)— a single reactive value, read/write.proxy(object)— the closest equivalent to today'suseState()/reactive(): an object whose properties are each backed by a signal.computed(() => ...)— a derived value that recalculates automatically when the signals it reads change, and is cached until then.effect(() => ...)— runs a callback whenever the signals it reads change (similar in spirit touseEffect, but not tied to a component).
// OWL 2.0 (this book)
setup() {
this.state = useState({ count: 0, step: 1 });
}
// OWL 3 (alpha)
setup() {
this.state = proxy({ count: 0, step: 1 });
this.doubled = computed(() => this.state.count * 2);
}
What this replaces: the pattern from Chapter 7 where you'd compute a derived value inline in the template, or recompute it on every render inside a getter. computed() caches the result and only recalculates when its actual dependencies change — closer to how memoization (Chapter 8) works, but automatic.
Props and Environment: A New Injection Model
This is the change with the widest blast radius. In OWL 2.0, every component automatically receives this.props and this.env (Chapters 8 and 11). In OWL 3, both are removed as implicit component members.
Props are declared explicitly with useProps() and a validator built from the t helper:
// OWL 2.0 (this book)
static props = { name: String, age: { type: Number, optional: true } };
// OWL 3 (alpha)
setup() {
this.props = useProps({
name: t.string(),
age: t.number().optional(0),
});
}
this.env and the whole services layer (useService, Chapter 13) are replaced by a Plugin system: instead of a global environment object that any component can pull services out of, you define a Plugin class and explicitly declare which components depend on it.
// OWL 3 (alpha) — sketch, API still moving
class OrmPlugin extends Plugin { /* ... */ }
setup() {
this.orm = usePlugin(OrmPlugin);
}
Why this matters for you: everything Chapter 13 taught about useService("orm"), useService("notification"), and so on maps conceptually to "inject a Plugin" in OWL 3 — the pattern (declare a dependency, don't reach for a global) survives, but the API is completely different.
Lifecycle Changes
Three changes here directly affect hooks you already know from Chapter 10:
onWillUpdatePropsis removed, with no direct replacement. Depending on what you were doing with it, the migration guide points you towardcomputed()(if you were deriving state from props),useEffect()(if you were running a one-off side effect), or a newasyncComputed()hook (if you were loading data based on a prop — the prop has to be a signal for this to work).onPatched/onWillPatchbecome stricter. In OWL 2.0, these fire when any descendant re-renders, including through a slot. In OWL 3, they only fire when the component itself re-renders — a descendant's re-render no longer bubbles up to it.this.render(),onWillRender, andonRenderedare removed outright, with no direct replacement listed yet.
Template Compiler Changes
A few changes affect how you write QWeb templates:
- No more implicit free variables. In OWL 2.0 you can write
t-on-click="onClick"and OWL resolvesonClicktothis.onClick. OWL 3 requires the explicitthis.:t-on-click="this.onClick". t-escis removed. Uset-outfor everything — in OWL 3,t-outhas been extended to safely handle plain values as well as markup, so it covers whatt-escused to do (Chapter 6).t-refandt-modelnow take a signal, not a string. In OWL 2.0 you writet-ref="myRef"and readthis.myRef.el; in OWL 3 the ref itself is a signal you create and pass in.t-slotis renamed tot-call-slot. The rename is meant to make it clearer that this directive inserts a slot's content, as opposed tot-set-slot, which still defines what a slot receives (Chapter 14).
Events
useExternalListener (the hook you'd use to listen on window or document with automatic cleanup) is renamed to useListener. Functionally it's the same idea: attach a listener that gets removed for you when the component unmounts.
t-on-* directives also gain a new .passive modifier for performance-sensitive listeners like scroll or touchmove — it tells the browser the handler will never call preventDefault(), which lets the browser optimize scrolling. It's mutually exclusive with .prevent for the same reason.
What's Being Removed Without a Direct Replacement
A short list of things this book covers (or that exist in OWL 2.0) that the migration guide currently lists as gone, with no 1:1 replacement yet documented:
t-portal(rendering outside the component tree)useComponent()(the low-level hook for accessing the current component instance)loadFile
If you build something with these today, know that a future OWL 3 migration will require rethinking that part of the code, not just search-and-replacing an API name.
Current Status and Timeline
As of this writing, odoo/owl is publishing alpha pre-releases (the latest at research time was 3.0.0-alpha.45) from a master branch that has already been restructured into separate packages (owl-core, owl-compiler, owl-runtime, owl). The owl3_design.md document itself states the design is still evolving, and there is no announced date for a stable 3.0.0. Odoo's own codebase (the saas-19.4 branch) already has commits vendoring OWL 3 alpha builds — a sign that internal testing is underway — but that is not the same as OWL 3 being ready for addon authors.
Should You Learn OWL 3 Now?
Not for production work — not yet. Everything you built in this book's examples and the companion example addons is OWL 2.0, and that's what every currently supported Odoo version runs, including Odoo 19. Treat this chapter as a map of where the concepts are heading, so that terms like "signals," "Plugins," and useProps() won't be unfamiliar when they show up in release notes or blog posts.
If you want to go deeper once you're comfortable with everything in Chapters 1–17, the primary sources are:
- doc/v3/owl/owl3_design.md in the odoo/owl repository (the design rationale)
- doc/v3/owl/migration_owl2_to_owl3.md in the same repository (the practical, breaking-change-by-breaking-change migration guide)
Both are living documents — expect them to change before OWL 3 stabilizes.
Summary
OWL 3 is a ground-up rework of OWL's reactivity system, moving from component-bound proxies (useState) to standalone signals (signal, proxy, computed, effect). That single shift cascades into how props are declared (useProps() instead of static props), how services are injected (a Plugin system instead of env/useService), which lifecycle hooks exist (onWillUpdateProps gone, onPatched/onWillPatch stricter), and even small template syntax rules (explicit this., t-esc gone, t-slot renamed to t-call-slot). All of it is still alpha and explicitly a work in progress — read this chapter to recognize the shape of what's coming, not to start building with it.
TL;DR: OWL 3 is still alpha (3.0.0-alpha.45, no stable date) and rebuilds reactivity around signals, replacing useState/props/services/several hooks along the way — read this chapter for awareness, not to start building with it.
What's Next?
There's no next chapter — this is the end of the book. The best next step is to go back and put Chapters 1 through 17 to work: build something real with the example addons, break it, fix it, and let that be how OWL 2.0 actually sticks. When you're curious about OWL 3 again, doc/v3/owl/ in the odoo/owl repository is where the design keeps evolving.
End of Chapter 18 End of "OWL 2.0: Where Odoo Ends and You Begin"