CLI commands

VextJS provides the vext command line tool, covering the complete life cycle of project creation, development, construction and deployment.

Installation

The vext CLI is installed with the vextjs package, no additional installation is required:

npm install vextjs

After installation, it can be called in the following ways:

# via npx
npx vext <command>

# Via package.json scripts (recommended)
npm run dev # → vext dev
npm start # → vext start
npm run build # → vext build

Command overview

CommandDescriptionCommon scenarios
vext create <name>Create a new projectProject initialization
vext devStart development modeDaily development
vext buildBuild projectBuild before deployment
vext typegenGenerate declaration + service dependency diagnosis (experimental)TS/JS project engineering assistance
vext doctor routesStatic route diagnosis + inspect / manifest (experimental)OpenAPI / routing management
vext startStart production modeProduction deployment
vext stopStop serviceCluster mode management
vext reloadRolling restartZero-downtime updates
vext statusView running statusCluster status monitoring

vext create — Create a project

Interactively create new VextJS projects and automatically generate project skeleton and configuration files. The default template is fullstack-react; API-only scaffolding remains available through --template api --frontend none.

Usage

npx vextjs create <project-name> [options]

Options

OptionsDescriptionDefault
--template <name>Project template (fullstack-react / api)fullstack-react
--frontend <name>Frontend target (react / none)react
--adapter <name>Specify Adapter (native/hono/fastify/express/koa)native
--jsCreate a JavaScript project (not TypeScript)false
--skip-installSkip npm installfalse
--forceForce overwriting if the target directory exists and is not emptyfalse
-h, --helpShow help

Example

# Create TypeScript full-stack project (default Native Adapter)
npx vextjs create my-app

#Specify Adapter
npx vextjs create my-app --adapter hono
npx vextjs create my-app --adapter fastify

# Create JavaScript full-stack project
npx vextjs create my-app --js

# Create API-only project
npx vextjs create my-api --template api --frontend none

# Skip dependency installation
npx vextjs create my-app --skip-install

Generated directory structure

my-app/
├── preload/
│ └── README.md # Project-level preload script placeholder description
├── public/
│ └── favicon.svg # Static asset copied into the frontend build
├── src/
│ ├── client/
│ │ ├── App.tsx # React app
│ │ ├── index.html # HTML shell
│ │ ├── main.tsx # Browser entry
│ │ └── styles.css
│ ├── config/
│ │ ├── default.ts #Default configuration (port: 3000)
│ │ ├── development.ts # Development environment coverage
│ │ ├── production.ts # Production environment coverage (port: 3001)
│ │ ├── local.example.ts # Enable local coverage after copying to local.ts
│ │ └── bootstrap.example.ts # Copy to bootstrap.ts and enable startup provider
│ ├── routes/
│ │ └── index.ts # Example routing
│ ├── services/
│ │ └── example.ts # Example service
│ ├── middlewares/
│ │ └── README.md # Custom middleware placeholder description
│ ├── plugins/
│ │ └── README.md # Custom plug-in placeholder description
│ ├── locales/
│ │ └── README.md # i18n language pack placeholder description
│ └── types/
│ └── generated/
│ └── .gitkeep # typegen output directory placeholder (TS project)
├── package.json
├── tsconfig.json
└── .gitignore

After creation is complete:

cd my-app
npm run dev

Visit http://localhost:3000 and you should see the React client. API routes are available at /api/hello and /api/health.

If you need to pull remote configuration (such as Nacos/bootstrap database configuration) before the configuration is frozen, you can copy src/config/bootstrap.example.ts to src/config/bootstrap.ts and register the provider through defineBootstrapConfig(). When local coverage is required, src/config/local.example.ts can be copied to src/config/local.ts, which is excluded by .gitignore by default.

vext dev — development mode

Start the project in development mode, supporting file monitoring and smart hot reloading.

Usage

vext dev [options]

Options

OptionsDescriptionDefault
--port <number>Specify portValue in configuration file
--host <address>Specify the listening addressValue in the configuration file
--debounce <ms>Debounce interval (milliseconds, 0 = disable)0
--pollForce polling mode (Docker/NFS environment)false
--poll-interval <ms>Polling interval (milliseconds, only valid when --poll is used)1000
--no-hotDisable Soft Reload, all changes go to Cold Restart
--strict-preflightMake TypeScript semantic diagnostics re-block startup/reloading
--port-conflict <strategy>Port conflict strategy (error/prompt/kill/next)error
--verbose-lifecycleOutput detailed lifecycle logs and complete watcher change list
--startup-profileOutput startup phase summary and detailed time consumption
--startup-profile-json <p>Write startup phase time to JSON file
--clearClear the console after each reload
-h, --helpShow help

Port conflict policy

  • error: direct failure (default)
  • prompt: Ask the parent process how to handle it in TTY environment
  • kill: Try to kill the process occupying the port
  • next: automatically selects the next available port
vext dev --port-conflict prompt
vext start --port-conflict next

Start log tiering

By default, vext dev only prints the listening address and total startup time, and then prints the necessary results during cold restart / hot reload. vext dev --startup-profile will output a human-readable startup summary and detailed events; the summary is main/preflight, main/preload, pre-worker-bootstrap, compile, config, i18n, database, plugins, middleware, services, routes, openapi, listen, onReady Classification in other stages; unnamed empty windows that exceed the threshold will be entered into profile JSON in the form of gap.*.

--startup-profile-json <path> only writes JSON files and will not automatically print summary or details; if you need to output both at the same time, you can combine --startup-profile --startup-profile-json <path>.

If you need life cycle troubleshooting details, you can enable:

vext dev --verbose-lifecycle
VEXT_VERBOSE_LIFECYCLE=1 vext start

Example

# Use default settings from configuration file
vext dev

#Specify port
vext dev --port 8080

#Specify address and port
vext dev --host 127.0.0.1 --port 8080

# Turn on 50ms anti-shake (merged into one reload when saving in quick succession)
vext dev --debounce 50

# Docker/NFS environment uses polling mode
vext dev --poll --poll-interval 2000

# Disable Soft Reload (all changes go to Cold Restart)
vext dev --no-hot

# Output the summary and detailed time consumption of the startup phase
vext dev --startup-profile

# Only write JSON, do not print summary/details
vext dev --startup-profile-json .vext/inspect/startup-profile.json

Hot reload strategy

vext dev provides a three-layer hot reload strategy and automatically selects the optimal method:

LevelTrigger ConditionBehaviorSpeed
Tier 1 — Hot route replacementsrc/routes/ file changesAtomic replacement request handler, zero interruption⚡ Millisecond level
Tier 2 — Service Reloadsrc/services/ or src/locales/ file changesRebuild affected service instances⚡ Milliseconds
Tier 3 — Cold Rebootsrc/config/ or src/plugins/ file changesFull restart process🔄 Seconds

See the Hot Reload chapter for details.

Frontend files under src/frontend/** and static assets under public/** trigger a frontend rebuild message. React pages, layouts, and shared components use Fast Refresh by default; they do not require a backend cold restart unless mixed with backend changes.

package.json script

{
  "scripts": {
    "dev": "vext dev"
  }
}

vext build — Build the project

Compile TypeScript source code into JavaScript to generate a production-usable dist/ directory; tool products such as typegen and route manifest will be refreshed before building. When frontend is enabled, vext build also bundles the browser client into dist/client/.

Usage

vext build [options]

Options

OptionsDescriptionDefault
--outdir <path>Output directorydist
--cleanClean the output directory before compilationfalse
--sourcemapGenerate source maptrue
--no-sourcemapDisable source map
--minifyCompress output codefalse
--typecheckExecute tsc --noEmit after refreshing generated / manifestfalse
--upload-assetsUpload frontend static assets after the frontend buildfalse
--deploy-dry-runPrint the frontend upload plan without writing assetsfalse
-h, --helpShow help

Example

# Build project
vext build

# Refresh generated / manifest and then perform type checking and build again
vext build --typecheck

# Clean old dist and build
vext build --clean

#Specify output directory
vext build --outdir build

# Upload frontend static assets after building
vext build --upload-assets

# Print the frontend upload plan only
vext build --upload-assets --deploy-dry-run

# Start after building
vext build && vext start

Build behavior

  • Refresh .vext/types/*.generated.d.ts, src/types/generated/index.d.ts, .vext/manifest/services.json and .vext/manifest/routes.json first
  • When --typecheck is enabled, execute tsc --noEmit after refreshing the generated / manifest
  • Use esbuild for server compilation and frontend bundling
  • The output directory defaults to dist/
  • Maintain source code directory structure
  • .js and .js.map files are generated by default; declaration files will not be generated in dist/
  • When frontend is enabled, dist/client/index.html, manifest.json, deploy-manifest.json, size-report.json, static assets, and client contract artifacts are generated
  • When --upload-assets is used, Vext reads dist/client/deploy-manifest.json and uploads only changed static assets by sha256 and frontend.deploy.upload.stateFile

package.json script

{
  "scripts": {
    "build": "vext build",
    "prepublishOnly": "vext build"
  }
}
development vs build
  • vext dev: Load .ts files directly from src/, compile on-the-fly through esbuild, support hot reloading
  • vext build: compile src/ to dist/, load production mode from dist/ :::

vext deploy assets — Upload frontend static assets

Read dist/client/deploy-manifest.json and upload JavaScript, CSS, images, fonts, and copied public/** resources to the configured target. The first built-in adapters are filesystem and mock; cloud vendors can be connected through a custom deploy adapter.

Usage

vext deploy assets [options]

Options

OptionsDescriptionDefault
--outdir <path>Build output directorydist
--manifest <path>Deploy manifest pathdist/client/deploy-manifest.json
--adapter <name>Upload adapter, such as filesystem or mockConfig value
--target-dir <path>Filesystem adapter target directoryConfig value
--prefix <path>Upload key prefixConfig value
--state-file <path>Incremental upload state fileConfig value
--dry-runPrint the upload plan without writing assetsfalse
-h, --helpShow help

Example

# Use the upload target from configuration
vext deploy assets

# Plan only
vext deploy assets --dry-run

# Override this upload target directory and key prefix
vext deploy assets --target-dir .deploy/cdn --prefix my-app/v1

On the second run, Vext reads frontend.deploy.upload.stateFile and compares each uploadKey sha256. Unchanged JavaScript, CSS, images, fonts, and stable public files are skipped instead of uploaded again. index.html and source maps are not part of the default deploy manifest because Vext still renders HTML from the server path and keeps source maps out of CDN publishing by default.

vext typegen — Generate declarations and perform service dependency diagnostics (experimental)

Provide generated declarations for app.services and app.extend() / defineAppExtensions<{ ... }>() in plugins, and perform tooling-only service dependency checks.

Usage

vext typegen [options]

Options

OptionsDescriptionDefault
--servicesGenerate only services.generated.d.tsfalse
--app-extensionsGenerate only app-extensions.generated.d.tsfalse
--checkOnly verify generated results, do not write filesfalse
--jsonOutput machine-readable JSONfalse
--write-manifestWrite .vext/manifest/services.jsonfalse
--root <path>Specify the project root directoryCurrent directory
-C <path>--root alias
--verboseReserved for subsequent detailed loggingfalse
-h, --helpShow help

Products

.vext/types/services.generated.d.ts
.vext/types/app-extensions.generated.d.ts
src/types/generated/index.d.ts
.vext/manifest/services.json

Example

vext typegen
vext typegen --check
vext typegen --write-manifest
vext typegen --services --root ./examples/hello-world

Applicable Boundary

  • typegen as a whole still belongs to the tooling-only capability and will not enter the main runtime path of vext start;
  • vext dev will automatically execute basic typegen in preflight, vext build will also refresh generated declarations and manifests before optional typecheck and compilation;
  • TypeScript semantic diagnostics are output asynchronously after ready / reload by default; if you want to block startup or reload like the old behavior, you can use --strict-preflight or VEXT_DEV_STRICT_PREFLIGHT=1;
  • TS projects give priority to output high-quality types, JS projects allow regression to import(...).default / unknown, but the command itself is still available;
  • --write-manifest will write the service index, app.extend() / defineAppExtensions<{ ... }>() aggregation results and service dependency graph summary into .vext/manifest/services.json;
  • More examples of generated declarations can be viewed in conjunction with the Services and Plugins documentation.

vext doctor routes — Static routing diagnosis (experimental)

Scan the static route metadata in src/routes/, output diagnostics such as duplicate routes, missing docs.summary, automatic inference of operationId, etc., and save the results to the inspect/manifest product.

Usage

vext doctor <target> [options]

Targets

TargetDescription
routesScan static route metadata and OpenAPI related fields
allCurrently still an alias of routes, used to reserve subsequent extension bits

Options

OptionsDescriptionDefault
--jsonOutput machine-readable JSONfalse
--write-inspectWrite .vext/inspect/routes.jsonfalse
--write-manifestWrite .vext/manifest/routes.jsonfalse
--refreshSkip cache manifest and rescan routing diagnosticsfalse
--root <path>Specify the project root directoryCurrent directory
-C <path>--root alias
-h, --helpShow help

Product positioning

ProductsPositioningApplicable objects
.vext/inspect/routes.jsoninspect / diagnostic middle layer, including diagnostic details and debugging fieldsdoctor, debug, in-depth analysis
.vext/manifest/routes.jsonStable consumption layer, fields converge to routes-only manifestEditor, CI, visualization, follow-up codemod

Example

vext doctor routes
vext doctor routes --write-inspect
vext doctor routes --write-inspect --write-manifest --json

Current boundary

  • The current route manifest and services manifest are still maintained hierarchically and are not merged into a single overall manifest;
  • When docs.operationId is missing, the doctor will give an auto-operation-id information prompt according to the runtime behavior instead of false warning;
  • The routing side is still in charge of doctor routes --write-manifest; the service side is in charge of typegen --write-manifest.

vext start — Start production mode

Start the project in production mode. TypeScript projects load compiled code from the dist/ directory and need to execute vext build first; if there is no valid build product, the command will fail directly and prompt you to use vext build or use vext dev during development.

Usage

vext start [options]

Options

OptionsDescriptionDefault
--port <number>Specify portValue in configuration file
--host <address>Specify the listening addressValue in the configuration file
--port-conflict <strategy>Port conflict strategy (error/prompt/kill/next)error
--startup-profileOutput summary and detailed time consumption of production startup phase
--startup-profile-json <p>Write the production startup phase time to a JSON file
--verbose-lifecycleOutput detailed lifecycle logs
-h, --helpShow help

Example

#Build first, then start
vext build
vext start

#Specify port
vext start --port 8080

# Automatically switch to the next available port when there is a port conflict
vext start --port-conflict next

# Check the production cold-start phase time consumption
vext start --startup-profile
vext start --startup-profile-json .vext/inspect/start-profile.json

# Load the production profile and override the port
vext start --port 8080

# Load a custom config profile (src/config/sg-sit.ts needs to exist)
vext start --config sg-sit

Default command

When no command is passed, vext executes start by default:

# The following two methods are equivalent
vext
vext start

Cluster mode

If cluster is enabled in the configuration, vext start will automatically enter Cluster mode, and the Master process will manage multiple Worker processes:

// src/config/production.ts
export default {
  cluster: {
    enabled: true,
    workers: "auto", // Automatically detect the number of CPU cores
  },
};

Or enable via environment variable:

VEXT_CLUSTER=1 vext start

Preload (Preload) automatic injection

vext start and vext dev will automatically parse two types of preload sources:

  1. vext.preload declared in the installed dependency package
  2. preload/ in the root directory of the application project

These scripts will be injected uniformly through --import before the child process is started. For example, vextjs-opentelemetry can use the package-level vext.preload to automatically initialize the OpenTelemetry SDK before loading the application code; the application project itself can also directly place a script in the root directory preload/ to bridge the pre-launch environment.First phase project-level preload rules:

  • The directory is fixed to the project root preload/
  • Non-recursive scan
  • Project-level preload is executed first, and package-level preload is executed later.
  • .mjs / .js direct injection
  • .ts / .mts will be compiled into .vext/preload/*.mjs before startup and then injected
  • If the files in preload/ change under vext dev, cold restart will be triggered.

See Preload for details.

Configuring Provider during startup

If src/config/bootstrap.ts exists in the project, vext start / vext dev will execute the bootstrap config provider declared in it before configuring validate / freeze, and merge the patch returned by the provider into the final configuration. The priority is: default < config profile < local < provider < CLI.

In Cluster mode, the Master will pass the current round of provider patches to the Worker for reuse, preventing the Master/Worker from seeing different remote configurations in the same startup cycle.

package.json script

{
  "scripts": {
    "build": "vext build",
    "start": "vext start",
    "start:sg-sit": "vext start --config sg-sit",
    "start:us-uat": "vext start --config us-uat",
    "deploy:assets:sg-sit": "vext deploy assets --config sg-sit --dry-run"
  }
}

:::tip Config profile selection vext start, vext build, and vext deploy assets default to the production profile. vext dev defaults to the development profile. To select a custom profile:

  • CLI argument: vext start --config sg-sit
  • Environment variable: VEXT_CONFIG=sg-sit vext start

The profile name maps to src/config/{profile}.ts and, after build, dist/config/{profile}.js.

vext stop — stop the service

Stop a running Cluster mode service. Send a stop signal by reading the PID file.

Usage

vext stop [options]

Options

OptionsDescriptionDefault
--pid-file <path>PID file path.vext.pid
--forceForced termination (SIGKILL)false
-h, --helpShow help

Example

# graceful stop
vext stop

# force stop
vext stop --force

#Specify PID file
vext stop --pid-file /var/run/myapp.pid
Info

vext stop is only available in Cluster mode. In single-process mode, just use Ctrl+C or send SIGTERM signal to shut down gracefully.

vext reload — rolling restart

Triggers a zero-downtime rolling restart in Cluster mode. Restart Worker processes one by one to ensure that the service is always available.

Usage

vext reload [options]

Options

OptionsDescriptionDefault
--pid-file <path>PID file path.vext.pid
-h, --helpShow help

Example

# Rolling restart after deploying new version
vext build
vext reload

Rolling restart process

1. Send the SIGUSR2 signal to the Master process
2. Master restarts Workers one by one:
   a. Start a new Worker
   b. Wait for the new Worker to be ready
   c. Gracefully shut down the old Worker
   d. Repeat until all Workers are updated
3. There is always a Worker to process requests throughout the entire process, with zero downtime.
Applicable scenarios

After the code is updated, execute vext build + vext reload to complete the version update without downtime. Suitable for production environments requiring high availability.

vext status — View running status

View the service running status in Cluster mode, including information about the Master process and each Worker process.

Usage

vext status [options]

Options

OptionsDescriptionDefault
--pid-file <path>PID file path.vext.pid
-h, --helpShow help

Example

vext status

Output example

VextJS Cluster Status

Master PID: 12345
Workers: 4/4 running
Uptime: 2d 5h 32m

  PID State CPU Memory Requests
  12346 online 2.1% 48 MB 125,432
  12347 online 1.8% 52 MB 124,891
  12348 online 2.3% 47 MB 126,003
  12349 online 1.9% 50 MB 125,720

Global options

All commands support the following global options:

OptionsDescription
-h, --helpDisplay help information
-v, --versionDisplay version number
# View version
vext --version
# Output: vextjs v0.3.26

# View help
vext --help
{
  "name": "my-app",
  "type": "module",
  "scripts": {
    "dev": "vext dev",
    "build": "vext build",
    "start": "vext start",
    "stop": "vext stop",
    "reload": "vext reload",
    "status": "vext status",
    "test": "vitest run",
    "test:watch": "vitest",
    "test:cov": "vitest run --coverage",
    "typecheck": "tsc --noEmit"
  }
}

FAQ

vext start reports error "dist/ not found"

You need to execute vext build first to compile the TypeScript code. vext start loads compiled JavaScript files from dist/.

If frontend is enabled, vext start also requires dist/client/index.html.

Should I use vext dev or vext start when developing?

Daily development uses vext dev, which directly loads TypeScript files under src/ and supports hot reloading without manual compilation. vext start is used in production environments.

How to specify Node.js version?

VextJS requires Node.js >= 20.19.0. It is recommended to create a .node-version or .nvmrc file in the project root directory to specify the version:

echo "22" > .node-version

vext stop / vext reload / vext status not working?

These three commands are only available in Cluster mode. Make sure cluster.enabled: true is enabled in the configuration or the VEXT_CLUSTER=1 environment variable is used, and the service is started via vext start.

Next step