CLI Reference
The weld binary compiles a .weld file to Zig (the default), to a native binary, to a frontend client, or to a test runner. It also hosts the formatter as weld fmt.
weld <file.weld> [options]
weld dev <file.weld> # watch, rebuild, and rerun on save
weld test <file.weld> # run in-language tests
weld fmt [--check] <files…>
weld import <openapi|proto> <spec>Compile options
| Flag | Default | Description |
|---|---|---|
-o NAME | derived from input | Output path (extension chosen by --emit). |
--emit KIND | zig | What to produce — see the table below. |
--target TRIPLE | host | Cross-compile target, e.g. aarch64-linux, riscv64-linux (passed to Zig). |
-O LEVEL | ReleaseFast | Zig optimize mode: Debug, ReleaseFast, ReleaseSafe, ReleaseSmall. |
--port N | 8080 | Default listen port baked into the generated server. Overridden at runtime by the PORT environment variable (see below). |
--green | off | Build on the experimental green-thread runtime (see The Green Runtime). |
--profile | off | With --green, print a per-phase, per-route timing breakdown on shutdown. |
-h, --help | Show usage. |
The compiled server also reads a few settings from the environment at startup:
PORT— the default listener's port (falling back to the--portdefault), so the same binary runs on any port:PORT=3000 ./app.<NAME>_PORT— the port for a namedlistenlistener, falling back to its literal (e.g.ADMIN_PORTforlisten admin { port 9090 }).MAX_BODY_SIZE— the maximum accepted request body in bytes (default 8 MB); a larger request is rejected413. Bodies up to 64 KB use a pooled buffer; larger ones are read into a right-sized heap buffer.WELD_LOG— set to any truthy value (1,true, …) to log one line per request:weld: GET /path 200 0.42ms. Off by default (zero cost).WS_PING_INTERVAL— seconds between server WebSocket keepalive pings (default 25;0disables). Keep it under the ~30 s read timeout. See WebSocket Hubs.SHUTDOWN_DELAY_SECONDS/SHUTDOWN_GRACE_SECONDS— graceful-shutdown tuning (defaults0and25); see Health checks & graceful shutdown.- Any variables named in a
requiredeclaration are checked too — a missing one refuses to boot.
Serving configuration
How the server listens and serves — additional listeners, virtual hosts, CORS, response compression, and graceful shutdown — is configured in your .weld source and covered in Listeners & Serving.
Platforms & cross-compilation
The weld compiler is distributed for Linux, macOS, and Windows (weld.exe). Because it drives Zig's cross-compiler, --target is host-independent: from any of those hosts you can build a server for any other. In particular, a Windows machine can cross-compile Linux or macOS server binaries — driver sqlite programs included, since Zig bundles the target's libc and compiles the SQLite amalgamation for it:
# On Windows, produce a Linux x86-64 server binary:
weld app.weld --emit bin --target x86_64-linux -o appThe generated server targets POSIX (Linux/macOS), so --emit bin without a --target on Windows — i.e. a native Windows server — is not supported yet; pick a Linux or macOS --target. Emitting Zig (--emit zig), TypeScript/JavaScript clients, weld fmt, and weld import all work natively on Windows.
weld dev
weld dev <file.weld>A watch-rebuild-rerun loop for local development. Weld watches the source file and, on every save, stops the running server, recompiles it to a native binary (--emit bin, built -O ReleaseSafe for fast, safety-checked iteration), and launches the fresh one — so a browser refresh always hits the latest code. If a build fails, the last good server keeps running and the errors are printed; fix them and save again. Press Ctrl-C to stop.
weld dev app.weld
# weld dev: watching app.weld — rebuilds and reruns on save (Ctrl-C to stop)
# weld dev: building app.weld...
# weld dev: running ./app.devThe dev binary is written next to the source as <name>.dev. Server output (including WELD_LOG request logs) is inherited, so it streams straight to your terminal. For production builds use --emit bin -O ReleaseFast.
weld test
weld test <file.weld>Compiles the file's in-language test blocks and runs them, printing a pass/fail summary (equivalent to --emit test). Tests compile away in the server binary. For writing tests — assert, and mock for faking database/upstream/gRPC calls — see Testing & Mocking.
--emit kinds
| Kind | Produces |
|---|---|
zig | The generated Zig server source (default). |
bin | A native binary — invokes zig build-exe for you. |
ts | A TypeScript client. |
js | A JavaScript client with JSDoc types. |
client | Both .ts and .js clients. |
test | A Zig test file from your test blocks, then runs it (CI-ready, exits non-zero on failure). |
Examples
# Compile straight to a native binary and run it
weld app.weld --emit bin -O ReleaseFast
./app &
curl localhost:8080/
# Cross-compile
weld app.weld --emit bin --target aarch64-linux -o app-arm64
# Emit Zig and drive the toolchain yourself, on a custom port
weld app.weld -o app.zig --port 9090
zig build-exe app.zig -O ReleaseFast
# Green runtime with profiling
weld app.weld --green --profile --emit bin -O ReleaseSafe
# Generate frontend clients
weld app.weld --emit client -o api # api.ts and api.js
# Run in-language tests
weld app.weld --emit testweld fmt
Formats sources in place — reindenting by nesting, normalizing blank lines and trailing whitespace, and preserving comments and strings byte-for-byte (idempotent, semantics-preserving).
weld fmt src/*.weld # rewrite in place
weld fmt --check src/*.weld # CI mode: exit non-zero if any file is unformattedweld import
Generate typed Weld client code from an existing API definition — an OpenAPI 3.x JSON spec or a proto3 file. The output is ordinary Weld (record types plus an upstream or grpc block) that you then import, so calls to the external service are type-checked from its own definition.
# OpenAPI 3.x spec -> upstream + record types (prints to stdout, or -o to a file)
weld import openapi petstore.json -o pets.weld
# proto3 -> grpc block + @field-numbered message records (stream is preserved)
weld import proto greeter.proto -o greeter.weld- OpenAPI: each operation becomes a
call— path/query params and a JSON request body map to typed arguments, and the 2xx JSON schema becomes the return type.components.schemasbecome recordtypes;servers[0].urlbecomes thebase. - proto3: each
servicebecomes agrpcblock with onerpcper method (client/serverstreampreserved);messages become{ field: T @n }records andenums carry over.
Try it on the bundled specs in examples/imports/.