Getting Started with StormyCMS
This guide takes you from nothing to a running Stormy site with its own admin editor.
Prerequisites
- Node.js 20.9 or newer
- pnpm 10 (
corepack enableornpm i -g pnpm) - A Stormy CMS site with client credentials (Client ID and Client Secret)
- Optional: S3-compatible object storage for media uploads from the admin editor
Step 0: Create a Site and Get Credentials
- Sign in at account.stormycms.com with GitHub or Google (every account includes one free site with one seat)
- Go to Dashboard → Sites → New Site and create your site
- Open your site's Keys page to copy your Client ID
- Generate your Client Secret from the same page — it's revealed once, so store it somewhere safe
If you ever need to rotate credentials, the Keys page can reset both the client ID and the client secret at any time.
Step 1: Scaffold a Project
The stormy init command creates a new project from the official Next.js boilerplate:
npx @stormycms/cli init# or, with the CLI installed globally:stormy initYou'll be prompted for a project name and target directory, then for your environment values (optional). The CLI then initializes a git repository with an initial commit and installs dependencies.
Non-interactive usage:
stormy init --name my-project --target ./my-project --skip-envstormy init --name my-project --skip-install| Flag | Description |
|---|---|
-n, --name <name> | Project name (lowercase kebab-case, e.g. my-stormy-site) |
-t, --target <path> | Target directory (defaults to ./{project name}) |
--skip-env | Skip environment prompts and use example values |
--skip-install | Create the project without installing dependencies |
Step 2: What You Get
The generated project is a pnpm + Turborepo monorepo:
my-stormy-site/├── apps/│ ├── site/ # Public CMS-rendered site (localhost:3000)│ └── admin/ # Your own admin editor (localhost:4000)└── packages/ ├── components/ # Shared React components + CMS export map └── types/ # Shared ambient type declarationsThe key idea: packages/components is imported by both apps. The admin editor renders the same components as the public site, so previews are always accurate — and there is no separate schema to maintain in an external portal.
Step 3: Configure Environment Variables
If you used --skip-env, copy and fill in the env files:
cp apps/admin/.env.example apps/admin/.envcp apps/site/.env.example apps/site/.envapps/site/.env
| Variable | Description |
|---|---|
NEXT_PUBLIC_SITE_URL | The public site URL (e.g. http://localhost:3000) |
STORMY_CMS_CLIENT_ID | Your site's client ID (sent as x-client-id) |
STORMY_CMS_CLIENT_SECRET | Your site's client secret (sent as x-client-secret) |
apps/admin/.env additionally needs:
| Variable | Description |
|---|---|
STORMY_CMS_REDIRECT_URL | OAuth callback, e.g. http://localhost:4000/api/auth/stormy |
NEXT_PUBLIC_SITE_URL | The admin URL used for auth redirects (e.g. http://localhost:4000) |
NEXT_PUBLIC_PREVIEW_SITE_URL | The public site URL for previews (e.g. http://localhost:3000) |
S3_ENDPOINT, S3_BUCKET, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_REGION | S3-compatible storage for media uploads |
Important: never commit .env files or expose STORMY_CMS_CLIENT_SECRET in client-side code.
Step 4: Run It
pnpm dev- Public site: http://localhost:3000
- Admin editor: http://localhost:4000
Sign in to the admin with GitHub or Google. You can now create layouts and pages visually, edit component fields, and manage media — all rendered with your own components.
Step 5: Make Your First API Request (Optional)
Everything the admin does goes through the same GraphQL API you can call directly:
const response = await fetch('https://api.stormycms.com/graphql', { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-client-id': process.env.STORMY_CMS_CLIENT_ID, 'x-client-secret': process.env.STORMY_CMS_CLIENT_SECRET, }, body: JSON.stringify({ query: ` query GetPages($limit: Int, $offset: Int) { pages(limit: $limit, offset: $offset) { id slug metadata { title description keywords } } } `, variables: { limit: 10, offset: 0 }, }),});
const result = await response.json();console.log(result.data.pages);Most applications won't need raw fetch calls — @stormycms/core provides a typed client (StormyCMSClient) that handles headers, auth, and parsing for you.
What's Next?
- Components & Schema - Register your own components with
withCMS - CLI Reference - Generate schemas from existing components with
stormy generate - Boilerplate Tour - Understand the generated project in depth
- GraphQL Queries and Mutations - Work with the API directly
Security Best Practices
- Never expose your client secret in client-side code — keep API calls in server components, route handlers, or server actions
- Use environment variables for all credentials
- Reset your client secret (via the API or your account portal) if you suspect it's been compromised
- Use HTTPS for all API requests in production
- Use a restricted S3 bucket credential for media uploads in production
Last updated: 7/10/26, 3:17 AM