| title | The Motoko Runtime |
|---|---|
| section | Architecture |
| slug | runtime |
When you run motoview build, your .mview files are compiled to Motoko and wired into a canister actor. That actor never works alone — it leans on the MotoView runtime, a Motoko library shipped in runtime/ (the mops package motoview). The runtime is what turns an HTTP request from the browser into rendered HTML, dispatched events, and versioned UI batches.
This page walks through the modules in runtime/src and shows how a generated actor stitches pages, layouts, and assets together behind http_request / http_request_update.
The runtime is deliberately small and dependency-free. Each module owns one concern:
- App — the orchestrator class. Holds registered pages and layouts, routes incoming requests, renders the matching page into its layout, dispatches events to typed handlers, and produces the batch JSON described in the protocol.
- Types — the shared types: requests, responses, batches, route entries, render context, handler signatures.
- Router — matches a request path against registered routes, including parameters like
/products/{id}and typed/orders/{id:Nat}. - Url — parses paths, query strings, and form-encoded bodies (used to read
path,lastBatchId, and event payloads). - Json — minimal JSON building/escaping for batch responses.
- Hash — hashing helpers, including the
batchIdhash that lets the client skip unchanged renders. - Security / Sha256 — SHA-256 and HMAC-SHA256 in pure Motoko, verified against standard test vectors. This is what mints and re-derives the signed
secureform token (path + handler + caller principal + nonce + expiry + field-schema hash). - Html.Builder — a small typed builder for emitting escaped HTML, used by generated page code.
- Base64 — encode/decode for tokens and binary asset payloads.
- ClientAssets — serves the only browser code:
/motoview.wasm(the WASM brain),/motoview.js(the JS glue hands), and/motoview.css.
The compiler emits a Motoko actor that constructs an App, registers each compiled page and layout, and forwards the IC HTTP entry points to it.
import App "mo:motoview/App";
import Types "mo:motoview/Types";
import HomePage "Generated/HomePage";
import MainLayout "Generated/MainLayout";
actor {
let app = App.App();
// Pages and layouts compiled from your .mview files
app.layout("main", MainLayout.render);
app.page("/", HomePage.render, HomePage.handlers);
public query func http_request(req : Types.Request) : async Types.Response {
// MVP transport: upgrade so every request is served by update.
app.httpRequest(req);
};
public func http_request_update(req : Types.Request) : async Types.Response {
app.httpRequestUpdate(req);
};
};Two entry points, two jobs:
http_request— the IC query entry point. In the MVP it returnsupgrade = true, which tells the replica to re-issue the call as an update. This sidesteps query response-certification while the protocol matures. (Certified query rendering for cacheable public pages is Roadmap.)http_request_update— does the real work. TheApproutes the path through theRouter, then:- For a first load (
GET /page), it renders the page into its layout and returns server-rendered HTML with content inside<div id="mv-root">. - For a sync poll (
GET /_motoview/render), it compares the freshly computedbatchIdagainstlastBatchIdand returns"changed"or"unchanged". - For an event (
POST /_motoview/event), it verifies thesecuretoken viaSecurity, dispatcheshandlerId+ args to the typed Motoko handler, re-renders, and returns the new batch immediately. - For
/motoview.wasm,/motoview.js,/motoview.css, it serves bytes fromClientAssets.
- For a first load (
# First load: full HTML document
GET / -> <html> ... <div id="mv-root"> ... </div>
# Background sync (adaptive polling)
GET /_motoview/render?path=/&lastBatchId=ab12 -> { "status": "unchanged" }
# An interaction
POST /_motoview/event -> { "status": "changed", "batchId": "cd34", "html": "..." }Because every response carries a batchId (a hash of rendered state from Hash), the WASM client only swaps the DOM when something actually changed.
- See Events for how
@clickhandlers are baked intodata-mv-arg*attributes and dispatched server-side. - See Forms & Security for the full
securetoken derivation. - See The Protocol for batch statuses and the adaptive polling cadence.