A multi-project tool for generating and seeding mock data into Webiny CMS instances. Manages project connections (encrypted), syncs models/groups/tenants from live Webiny, generates realistic fake data respecting CMS field validation, and sends entries via GraphQL. Includes a CLI, REST API, and web UI.
yarn installyarn cli initThis generates a .env file with a random encryption key and default port config:
ENCRYPTION_KEY=<64-char hex>
API_PORT=4000
UI_PORT=4001
Option A: Via CLI
yarn cli add-projectPrompts for project name, Webiny API URL, API token, tenant, and version.
Option B: Via seed file (recommended for teams)
Create .projects.json in the project root:
[
{
"name": "My Webiny Project",
"apiUrl": "https://your-api.webiny.com",
"apiToken": "your-api-token",
"tenant": "root",
"webinyVersion": "6.0.0"
}
]Projects are upserted by name on every server start. The API token is encrypted before storage. See .projects.json.example for the format.
Important:
.projects.jsoncontains real API tokens — it is gitignored. Never commit it. Only.projects.json.examplewith placeholder values is tracked.
yarn devThis starts both the API server (port 4000) and the UI (port 4001) with hot reload.
Open http://localhost:4001 in your browser.
If not already seeded via .projects.json, add a project:
- Click Add Project on the project list page
- Enter project name, Webiny API URL, API token, tenant, and version
Before seeding or importing, the project needs tenants and models pulled from Webiny:
- Open the project
- Go to Pull Tenants — click Pull Tenants to discover tenants from the Webiny instance
- Go to Pull Models — click Pull Models to pull CMS model definitions and groups
These must be done in order — tenants first, then models. After pulling, the tenants and models tabs show what was discovered.
Option A: Seed new mock data
- Go to Seed Data
- Select a target tenant
- Set entries per model and revisions (e.g.
1or1-5for a random range) - Select which models to seed (grouped by content model group)
- Optionally override entries/revisions per model
- Choose a publish strategy (none, all, random %, first revision, last revision)
- Optionally enable unpublish cycles (simulates real content lifecycle)
- Click Seed Data — a confirmation dialog shows all settings and lets you adjust batch size (concurrent mutations)
- Confirm to start the job
Option B: Import existing entries from Webiny
- Go to Import to pull existing entries from the Webiny instance into the local audit log
- Imported entries become available as refs for future seed runs
All operations run as background jobs with real-time progress via WebSocket. Check the Jobs tab for status, logs, and to cancel running jobs.
- Dependency ordering: models with ref fields are seeded after the models they reference — e.g.
productCategoryseeds beforeproduct - Available refs: all previously seeded and imported entries are available for ref fields, so you can seed categories in one run and products in another
- Batch size: controls how many GraphQL mutations run concurrently (1–50). Higher = faster but more load on Webiny
- Fail fast: if a mutation fails for a model, seeding stops for that model and moves to the next
- Rate limiting: automatic retry on HTTP 429 with exponential backoff (up to 3 retries)
| Command | Description |
|---|---|
yarn cli init |
Generate .env with encryption key + port config |
yarn cli add-project |
Add a Webiny project interactively |
yarn cli list-projects |
Show all configured projects |
yarn cli remove-project |
Select + confirm + remove a project |
yarn cli pull-models |
Pull models/groups from a Webiny project |
yarn cli seed |
Generate + send mock entries (select project → tenants → models → amounts) |
yarn cli rotate-key |
Rotate the API token encryption key |
yarn cli upload-files |
Upload files to a Webiny project's file manager |
CLI (src/cli/) → shared services (src/shared/node/)
API (src/api/) → shared services
UI (src/ui/) → API via HTTP + WebSocket
- Shared layer (
src/shared/node/): SQLite persistence, GraphQL client, generators, job execution - API layer (
src/api/): Fastify REST + WebSocket server - UI layer (
src/ui/): React + Mantine + MobX - DI:
@webiny/dicontainer with abstractions/implementations pattern
All long-running operations (seed, sync, import, cleanup) run as background jobs:
- API route enqueues a job → returns 202 with job ID
- JobWorker polls every 3s, picks up pending jobs, runs executor
- Progress + logs pushed to UI via WebSocket in real-time
- UI shows toast notification on completion/failure
- Affected data auto-refreshes in the UI
Job types: seed, pull-tenants, pull-models, cleanup, import.
Every seeded entry is logged with:
- Request: full GraphQL mutation, variables, URL (auth token redacted)
- Response: complete raw HTTP response from Webiny
- Error: error message if the mutation failed
Click any entry in the Audit Log tab to see the full request/response detail.
| Script | Command | Purpose |
|---|---|---|
yarn dev |
concurrently |
API + UI together |
yarn cli |
tsx src/cli/entry.ts |
CLI tool |
yarn api:dev |
tsx --watch src/api/entry.ts |
API server only |
yarn ui:dev |
vite dev |
UI dev server only |
yarn typecheck |
tsc --noEmit |
Type checking |
yarn test |
vitest run |
Run tests |
yarn test:watch |
vitest |
Watch mode |
yarn lint |
oxlint |
Lint check |
yarn format:check |
oxfmt --check |
Format check |
yarn db:generate |
drizzle-kit generate |
Generate DB migration |
Before every commit: yarn lint && yarn format:check && yarn typecheck && yarn test
| Variable | Required | Default | Purpose |
|---|---|---|---|
ENCRYPTION_KEY |
Yes | — | 64-char hex for AES-256-GCM token encryption |
API_PORT |
No | 4000 | Fastify server port |
UI_PORT |
No | 4001 | Vite dev server port |
DB_PATH |
No | .webiny/data-mock.db |
SQLite database path |
All runtime data is stored in .webiny/ (gitignored):
.webiny/
├── data-mock.db # SQLite database
├── cache/ # File cache
└── logs/ # Log files
.projects.json is read on every server start. Projects are matched by name — existing projects are updated, new ones are inserted. This is the recommended way to share project connections across a team (each developer creates their own .projects.json from the example).
cp .projects.json.example .projects.json
# Edit .projects.json with your real values