Back to Lowdefy

lowdefy (CLI)

code-docs/packages/cli.md

5.2.012.8 KB
Original Source

lowdefy (CLI)

The command-line interface for Lowdefy. Provides commands for initializing, developing, building, and running Lowdefy applications.

Purpose

The CLI is the primary entry point for developers working with Lowdefy:

  • Initialize new projects
  • Run development server with hot reload
  • Build production applications
  • Start production servers

Commands

lowdefy init

Initialize a new Lowdefy project in the current directory.

bash
lowdefy init

Creates:

  • lowdefy.yaml - Main configuration file
  • .gitignore - Ignores build artifacts

lowdefy dev

Start the development server with hot reload.

bash
lowdefy dev [options]

Options:

OptionDescriptionDefault
--config-directoryConfig directory pathCurrent directory
--dev-directoryDev server directory.lowdefy/dev
--portServer port3000
--no-openDon't open browserOpens browser
--watchAdditional paths to watch-
--watch-ignorePaths to ignore-
--ref-resolverCustom ref resolver path-
--log-levelLog level (error/warn/info/debug)info

What happens:

  1. Downloads dev server package
  2. Runs @lowdefy/build on config
  3. Starts Next.js dev server
  4. Watches for config changes
  5. Rebuilds on change

lowdefy build

Build a production-ready application.

bash
lowdefy build [options]

Options:

OptionDescriptionDefault
--config-directoryConfig directory pathCurrent directory
--server-directoryServer output directory.lowdefy/server
--no-next-buildSkip Next.js buildBuilds Next.js
--ref-resolverCustom ref resolver path-
--log-levelLog levelinfo

What happens:

  1. Downloads production server package
  2. Runs @lowdefy/build on config
  3. Runs next build on the server
  4. Outputs ready-to-deploy app

lowdefy start

Start a built production application.

bash
lowdefy start [options]

Options:

OptionDescriptionDefault
--config-directoryConfig directory pathCurrent directory
--server-directoryServer directory.lowdefy/server
--portServer port3000
--log-levelLog levelinfo

lowdefy init-docker

Generate a Dockerfile for containerized deployment.

bash
lowdefy init-docker [options]

lowdefy init-vercel

Generate Vercel deployment scripts.

bash
lowdefy init-vercel [options]

lowdefy upgrade

Upgrade a Lowdefy app by walking through migration prompts that handle breaking changes between versions.

bash
lowdefy upgrade [options]

Options:

OptionDescriptionDefault
--toTarget versionLatest stable
--planShow upgrade plan without executing-
--resumeResume interrupted upgrade-
--config-directoryConfig directory pathCurrent directory
--log-levelLog levelinfo

What happens:

  1. Reads current version from lowdefy.yaml
  2. Fetches @lowdefy/codemods@latest from npm (reuses fetchNpmTarball)
  3. Resolves the version chain via resolveChain.js
  4. Presents migration prompts phase by phase via executePhase.js
  5. Updates lowdefy.yaml version after each phase
  6. Suggests git commit between phases

Architecture

┌─────────────────┐
│  upgrade command │
│  (upgrade.js)   │
└────────┬────────┘
         │
         ▼
┌──────────────────────┐     ┌───────────────────────────┐
│  fetchNpmTarball     │────▶│  @lowdefy/codemods@latest │
│  (reused from CLI)   │     │  → .lowdefy/codemods/     │
└──────────────────────┘     └───────────────────────────┘
         │
         ▼
┌──────────────────────┐
│  resolveChain.js     │  Reads registry.json, computes
│                      │  version chain using semver ranges
└────────┬─────────────┘
         │
         ▼
┌──────────────────────┐
│  executePhase.js     │  For each phase in the chain:
│                      │  presents prompts in order
└────────┬─────────────┘
         │
         ▼
┌──────────────────┐
│  handlePrompt.js │  Reads .md prompt, presents options:
│                  │  clipboard / view / skip
│                  │  AI tool detection
└────────┬─────────┘
         │
         ▼
┌──────────────────────┐
│  upgradeState.js     │  Writes .lowdefy/upgrade-state.json
│                      │  for --resume and build-time warnings
└──────────────────────┘

Key modules

ModulePurpose
commands/upgrade/upgrade.jsCommand entry point — fetch codemods, orchestrate
commands/upgrade/resolveChain.jsVersion chain resolution from registry.json using semver ranges
commands/upgrade/executePhase.jsPhase orchestrator — presents prompts in order
commands/upgrade/handlePrompt.jsPresents prompt options — clipboard, AI detection, manual guide
commands/upgrade/upgradeState.jsReads/writes .lowdefy/upgrade-state.json for resume and build warnings

Integration points

  • fetchNpmTarball — Reused from the existing server download flow to fetch @lowdefy/codemods@latest.
  • validateVersion.js — Extended to check for .lowdefy/upgrade-state.json and warn about pending codemods during build and dev.
  • @lowdefy/codemods — External package containing all migration prompts and registry. See codemods.md.

Design decisions

Why @lowdefy/codemods@latest: The codemods package contains the full migration history for all versions. Fetching @latest ensures the chain resolver has complete coverage. The --to flag controls the target version, not the codemods package version. This mirrors how getServer.js decouples CLI version from server version.

Why prompts instead of scripts: AI tools execute find-and-replace reliably from markdown prompts. Prompts can be updated after publishing (they're just text), work with any AI tool, and one format eliminates the need for script execution infrastructure (child_process.fork, backup logic, etc.).

Why lazy AI detection: The CLI checks for AI tool environment indicators only when presenting a prompt. Detection never blocks the upgrade flow — it may add options in future, falls back to clipboard/manual otherwise.

Environment Variables

All options can be set via environment variables:

VariableCorresponding Option
LOWDEFY_DIRECTORY_CONFIG--config-directory
LOWDEFY_DIRECTORY_DEV--dev-directory
LOWDEFY_DIRECTORY_SERVER--server-directory
LOWDEFY_LOG_LEVEL--log-level
LOWDEFY_DISABLE_TELEMETRY--disable-telemetry
PORT--port

Architecture

┌─────────────────┐
│  lowdefy CLI    │
│  (Commander.js) │
└────────┬────────┘
         │
         ▼
┌─────────────────────────────────────────────────────┐
│                    Commands                                    │
├──────────┬──────────┬──────────┬──────────┬─────────┬────────┤
│   init   │   dev    │  build   │  start   │ upgrade │ init-* │
└──────────┴────┬─────┴────┬─────┴────┬─────┴────┬────┴────────┘
                │          │          │
                ▼          ▼          ▼
         ┌──────────────────────────────────┐
         │      Server Package Download      │
         │  (from npm: @lowdefy/server-*)    │
         └──────────────────────────────────┘
                         │
                         ▼
         ┌──────────────────────────────────┐
         │        @lowdefy/build            │
         │    (config compilation)          │
         └──────────────────────────────────┘
                         │
                         ▼
         ┌──────────────────────────────────┐
         │         Next.js Server           │
         │   (dev server or production)     │
         └──────────────────────────────────┘

Key Modules

/commands/

DirectoryPurpose
init/Project initialization logic
dev/Development server orchestration
build/Production build orchestration
start/Production server startup
upgrade/Codemod upgrade orchestration
init-docker/Dockerfile generation
init-vercel/Vercel scripts generation

/utils/

ModulePurpose
runCommand.jsCommand wrapper with error handling
createPluginTypesMap.jsGenerate plugin type maps

Logging

The CLI uses createCliLogger from @lowdefy/logger/cli (ora spinners, colored terminal output). The logger is available as context.logger with four level methods (error, warn, info, debug). Color is passed via merge objects: logger.info({ color: 'blue' }, 'text'). Spin/succeed: logger.info({ spin: true }, 'Building...').

When running the dev server, the CLI pipes the manager process stdout through createStdOutLineHandler which parses pino JSON lines, reconstructs errors, and routes them to logger[level](error) or logger[level]({ color/spin/succeed }, msg) for rendering.

See @lowdefy/logger for the full logging architecture.

Design Decisions

Why Download Server Packages?

The CLI downloads @lowdefy/server and @lowdefy/server-dev on demand:

  • Keeps CLI package small
  • Server can be versioned independently
  • Different server variants possible

Why Not Bundle Build?

The build package (@lowdefy/build) is also downloaded:

  • Reduces CLI size
  • Ensures build matches server version
  • Allows build improvements without CLI updates

Node.js Version Check

The CLI enforces Node.js >= 18:

javascript
if (Number(nodeMajorVersion) < 18) {
  throw new Error('...');
}

This ensures compatibility with:

  • ES modules
  • Modern JavaScript features
  • Next.js requirements

Integration Points

  • @lowdefy/build: Called for config compilation
  • @lowdefy/server: Downloaded for production builds
  • @lowdefy/server-dev: Downloaded for development
  • Next.js: Underlying framework for both servers

Typical Workflow

bash
# 1. Create new project
npx lowdefy init

# 2. Develop locally
npx lowdefy dev

# 3. Build for production
npx lowdefy build

# 4. Run production server
npx lowdefy start

# Or deploy to Vercel/Docker
npx lowdefy init-vercel  # or init-docker

File Watching (Dev Mode)

The dev server watches:

  • All .yaml, .yml, .json, .json5 in config directory
  • Custom paths via --watch
  • Excludes node_modules, .git, .lowdefy

On change:

  1. Rebuild config via @lowdefy/build
  2. Hot reload the Next.js dev server
  3. Browser refreshes automatically