Skip to main content
primo dev runs the full Primo CMS on your machine and keeps it in sync with your local files. You write blocks and content in your editor; the CMS picks up the changes. You make edits in the CMS; they’re written back to disk.

Starting the Dev Server

From a workspace root (the directory containing server.yaml):
primo dev
Each site is served on its own subdomain:
  • http://my-site.localhost:3000 — the published site
  • http://my-site.localhost:3000/admin — the CMS editor
The dev server listens on all interfaces, so you can hit http://<your-lan-ip>:3000 from a phone on the same network to test mobile layouts.

Options

primo dev -p 8080            # Use a custom port
primo dev --author files     # Default: files are source of truth
primo dev --author cms       # CMS is source of truth
primo dev --author both      # Bidirectional (beta)

Author Modes

--author controls which side wins when files and the CMS disagree. This is the most important concept in local dev — pick a mode that matches how you’re working.
Files are source of truth.
  • Edits to local files are imported into the CMS on save.
  • The CMS UI is read-only for content that’s tracked in files — you’ll see a banner.
  • Use this mode when you’re building blocks or page types in your editor.
primo dev --author files

Site Layout

Each site folder follows this layout:
sites/my-site/
├── site.yaml          # Site name, hostname, group
├── site/
│   ├── fields.yaml    # Site-wide fields (logo, nav, etc.)
│   ├── content.yaml   # Values for site fields
│   ├── head.svelte    # Custom <head> content
│   └── foot.svelte    # Custom end-of-body content
├── blocks/
│   └── hero/
│       ├── component.svelte
│       ├── fields.yaml
│       └── content.yaml
├── page-types/
│   └── blog-post/
│       └── config.yaml
├── pages/
│   └── index.yaml
└── uploads/           # Images and files (see below)
See Architecture for the underlying data model.

Uploads

Files dropped into sites/my-site/uploads/ are automatically imported into the CMS as site_uploads records:
sites/my-site/uploads/
├── hero.jpg
└── logo.svg
  • On import, new files become uploads with stable IDs.
  • Hash comparison skips re-upload when content is unchanged.
  • A file removed from uploads/ becomes an orphan upload warning — clean it up in the CMS or remove the record from the file system to delete it.
This means you can drop an image into uploads/ and reference it from an image field without ever opening the CMS.

site.yaml and Hostname

site.yaml holds the site name, hostname, and group. These round-trip between the CMS and files — editing the name in the dashboard updates site.yaml, and editing site.yaml updates the CMS.
host (the deployed hostname for a hosted server) is per-environment and is not overwritten by file sync. This prevents primo push from pointing your production site at localhost.

Avatar Uploads

iPhone HEIC photos are automatically converted to JPEG when uploaded as avatars — no manual conversion required.

Validating Your Work

Run primo validate from the workspace root to check site structure:
primo validate
primo validate --strict    # Treat warnings as errors
For AI-assisted development, the MCP server exposes per-file validators (validate_block, validate_page, validate_site) that agents call automatically.

Next Steps

Sync with a Hosted Server

Pull and push changes against a deployed Primo

Deploy

Ship your workspace to production