Skip to content

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.

sh
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

FlagDefaultDescription
-o NAMEderived from inputOutput path (extension chosen by --emit).
--emit KINDzigWhat to produce — see the table below.
--target TRIPLEhostCross-compile target, e.g. aarch64-linux, riscv64-linux (passed to Zig).
-O LEVELReleaseFastZig optimize mode: Debug, ReleaseFast, ReleaseSafe, ReleaseSmall.
--port N8080Default listen port baked into the generated server. Overridden at runtime by the PORT environment variable (see below).
--greenoffBuild on the experimental green-thread runtime (see The Green Runtime).
--profileoffWith --green, print a per-phase, per-route timing breakdown on shutdown.
-h, --helpShow usage.

The compiled server also reads a few settings from the environment at startup:

  • PORT — the default listener's port (falling back to the --port default), so the same binary runs on any port: PORT=3000 ./app.
  • <NAME>_PORT — the port for a named listen listener, falling back to its literal (e.g. ADMIN_PORT for listen admin { port 9090 }).
  • MAX_BODY_SIZE — the maximum accepted request body in bytes (default 8 MB); a larger request is rejected 413. 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; 0 disables). Keep it under the ~30 s read timeout. See WebSocket Hubs.
  • SHUTDOWN_DELAY_SECONDS / SHUTDOWN_GRACE_SECONDS — graceful-shutdown tuning (defaults 0 and 25); see Health checks & graceful shutdown.
  • Any variables named in a require declaration 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:

sh
# On Windows, produce a Linux x86-64 server binary:
weld app.weld --emit bin --target x86_64-linux -o app

The 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.

sh
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.dev

The 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

KindProduces
zigThe generated Zig server source (default).
binA native binary — invokes zig build-exe for you.
tsA TypeScript client.
jsA JavaScript client with JSDoc types.
clientBoth .ts and .js clients.
testA Zig test file from your test blocks, then runs it (CI-ready, exits non-zero on failure).

Examples

sh
# 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 test

weld 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).

sh
weld fmt src/*.weld            # rewrite in place
weld fmt --check src/*.weld    # CI mode: exit non-zero if any file is unformatted

weld 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.

sh
# 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.schemas become record types; servers[0].url becomes the base.
  • proto3: each service becomes a grpc block with one rpc per method (client/server stream preserved); messages become { field: T @n } records and enums carry over.

Try it on the bundled specs in examples/imports/.