Stormy CLI
The stormy command-line tool (@stormycms/cli) does two jobs:
stormy init— scaffold a new project from the official Next.js boilerplatestormy generate— derive a CMS component schema from your existing components, so you don't maintain duplicate schemas between the CMS and your application code
Installation
# Run without installingnpx @stormycms/cli init
# Or install globallynpm install -g @stormycms/clistormy --helpstormy init
Creates a new Stormy CMS project from the bundled boilerplate.
stormy initstormy init --name my-project --target ./my-project --skip-envstormy init --name my-project --skip-install| Option | Description |
|---|---|
-n, --name <name> | Project name. Must be lowercase kebab-case (e.g. my-stormy-site). Prompted if omitted. |
-t, --target <path> | Target directory. Defaults to ./{project name}. Must be empty or nonexistent. |
--skip-env | Skip environment variable prompts; .env files are generated from example values. |
--skip-install | Create the project without running pnpm install. |
What it does, in order:
- Extracts the boilerplate into the target directory
- Applies your project name to
package.json, lockfiles, andREADME.md - Prompts for environment values (unless
--skip-env) and writes.envfiles for both apps - Initializes a git repository
- Installs dependencies with pnpm (unless
--skip-install)
Afterwards:
cd my-projectpnpm dev# Public site: http://localhost:3000# Admin editor: http://localhost:4000stormy generate
Scans a directory of components and generates CMS-wrapped component definitions — a starting export map you can refine by hand.
stormy generatestormy generate --components ./packages/components/src/lib --output ./packages/components/src/index.ts| Option | Description | Default |
|---|---|---|
-c, --components <path> | Path to the components directory | packages/components/src/lib |
-o, --output <path> | Output file path | packages/components/src/index.ts |
-f, --framework <name> | Framework plugin to use | Auto-detected |
Generation infers each component's editable fields from its props (e.g. a title: string prop becomes an input field). Treat the output as a first draft: review field controls, defaults, parent/child constraints, and containment rules, then adjust. See Components & Schema.
Prop type mapping
stormy generate inspects React prop types and selects a CMS field for each one. The React plugin currently maps:
| Prop type | Generated field | Notes | Source |
|---|---|---|---|
string | input | Single-line text | (Native) |
number | input | Numeric input | (Native) |
boolean | checkbox | (Native) | |
Date | dateTime | Date/time picker | (Native) |
LongString | textarea | Multi-line text | @stormymcs/core |
Markdown | markdown | Rich-text / markdown editor | @stormymcs/core |
ImageAsset | image | Media picker (S3-backed) | @stormymcs/core |
string literal union ('a' | 'b') | radio | options set to the union members | (Native) |
Record<string, string> | keyValueList | Repeatable key/value pairs | (Native) |
string[] | textList | (Native) | |
number[] | numberList | (Native) | |
boolean[] | checkboxList | (Native) | |
LongString[] | textareaList | @stormymcs/core | |
Markdown[] | list | With fieldTypes: ['markdown'] | @stormymcs/core |
ImageAsset[] | list | With fieldTypes: ['image'] | @stormymcs/core |
| Custom object / interface / class arrays | complexList | With subFields derived from the object props | (Native) |
| Custom object / interface / class (non-array) | object | With subFields (requires object support) | (Native) |
Framework detection
The framework is resolved in this order:
frameworkinstormy.config.ts- Auto-detection from your
package.jsondependencies (checked in order: Vue, Svelte, Solid, React) - Plugin-based detection
React is the fully supported plugin today (@stormycms/react/plugin); the detection scaffolding for other frameworks anticipates future plugins.
Configuration: stormy.config.ts
Place a stormy.config.ts at your project root to set defaults:
import type { StormyConfig } from '@stormycms/cli';
const config: StormyConfig = { components: './src/components', output: './cms/schema.ts', framework: 'react', // optional; auto-detected if omitted plugins: [], // optional custom framework plugins};
export default config;CLI flags override config values; config values override the built-in defaults.
Plugin System
The CLI supports custom framework plugins, registered by module name or path in the plugins array of stormy.config.ts. A framework plugin implements the StormyPlugin interface:
import type { StormyPlugin, ComponentInfo, GenerateOptions } from '@stormycms/cli';
const myFrameworkPlugin: StormyPlugin = { /** Plugin name (e.g., 'react', 'vue', 'svelte') */ name: 'my-framework',
/** Detect whether this framework is used in the project */ detect: (cwd: string) => { // e.g. inspect package.json dependencies return false; },
/** Parse component files and extract metadata */ parseComponents: (options: GenerateOptions): ComponentInfo[] => { // Read options.components, return one ComponentInfo per component: // { name, fileName, export, componentId, label, fields } return []; },
/** Generate the schema file content written to options.output */ generateSchema: (components: ComponentInfo[], importBasePath: string): string => { return '// generated export map'; },};
export default myFrameworkPlugin;Each ComponentInfo.fields entry maps a component prop to a CMS field ({ label, prop, field, options?, fieldTypes?, subFields? }) — the same shape withCMS consumes (see Components & Schema). @stormycms/react/plugin is the reference implementation: it detects React from your dependencies, parses .tsx component files, infers fields from prop types, and emits a withCMS-wrapped export map.
Last updated: 8/2/26, 3:38 PM