Ad – 728×90
🦉 Getting Started

Setting Up OWL JS – Three Ways to Get Started

OWL JS is flexible — you can run it with zero tooling (a single HTML file) or with a full modern dev stack (npm + Vite + hot reload). This lesson walks you through all three approaches so you can pick the right one for your situation. Recommendation for learning: start with Approach 1 (CDN, no tools) to get OWL running in under 5 minutes, then move to Approach 2 or 3 when you are ready to build real projects.

⏱️ 15 min read 🎯 Beginner 📅 Updated 2026

Which Setup Should You Choose?

ApproachSetup timeTools neededBest for
1. Single HTML file (CDN) ~2 min Text editor + browser Quick experiments, first lesson, zero-friction start
2. Static server (ES modules) ~10 min Text editor + Node.js (optional) Multi-file projects without a build step
3. npm + Vite project ~15 min Node.js + npm + terminal Real projects, hot reload, production builds, testing
💡
For this course: start with Approach 1

All examples in the early lessons of this course run with the single-file CDN setup. You do not need Node.js or npm installed to follow along. When you reach the projects section, the Approach 3 setup will be recommended.

Approach 1 – Single HTML File (CDN, No Tools Required)

This is the fastest way to run OWL JS. Download the OWL bundle from the GitHub releases page and include it with a <script> tag, or use jsDelivr CDN directly. No npm, no Node.js, no terminal commands.

File structure

Directory structure
hello_owl/
  index.html
  app.js

index.html

HTML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Hello OWL JS</title>
  <!-- Load OWL JS from CDN (IIFE build — exposes global 'owl') -->
  <script src="https://cdn.jsdelivr.net/npm/@odoo/owl/dist/owl.iife.js"></script>
</head>
<body>
  <!-- OWL will mount into this div -->
  <div id="app"></div>

  <!-- Load your app code AFTER OWL -->
  <script src="app.js"></script>
</body>
</html>

app.js

JavaScript
// 'owl' is available as a global variable (loaded by the CDN script)
const { Component, mount, xml, useState } = owl;

class App extends Component {
  state = useState({ count: 0 });

  static template = xml`
    <div style="font-family: sans-serif; padding: 2rem; text-align: center;">
      <h1>Hello OWL JS! 🦉</h1>
      <p style="font-size: 2rem; margin: 1rem 0;">
        Count: <strong><t t-esc="state.count"/></strong>
      </p>
      <button t-on-click="() => state.count++"
              style="margin: 0.5rem; padding: 0.5rem 1.5rem; font-size: 1rem;">
        + Increment
      </button>
      <button t-on-click="() => state.count--"
              style="margin: 0.5rem; padding: 0.5rem 1.5rem; font-size: 1rem;">
        - Decrement
      </button>
      <button t-on-click="() => state.count = 0"
              style="margin: 0.5rem; padding: 0.5rem 1.5rem; font-size: 1rem;">
        Reset
      </button>
    </div>
  `;
}

// Mount the App component into the #app div
mount(App, document.getElementById("app"));
▶ Result in browser
Open index.html in any modern browser. A heading, counter display, and three buttons appear. Clicking the buttons updates the counter in real time — no page refresh.
⚠️
Open index.html via a web server, not directly from the filesystem

If you double-click index.html to open it (the URL starts with file:///), the CDN script loads fine because it is an external URL. However, once you split your code across multiple files and use ES modules (type="module"), browsers block module imports over file:// for security. Use a local web server (see Approach 2) instead.

Approach 2 – Static Server with ES Modules

This approach uses native JavaScript modules (import/export) to split your code across multiple files without a build step. You need a simple local HTTP server — browsers refuse to load ES modules over file://.

File structure

Directory structure
hello_owl/
  index.html
  main.js         ← entry point
  src/
    App.js        ← root component
    Counter.js    ← sub-component

Starting a local server

Shell
# Option A: Python (installed by default on macOS and most Linux)
python3 -m http.server 8080
# Visit http://localhost:8080

# Option B: Node.js (if you have npm)
npx serve .
# Visit the URL it prints

# Option C: VS Code Live Server extension
# Right-click index.html → "Open with Live Server"

index.html

HTML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>OWL JS App</title>
</head>
<body>
  <div id="app"></div>
  <!-- type="module" enables ES module imports -->
  <script src="main.js" type="module"></script>
</body>
</html>

main.js (entry point)

JavaScript
// Import OWL from a local file or CDN as ES module
// Using CDN skypack which serves OWL as an ESM
import { mount } from "https://cdn.skypack.dev/@odoo/owl";
import { App } from "./src/App.js";

mount(App, document.getElementById("app"));

src/App.js

JavaScript
import { Component, xml, useState } from "https://cdn.skypack.dev/@odoo/owl";
import { Counter } from "./Counter.js";

export class App extends Component {
  static components = { Counter };  // Register sub-component

  static template = xml`
    <div>
      <h1>OWL JS App</h1>
      <Counter/>
    </div>
  `;
}

src/Counter.js

JavaScript
import { Component, xml, useState } from "https://cdn.skypack.dev/@odoo/owl";

export class Counter extends Component {
  state = useState({ count: 0 });

  static template = xml`
    <div>
      <p>Count: <t t-esc="state.count"/></p>
      <button t-on-click="() => state.count++">+</button>
    </div>
  `;
}
Ad – 336×280

Approach 3 – npm + Vite (Recommended for Real Projects)

For real applications — Odoo module development, standalone OWL apps, projects with tests — you want a proper build tool. Vite is the recommended choice in 2026: it starts in under a second and rebuilds instantly on save.

Prerequisites

You need Node.js 18+ and npm installed. Download from nodejs.org. Verify installation:

Shell
node --version   # should show v18.x or higher
npm --version    # should show 9.x or higher

Create and configure the project

Shell
# 1. Create a new Vite project (choose "vanilla" + "JavaScript")
npm create vite@latest my-owl-app -- --template vanilla
cd my-owl-app

# 2. Install dependencies and add OWL
npm install
npm install @odoo/owl

# 3. Start the development server (with hot reload)
npm run dev
# Visit http://localhost:5173

Final file structure

Directory structure
my-owl-app/
  index.html          ← HTML entry point
  src/
    main.js           ← JavaScript entry point
    App.js            ← Root component
    components/       ← Your component files
  package.json
  vite.config.js

src/main.js

JavaScript
import { mount } from "@odoo/owl";
import { App } from "./App.js";

mount(App, document.getElementById("app"));

src/App.js

JavaScript
import { Component, xml, useState } from "@odoo/owl";

export class App extends Component {
  state = useState({ message: "Hello OWL JS! 🦉" });

  static template = xml`
    <div>
      <h1><t t-esc="state.message"/></h1>
      <input
        t-model="state.message"
        placeholder="Type something..."
        style="width: 300px; padding: 0.5rem; font-size: 1rem;"
      />
    </div>
  `;
}
▶ What you get
A heading and a text input. Typing in the input updates the heading in real time via t-model two-way binding. File changes trigger instant hot reload — no manual refresh needed.

Available npm scripts

Shell
npm run dev      # Start dev server with hot reload at http://localhost:5173
npm run build    # Build optimised production files into /dist
npm run preview  # Preview the production build locally

VS Code is strongly recommended for OWL development. Useful extensions:

ExtensionPurpose
OWL Vision (Odoo Inc.)OWL template syntax highlighting, component navigation, autocompletion
ESLintJavaScript linting — catch errors before running
PrettierAuto-format JavaScript and HTML on save
Live ServerQuick static server for Approach 2 setup
GitLensGit history and blame inline
ℹ️
OWL Devtools browser extension

Odoo provides an OWL Devtools browser extension for Chrome and Firefox. Once installed, it adds an "OWL" panel to your browser's developer tools showing the component tree, props, and state of every mounted OWL component. Install it from the Chrome Web Store (search "OWL Devtools") — it is invaluable for debugging.

📋 Summary

  • Approach 1 (CDN) — Fastest start. Single HTML + JS file. OWL loaded via CDN <script> tag. No tools needed. Perfect for learning the core concepts.
  • Approach 2 (Static server) — Multi-file ES modules. Run a local HTTP server (python3 -m http.server or npx serve). No build step.
  • Approach 3 (npm + Vite) — Full dev setup. npm install @odoo/owl, Vite for hot reload and production builds. Best for real projects.
  • Use VS Code with the OWL Vision extension for syntax highlighting and template autocompletion.
  • Install the OWL Devtools browser extension for debugging component trees in the browser.

Frequently Asked Questions

Do I need Node.js to use OWL JS? +

No — Approach 1 (single HTML + CDN) requires only a browser and a text editor. Node.js is only required for Approach 3 (npm + Vite). For learning the core OWL concepts in this course, you do not need Node.js at all. You will want it when you start building multi-file projects or when you reach the Odoo integration lessons.

Which version of OWL does the CDN serve? +

The jsDelivr URL https://cdn.jsdelivr.net/npm/@odoo/owl/dist/owl.iife.js serves the latest published version. To pin to a specific version (e.g. OWL 2.x), use https://cdn.jsdelivr.net/npm/@odoo/owl@2/dist/owl.iife.js. For production, always pin to a specific version to avoid unexpected breaking changes.

Can I use OWL JS with TypeScript? +

Yes — OWL is written in TypeScript and ships full type definitions. In the Vite setup, rename your files from .js to .ts and add a tsconfig.json. The OWL type definitions give you autocompletion for Component, useState, prop types, and lifecycle hooks. TypeScript is not required to learn OWL — this course uses JavaScript — but it is a valuable addition for larger projects.

How does OWL JS setup compare to setting up Odoo for development? +

Setting up a standalone OWL project (Approaches 1–3) is much simpler than setting up a full Odoo development environment. A real Odoo dev environment requires installing PostgreSQL, Python, Odoo itself, and configuring a database. The OWL-only setups here let you learn and practice OWL components without that overhead. The Odoo Integration section of this course covers the full Odoo setup when you are ready for it.

🏋️ Exercise

Set up Approach 1 (single HTML file) and get the counter example running in your browser:

  1. Create a folder named owl-practice.
  2. Inside it create index.html and app.js with the code from this lesson.
  3. Open index.html in your browser and verify the counter works.
  4. Add a fourth button: "Add 10" that adds 10 to the count with a single click.
  5. Add a <p> that shows "Even" when the count is even and "Odd" when it is odd. Use the t-if / t-else directives (covered in the Dynamic Templates section — try it now as a preview).