Skip to content

CLI ​

Use gsx to scaffold a project, run the development loop, generate Go, and format .gsx files.

text
gsx [global flags] <command> [arguments]

Choose a command ​

TaskCommand
Create a starter projectgsx init [dir]
Generate, build, and reload while editinggsx dev [dir]
Generate .x.go filesgsx generate [paths...]
Format .gsx filesgsx fmt [paths...]
Fix whitespace after upgradinggsx fix whitespace [paths...]
Inspect the resolved project setupgsx info
Remove the generation cachegsx clean --cache
Start the editor language servergsx lsp
Show version and build informationgsx version
List commandsgsx help

Global flags ​

-C is the only true global flag. It must appear before the command name and sets the base directory for commands that resolve project paths or configuration:

bash
gsx -C ./web generate .
FlagEffect
-C dirUse dir as the base for project paths and configuration.

-q and -v may also appear before or after generate, but they affect that command only:

bash
gsx -q generate
gsx generate -v ./views

gsx init ​

Create the simple gsx + Vite starter in a new directory:

bash
gsx init myapp
text
gsx init [dir] [flags]
FlagEffect
--template simpleSelect the starter template. simple is the only current template.
--module pathSet the Go module path. The default is the target directory name.
--forceOverwrite an existing go.mod or package.json.
--yes, -yRun setup commands without prompting.

Interactive setup ​

In a terminal, gsx init asks for a project name when dir is omitted. It then scaffolds the project and asks before running each setup command.

bash
gsx init

Press Enter, y, or yes to run a step. Skipping one step does not skip the remaining steps. Ending input (Ctrl-D) stops init: it runs nothing more and prints the steps it did not run. At the project-name prompt, nothing is created.

Non-interactive setup ​

Use --yes when a script should scaffold and run every setup command:

bash
gsx init myapp --module example.com/acme/myapp --yes

When standard input is not a terminal (a pipe, a file, or /dev/null) and --yes is omitted, init scaffolds the files, then prints the setup commands instead of running them.

init exits 0 on success, 2 for invalid usage or an existing protected project file, and 1 when scaffolding or a setup command fails, or input ends at a prompt.

gsx dev ​

Run the development loop from the project directory:

bash
gsx dev

Pass an optional project directory with gsx dev [dir].

Relevant source changes regenerate as needed, build, swap the server, and reload the browser. After the first successful build, later generation or build failures leave the last working server running. A .env change only restarts the backend with fresh environment values; it does not regenerate or build. See the development loop for the full file-by-file behavior.

FlagEffect
--web commandSet the front-door command. The default is npx vite.
--no-webRun generation and the Go server without the front door.
--build commandSet the server build command.
--run commandSet the built-server command.
--logCopy backend output to the default per-project log file.
--log-file pathCopy backend output to path.
--no-logDisable backend file logging, including logging from gsx.toml.

Common customizations ​

Run without Vite when another tool provides the front door:

bash
gsx dev --no-web

Override the build and run commands for one session:

bash
gsx dev --build "go build -o ./tmp/app ./cmd/site" --run "./tmp/app"

Command flag values are split on whitespace. For arguments that need exact boundaries, use arrays in the [dev] configuration.

Before the first successful build there is no previous server to keep alive. Fix the startup error and save again. A clean signal-driven shutdown exits 0; invalid flags exit 2, and fatal startup errors exit 1.

gsx generate ​

Generate a sibling .x.go file for every .gsx file under the selected paths:

bash
gsx generate
gsx generate ./views ./email

With no path, the command uses .. Directory paths are searched recursively, skipping hidden directories, vendor, node_modules, testdata, and directories listed in a go.mod ignore directive (for example ignore ./frontend).

FlagEffect
--no-cacheRegenerate without reading or writing cached results.
--jsonWrite diagnostics as one JSON array to stdout.
--watchKeep running and regenerate when source files change.
--format=ndjsonIn watch mode, write one machine-readable event per line.
-qSuppress the success summary.
-vList each written or removed file before the summary.

Generate flags may appear before or after path arguments.

Diagnostics and exit status ​

Normal diagnostics go to stderr. Use JSON when another program consumes them:

bash
gsx generate --json ./views
ExitMeaning
0Generation succeeded, including when everything was already current.
1A source diagnostic or operational error prevented generation.
2The command, configuration, or a path was invalid.

Warnings, such as duplicate-attribute, are printed but do not change the exit status. The [lint] table in gsx.toml can turn each lint off or make it an error; see Lints.

When a .gsx file has a generation error, gsx replaces its previous generated file with a deliberately non-compiling marker. This prevents go build from silently using stale output. Fix the .gsx file and run generate again.

Deleting a .gsx file removes its generated sibling on the next generation run. Only files with gsx's generated-file header are removed; a hand-written file with the same name is left alone. I/O and project-loading failures do not replace files with error markers.

Test coverage ​

go tool cover -func and -html fail on packages with gsx components (expected declaration, found component). Generated code maps errors back to .gsx with //line directives, and Go's coverage tooling handles them inconsistently (golang/go#41222). Drop the template entries before reporting:

bash
go test -coverprofile=cover.out ./...
grep -v '\.gsx:' cover.out > cover.go.out
go tool cover -func cover.go.out

Components are then not measured. Don't rename .gsx: to .x.go: in the profile: -html renders, but -func reports wrong percentages.

Watch mode ​

Use watch mode when an integration needs generation without the full dev loop:

bash
gsx generate --watch

For a machine-readable stream, use newline-delimited JSON:

bash
gsx generate --watch --format=ndjson

Human watch output goes to stderr. In NDJSON mode, stdout contains only event objects; diagnostic fields use the same shape as --json.

gsx fmt ​

Rewrite .gsx files in place before committing:

bash
gsx fmt -w .

Paths may be files or directories. Directories are searched recursively; with no path, the command formats .. It skips the same directories as gsx generate.

FlagEffect
noneWrite formatted source to stdout.
-wRewrite changed files in place.
-lList files whose source would change.
-dShow a unified diff.
-imports=goimportsRemove unused imports and normalize import declarations. This is the default.
-imports=gofmtFormat existing imports without removing, merging, or regrouping them.
-no-importsAlias for -imports=gofmt.
-stdin-filename=PATHRead the source from stdin and treat it as PATH.

The goimports mode cannot add a missing import; it organizes imports already present in the .gsx file. A CLI import mode overrides the [formatter] setting.

gsx fmt also formats CSS in <style> and JavaScript in executable <script> bodies. Interpolation holes are preserved. If an embedded body cannot be formatted safely, that body is left unchanged.

js`/css` attribute values are re-indented the same way as <script>/<style> bodies. Plain "…" string attributes are left verbatim.

Text flow ​

Inline elements (code, a, span, em, b, img, and other phrasing-content tags) stay in the surrounding text flow: the formatter never breaks their children open to meet the width budget. If a line has no other legal break point, it stays over budget rather than exploding an inline element.

Long prose wraps between words. The formatter never adds whitespace where text and markup touch.

{" "} sticks to the word before it and never starts a line.

Author layout still wins: breaking the line right after an opening tag's > keeps that element block-formatted, even if its content would otherwise fit inline.

Formatting stdin ​

-stdin-filename formats content that is not on disk. PATH names the file in -l/-d output and error messages and selects its gsx.toml, .editorconfig, and package for import analysis — nothing is read from it, and it need not exist. Path arguments and -w are rejected in this mode.

A pre-commit hook uses it to check the staged blob rather than the working copy:

bash
git show ":$f" | gsx fmt -l -stdin-filename "$f"

Check formatting in CI ​

-l and -d exit 1 when any file differs, so either works as a CI check:

bash
gsx fmt -l .
ExitMeaning
0Nothing failed; with -l/-d, nothing differs.
1With -l/-d only: at least one file differs and nothing failed.
2Something failed: a usage error (invalid flag, import-mode combination, or path) or a read, parse, analysis, or write failure on any file.

A failure wins over a difference, so a script can tell "run -w" from "this file is broken".

gsx fix ​

gsx fix whitespace [-all] [-w] [-l] [-d] [paths...] applies the punctuation-space and redundant-space-literal fixes in place. By default it fixes only line breaks that v0.4 rendered as nothing, so output matches v0.4 there and is unchanged elsewhere; run it beforegsx fmt when upgrading. -all applies every finding, including same-line spaces such as those an earlier gsx fmt joined onto the line, and changes output. -l lists and -d diffs without writing, and exit 1 when a file would change; add -w to write as well.

gsx info ​

Inspect the configuration that gsx resolves for the current project:

bash
gsx info

The human view shows the active config path and resolved filters, renderers, attribute rules, lint levels, minification, formatter width, and environment overrides. Use JSON for automation:

bash
gsx info --json

Human and JSON output are different inspection views, not identical encodings of the same fields. Scripts should consume --json rather than parse the human table.

Resolution failures exit 1. Invalid arguments or project configuration exit 2; a successful inspection exits 0.

gsx clean ​

Remove the generation cache:

bash
gsx clean --cache

The command exits successfully when the cache is disabled or absent. It refuses to remove a directory that does not contain gsx's cache marker, which protects against an unsafe GSXCACHE value. A refusal or removal failure exits 1; invalid flags exit 2.

gsx lsp ​

Editors start the language server over standard input and output:

bash
gsx lsp

You normally do not run this command yourself. See Editor setup for VS Code, Neovim, Zed, and generic client configuration.

gsx version ​

Print the installed version:

bash
gsx version

When available, the output also includes the commit revision, commit time, dirty-tree state, and Go toolchain version. Local builds without an embedded module version report (devel).

Environment variables ​

VariableEffect
`GSX_MINIFY=nonefull`
GSXCACHE=offDisable the generation cache.
GSXCACHE=pathUse path instead of the operating-system user cache directory.

For minification, a programmatic option in a custom gsx binary wins over GSX_MINIFY, which wins over gsx.toml. Use --no-cache for a single uncached generation run.

Stability ​

The CLI is alpha and ships in tagged releases with the runtime (one module, one tag; see Releases and versioning). This page lists the commands that are available now; see Status for the broader shipped surface.