Use this page after First Application. The authoring loop is shared, but the delivery loop is not: choose one product target instead of building every target in sequence.
- Choose native for one platform-specific executable with no language runtime at deployment.
- Choose Python when Python 3.11 or newer is already part of the deployment environment.
- Choose Web Application when Topaz owns the browser model, messages, update function, and view.
- Choose bounded HTTP service when a checked request handler should run behind a process supervisor and, for public traffic, a reverse proxy.
Raw Web and Worker packages are integration products for an existing JavaScript host. They are covered in WASM & Playground.
Shared authoring loop
Start from a checked two-module package. A current native package manifest has
the following identity. Save it as topaz.toml:
[package]
name = "task_summary"
version = "0.1.0"
language = "5.11"
entry = "src/main.tpz"
[build]
target = "native"
deterministic = true
[dependencies]
std = "5.11"
The helper module owns the application calculation:
export function remainingMinutes(values: Array<int>) -> int {
let mut total = 0
for value in values {
total += value
}
total
}The entry module turns the result into an observable command:
import src.summary { remainingMinutes }
export function main(args: Array<string>, stdin: string) -> Result<int, string> {
let minutes = remainingMinutes([10, 25])
print("remaining={minutes}")
Ok(0)
}Create topaz.lock once, then use the same order for normal work:
topaz lock --root task-summary
topaz fmt --check --root task-summary
topaz check --root task-summary --locked
topaz test --root task-summary --locked
topaz run --root task-summary --locked
fmt --check reports formatting drift without changing files. A failed
check or test stops before a product is written; fix the first Topaz
diagnostic and repeat the same command. Use topaz explain TPZ#### when a
diagnostic code needs a longer explanation.
Path A: native or Python command application
Native builds require a Rust toolchain for the current operating system and architecture. Python builds do not require Rust, but the resulting product requires Python 3.11 or newer.
Build only the product you intend to deliver:
topaz build --release --root task-summary --locked --out-dir native-product
topaz build --target python --root task-summary --locked --out-dir python-product
The release trees are:
native-product/
├── GENERATED-OUTPUT-NOTICE.txt
├── LICENSE
├── NOTICE
├── target
│ └── release
│ └── program[.exe]
└── topaz-artifact.json
python-product/
├── GENERATED-OUTPUT-NOTICE.txt
├── LICENSE
├── NOTICE
├── program.py
├── topaz-artifact.json
└── topaz_py_rt.pyprogram[.exe] means program on Unix and program.exe on Windows. Copy the
complete chosen directory to a fresh
location and run from its root:
./target/release/program
python3 program.py
Use the first command in the native product and the second in the Python
product; they are alternatives. If the application declares
[capabilities.fs], place its data/ and writable output directories beside
the product and keep that directory as the working directory. Application
data is not added to native or Python products automatically.
If a build reports a missing Rust toolchain, either install the matching Rust toolchain or choose Python. If an output directory contains another target or a changed managed file, keep it for inspection and build into a new empty directory.
Path B: managed Web Application
A Web Application build requires Rust with the
wasm32-unknown-unknown target. Create the checked scaffold instead of
converting the command entry:
topaz init --target web-app --root hello-web
topaz lock --root hello-web
topaz fmt --check --root hello-web
topaz check --root hello-web --locked
topaz test hello-web/tests/app.tpz --root hello-web --locked
topaz dev --root hello-web --port 8000
topaz build --root hello-web --locked --release --out-dir web-product
The generated entry uses the checked lifecycle:
import std.dom { Html, WebAppEvent, WebAppStep, text }
export record Model {
message: string,
}
export enum Msg {
Ready,
}
export function init() -> WebAppStep<Model, Msg> {
WebAppStep { model: Model { message: "Hello from Topaz" }, commands: [] }
}
export function update(model: Model, message: Msg, event: WebAppEvent) -> WebAppStep<Model, Msg> {
WebAppStep { model: model, commands: [] }
}
export function view(model: Model) -> Html<Msg> {
text(model.message)
}topaz dev is a loopback development server and keeps the last good product
after a failed edit. It is not a production server. The final directory
contains HTML, the checked application host, the raw Web facade, WASM,
capability metadata, declared styles and assets, and the common license and
artifact files. Copy the complete directory to a static host and serve it over
HTTP; opening ES modules through file:// is not the deployment path.
Data Lens is the maintained multi-module example for this path.
Path C: bounded HTTP service
Create a service scaffold when the product is a request handler rather than a command or browser UI:
topaz init --target http-service --root hello-service
topaz lock --root hello-service
topaz fmt --check --root hello-service
topaz check --root hello-service --locked
topaz test --root hello-service --locked
topaz dev --root hello-service --port 8080
topaz build --root hello-service --locked --release --out-dir service-product
The handler boundary is concrete and synchronous:
import std.http { HttpRequest, HttpResponse, text }
export function handle(req: HttpRequest) -> HttpResponse {
if req.url.path() == "/health" {
return text(200, "ok")
}
text(404, "not found")
}The service product contains one native executable, embedded bounded defaults, third-party notices, and the common artifact files. It binds to loopback by default. A non-loopback bind requires an explicit process argument; TLS, HTTP/2, outbound networking, and a general Web framework are not added.
Bounded HTTP Service completes this path, including budgets, observable failures, source-free execution, and deployment recovery.