Getting Started
Installation
Therapy.jl requires Julia 1.12 (for WasmTarget.jl IR compatibility).
using Pkg
Pkg.add(url="https://github.com/GroupTherapyOrg/Therapy.jl")Project Structure
A Therapy.jl app uses file-based routing. Each file in routes/ becomes a page. Components in components/ are available to all pages.
my-app/
app.jl # Entry point
routes/
index.jl # → /
about.jl # → /about
examples/
index.jl # → /examples
components/
Counter.jl # @island component (compiled to WASM)
Layout.jl # SSR layout wrapperSSR Components
Components are plain Julia functions that return HTML elements. They run at build time with full access to Julia packages. No macro needed.
# routes/index.jl — a simple page
() -> begin
Div(
H1("Hello, World!"),
P("This is server-rendered at build time."),
P("You can use any Julia package here — DataFrames, HTTP, etc.")
)
endAdding Interactivity
Use @island to make a component interactive. Island handlers, effects, and memos compile to WebAssembly via WasmTarget.jl. Only islands ship WASM to the browser — everything else is static HTML.
# components/Counter.jl
@island function Counter(; initial::Int = 0)
count, set_count = create_signal(initial)
doubled = create_memo(() -> count() * 2)
return Div(
Button(:on_click => () -> set_count(count() - 1), "-"),
Span(count),
Button(:on_click => () -> set_count(count() + 1), "+"),
P("doubled: ", doubled)
)
endSignals become WASM globals. Handlers become WASM exports. Effects and memos compile via WasmTarget.compile_closure_body(). The browser receives a tiny WASM module (1-12 KB per island).
Browser APIs
Use js() to call browser APIs from WASM. Signal values are interpolated with $1, $2, etc.
# Console logging (re-runs on every signal change)
create_effect(() -> js("console.log('count:', $1)", count()))
# DOM manipulation
js("document.documentElement.classList.toggle('dark')")
# localStorage
js("localStorage.setItem('key', $1)", count())Running Your App
# Development server with hot reload
julia +1.12 --project=. app.jl dev
# Build static site for deployment
julia +1.12 --project=. app.jl build
# Add --optim to either command to run Binaryen wasm-opt trim + dead-code
# elimination on every island. Slower to build, substantially smaller WASM.
julia +1.12 --project=. app.jl dev --optim
julia +1.12 --project=. app.jl build --optimThe dev server compiles islands on the fly and serves pages with hot reload. The build command generates static HTML + WASM files ready for deployment to GitHub Pages, Netlify, or any static host.