CLI reference
Root.js ships a few command-line tools. Run them with pnpm exec (or through a package.json script) from your project directory:
-
create-root: scaffolds a new project (pnpm create @blinkk/root). -
root: runs, builds and deploys the site. -
root-cms: sets up the CMS, generates types, and reads and writes content. -
root-password-protect: tools for password-protected pages.
This reference is generated from the source code.
create-root
create-root
create-root [dir] [options]| Argument | Description |
|---|---|
[dir] |
Output dir |
| Option | Description |
|---|---|
--template [template] |
Template to use: "starter" (Root CMS) or "minimal" (hello world) Default: "starter" |
--repo [repo] |
Github repo to pull from Default: "blinkk/rootjs/examples" |
--skip-gcp-setup |
Don't offer to set up Google Cloud for Root CMS templates |
root
| Global options | Description |
|---|---|
-q, --quiet |
Quiet |
root build
Generates a static build
root build [path] [options]
| Argument | Description |
|---|---|
[path] |
Optional. |
| Option | Description |
|---|---|
--ssr-only |
Produce a ssr-only build |
--mode <mode> |
See: https://vitejs.dev/guide/env-and-mode.html#modes Default: "production" |
-c, --concurrency <num> |
Number of files to build concurrently Default: "10" |
--threads [num] |
Renders pages using worker threads; pass a number for exactly N workers, or omit the value (or pass "auto") to pick based on cpu cores and page count |
--filter <urlPathRegex> |
Builds the url paths that match the given regex, e.g. "/products/.*" Default: "" |
--log <mode> |
Build log output: "progress" (default) shows a progress indicator and a final summary, "verbose" prints one line per output file, "quiet" prints only the final summary One of: progress, verbose, quiet. |
root codegen
Generates boilerplate code
root codegen [type] [name] [options]
| Argument | Description |
|---|---|
[type] |
Optional. |
[name] |
Optional. |
| Option | Description |
|---|---|
--out <outdir> |
Output dir |
root create-packagealias: package
Creates a standalone npm package for deployment to various hosting services
root create-package [path] [options]
| Argument | Description |
|---|---|
[path] |
Optional. |
| Option | Description |
|---|---|
--target <target> |
Hosting target, i.e. appengine or firebase |
--out <outdir> |
Output dir |
--mode <mode> |
Deployment mode, i.e. production or preview |
--app-yaml <path> |
For appengine targets, path to app.yaml (defaults to "app.yaml") |
root dev
Starts the server in development mode
root dev [path] [options]
| Argument | Description |
|---|---|
[path] |
Optional. |
| Option | Description |
|---|---|
--host <host> |
Network address the server should listen on, e.g. 127.0.0.1 |
root gae-deploy
Appengine deploy utility that can optionally run healthchecks before diverting traffic to the new version and clean up old versions
root gae-deploy <appdir> [options]
| Argument | Description |
|---|---|
<appdir> |
Required. |
| Option | Description |
|---|---|
--project <project> |
GCP project id |
--prefix <prefix> |
Prefix to append the version |
--promote |
Whether to promote the version (if healthchecks pass) |
--healthcheck-url <url> |
Healthcheck url path (e.g. "/healthcheck") which should return a 200 status with the text "OK" |
--max-versions <num> |
The max number of versions to keep |
root preview
Starts the server in preview mode
root preview [path] [options]
| Argument | Description |
|---|---|
[path] |
Optional. |
| Option | Description |
|---|---|
--host <host> |
Network address the server should listen on, e.g. 127.0.0.1 |
root start
Starts the server in production mode
root start [path] [options]
| Argument | Description |
|---|---|
[path] |
Optional. |
| Option | Description |
|---|---|
--host <host> |
Network address the server should listen on, e.g. 127.0.0.1 |
root secrets
Manage shared secrets backed by Google Cloud Secret Manager (requires the gcloud CLI)
root secrets
root secrets init
Create a secrets manifest
root secrets init [options]
| Option | Description |
|---|---|
--gcp-project <id> |
GCP project id |
--gsm-key <key> |
Secret Manager key for this manifest |
--manifest <path> |
Manifest path (defaults to ./.root.secrets.json) |
--import <path> |
Path to a shared manifest to import keys from |
--import-keys <names> |
Comma-separated subset of shared keys to import |
root secrets set
Store a secret value, read from a prompt (TTY) or piped stdin
root secrets set <name> [options]
| Argument | Description |
|---|---|
<name> |
Required. |
| Option | Description |
|---|---|
--manifest <path> |
Target manifest (defaults to ./.root.secrets.json) |
root secrets rm
Remove a secret
root secrets rm <name> [options]
| Argument | Description |
|---|---|
<name> |
Required. |
| Option | Description |
|---|---|
--manifest <path> |
Target manifest (defaults to ./.root.secrets.json) |
root secrets sync
Three-way merge managed secrets into .env
root secrets sync
root secrets pull
Force-download managed secrets into .env (overwrites local edits)
root secrets pull
root secrets push
Push .env values up to Secret Manager and record them in the manifest
root secrets push [options]
| Option | Description |
|---|---|
--manifest <path> |
Target manifest (defaults to ./.root.secrets.json) |
--keys <names> |
Comma-separated subset of .env keys (default: all) |
--yes |
Skip the confirmation prompt |
root secrets status
Show managed secrets and their sync status (no network)
root secrets status
root-cms
| Global options | Description |
|---|---|
-q, --quiet |
Quiet |
root-cms init-firebasealias: init
Inits the firebase project proper security rules
root-cms init-firebase [options]
| Option | Description |
|---|---|
--project <project> |
Gcp project id |
--admin <email> |
Adds an admin to the project |
root-cms setup
Sets up a google cloud project for root cms: checks gcloud sign-in, then configures firebase, firestore, storage, iam and secrets
root-cms setup [options]
| Option | Description |
|---|---|
--project <project> |
Gcp project id (skips the new/existing question) |
--site-id <siteId> |
Site id, used to keep sites on one gcp project apart |
--location <location> |
Region for a new firestore database and storage bucket |
--dry-run |
Print what would change without changing anything |
--yes |
Accept the default answer to every question |
root-cms generate-typesalias: types
Generates root-cms.d.ts from *.schema.ts files in the project
root-cms generate-types
root-cms export
Exports firestore data to a local directory
By default, all content in the Firestore database associated with the CMS will be exported.
A unique new directory will be created for each export.
File naming conventions: - Documents that act as containers for subcollections are exported as directories containing a __data.json file for the document's own data. - Standalone documents are exported as JSON files named after their document ID (e.g. page.json). - For collections like ActionLogs and Translations, the document ID (often a hash) is used as the filename.
Example output: <output>/Collections/Pages/Draft/... <output>/Collections/Pages/Published/... <output>/ActionLogs/...
root-cms export [options]
| Option | Description |
|---|---|
--filter <pattern> |
Comma-separated list of glob patterns to filter content (e.g. Collections/Pages/**, !ActionLogs/**) |
--site <siteId> |
Site id to export (overrides root config) |
--database <databaseId> |
Firestore database id (overrides root config, default: "(default)") |
--project <projectId> |
Gcp project id (overrides root config) |
$ root-cms export
$ root-cms export --filter "Collections/Pages/**"
$ root-cms export --filter "Collections/Pages/**,!Collections/Pages/Draft/**"
root-cms import
Imports firestore data from a local directory
root-cms import [options]
| Option | Description |
|---|---|
--dir <directory> |
Directory to import from (required) |
--filter <pattern> |
Comma-separated list of glob patterns to filter content (e.g. Collections/Pages/**, !ActionLogs/**) |
--site <siteId> |
Site id to import to (overrides root config) |
--database <databaseId> |
Firestore database id (overrides root config, default: "(default)") |
--project <projectId> |
Gcp project id (overrides root config) |
$ root-cms import --dir export_project_site_20251209t1305
$ root-cms import --dir export_project_site_20251209t1305 --filter "Collections/Pages/**"
root-cms docs.get
Fetches a single doc and outputs it as JSON
If an output path is provided, writes to a file. Otherwise, writes to stdout.
root-cms docs.get <docId> [outputPath] [options]
| Argument | Description |
|---|---|
<docId> |
Required. |
[outputPath] |
Optional. |
| Option | Description |
|---|---|
--mode <mode> |
Doc mode: "draft" or "published" (default: "draft") |
--raw |
Output raw firestore data without unmarshaling |
$ root-cms docs.get Pages/home
$ root-cms docs.get Pages/home ./out/home.json
$ root-cms docs.get Pages/home --mode published
$ root-cms docs.get Pages/home | jq .fields
root-cms docs.set
Updates a single doc from a JSON file or stdin
If a filepath is provided, reads from the file. Otherwise, reads from stdin.
root-cms docs.set <docId> [filepath] [options]
| Argument | Description |
|---|---|
<docId> |
Required. |
[filepath] |
Optional. |
| Option | Description |
|---|---|
--mode <mode> |
Doc mode: "draft" or "published" (default: "draft") |
$ root-cms docs.set Pages/home home.json
$ root-cms docs.set Pages/home home.json --mode published
$ cat data.json | root-cms docs.set Pages/home
root-cms docs.download
Downloads all docs in a collection to a local directory
root-cms docs.download <collection> [outputDir] [options]
| Argument | Description |
|---|---|
<collection> |
Required. |
[outputDir] |
Optional. |
| Option | Description |
|---|---|
--mode <mode> |
Doc mode: "draft" or "published" (default: "draft") |
$ root-cms docs.download Pages
$ root-cms docs.download Pages ./my-pages
$ root-cms docs.download Pages --mode published
root-cms docs.upload
Uploads docs from a local directory to a collection
root-cms docs.upload <collection> <dir> [options]
| Argument | Description |
|---|---|
<collection> |
Required. |
<dir> |
Required. |
| Option | Description |
|---|---|
--mode <mode> |
Doc mode: "draft" or "published" (default: "draft") |
$ root-cms docs.upload Pages ./Pages
$ root-cms docs.upload Pages ./my-pages --mode published
root-cms assets.upload
Uploads files to the asset library
Files are uploaded to the GCS bucket (and registered with the Google Cloud Image service for images when gci is enabled). If the folder already has a file with the same name, the asset is replaced and the new file is synced to every draft doc that uses it. Directories are uploaded recursively, mirroring their structure as subfolders.
root-cms assets.upload <paths...> [options]
| Argument | Description |
|---|---|
<paths> |
Required. |
| Option | Description |
|---|---|
--folder <folder> |
Asset library folder to upload into, e.g. "marketing/q1" (default: root) |
--name <name> |
Asset name (single file only) |
--asset-id <assetId> |
Id of an existing asset whose file should be replaced (single file only) |
--alt <text> |
Alt text for the uploaded file(s) |
--naming-mode <mode> |
Gcs object naming: "hash", "hash-path" or "clean" (default: folder setting) |
--cache-control <value> |
Cache-control header for the file(s) |
--no-gci |
Skip registering images with the gci service |
--no-sync |
Skip updating docs that use a replaced asset |
--modified-by <email> |
Email attributed as the author |
$ root-cms assets.upload ./hero.png
$ root-cms assets.upload ./hero.png --folder marketing --alt "Hero image"
$ root-cms assets.upload ./new-hero.png --asset-id AbC123dEf456
$ root-cms assets.upload ./icons --folder brand
root-cms client.call
Calls a method on the RootCMSClient with JSON-encoded arguments
Designed for AI agents. Arguments are a JSON array of positional args passed on the command line. When jsonArgs is omitted the method is called with no arguments; pass - to read the JSON args from stdin. The result is printed to stdout as a JSON envelope: {"ok": true, "result": <value>} {"ok": false, "error": "<message>"}
Run root-cms client.methods to discover available methods and their argument signatures.
root-cms client.call <method> [jsonArgs]
| Argument | Description |
|---|---|
<method> |
Required. |
[jsonArgs] |
Optional. |
$ root-cms client.call getDoc '["Pages", "home", {"mode": "draft"}]'
$ root-cms client.call listDocs '["Pages", {"mode": "published"}]'
$ root-cms client.call publishScheduledDocs
$ echo '["Pages", "home", {"mode": "draft"}]' | root-cms client.call getDoc -
root-cms client.methods
Lists the methods available on the RootCMSClient
Designed for AI discovery of available functionality. Prints each method's signature and description.
root-cms client.methods [options]
| Option | Description |
|---|---|
--json |
Output machine-readable JSON |
--types |
Include referenced type/interface definitions |
$ root-cms client.methods
$ root-cms client.methods --json
$ root-cms client.methods --json --types
root-cms proposal.check
Checks a CMS change proposal without touching the database
Parses the YAML, checks it against the proposal format, and prints a summary of the changes it describes. Collection schemas are not checked here (that needs db access — use proposal.diff). Exits non-zero on any error, so it works as a CI gate on a pull request.
root-cms proposal.check <file>
| Argument | Description |
|---|---|
<file> |
Required. |
$ root-cms proposal.check cms-proposals/hero-refresh.yaml
root-cms proposal.diff
Resolves a proposal against the live database and reports what it would write, without writing anything
root-cms proposal.diff <file> [options]
| Argument | Description |
|---|---|
<file> |
Required. |
| Option | Description |
|---|---|
--skip-validation |
Skip collection schema validation |
$ root-cms proposal.diff cms-proposals/hero-refresh.yaml
root-cms proposal.apply
Applies a CMS change proposal to the database
Writes drafts, release contents, and draft translations only — never publishes, schedules, or deletes. Nothing is written unless every change in the proposal resolves cleanly.
By default a proposal's recorded before values are treated as documentation for the human reviewer and are not checked against the database. Pass --verify-before to fail on drift instead.
root-cms proposal.apply <file> [options]
| Argument | Description |
|---|---|
<file> |
Required. |
| Option | Description |
|---|---|
--dry-run |
Resolve and validate everything, but write nothing |
--verify-before |
Fail if a recorded `before` value no longer matches the database |
--skip-validation |
Skip collection schema validation |
--modified-by <email> |
Email attributed as the author |
$ root-cms proposal.apply cms-proposals/hero-refresh.yaml
$ root-cms proposal.apply cms-proposals/hero-refresh.yaml --dry-run
$ root-cms proposal.apply cms-proposals/hero-refresh.yaml --verify-before
root-cms skill.install
Installs the bundled agent skills
Copies the skills (which teach AI coding agents how to use the root-cms client.* commands, and how to propose and apply CMS change proposals) into a local skills directory.
When no directory is given, existing agent skills directories are auto-detected (e.g. .claude/skills, .agent/skills, or any .*/skills dir already in the project) so Root does not assume a specific AI provider. If none is found, it installs to .agent/skills.
root-cms skill.install [dir] [options]
| Argument | Description |
|---|---|
[dir] |
Optional. |
| Option | Description |
|---|---|
--force |
Overwrite the skill if it is already installed |
--skill <name> |
Install only the named skill |
$ root-cms skill.install
$ root-cms skill.install ./my-agent/skills
$ root-cms skill.install --skill root-cms-propose
$ root-cms skill.install --force
root-cms translations.migrate
Migrates v1 translations to the v2 translations manager
Requires experiments: {v2TranslationsManager: true}. The CMS runs this automatically on the first root dev or root build. Run it on demand to migrate as a deliberate step, e.g. when opting in. The v1 translations are left in place as a backup, and the migrated translations are published.
root-cms translations.migrate [options]
| Option | Description |
|---|---|
--status |
Print the migration status without migrating |
--force |
Re-run a completed migration (overwrites v2 edits to migrated strings) |
$ root-cms translations.migrate --status
$ root-cms translations.migrate
$ root-cms translations.migrate --force
root-password-protect
| Global options | Description |
|---|---|
-q, --quiet |
Quiet |
root-password-protect generate-hash
Generates a hash/salt pair from a plain-text password
root-password-protect generate-hash <password>
| Argument | Description |
|---|---|
<password> |
Required. |