Initial Setup Variables
These variables only take effect on first startup when initializing a new instance:PRIMO_SUPERUSER_EMAIL
Creates the initial PocketBase superuser for the backend dashboard at /_/. This is separate from the regular user account you use to sign in to Primo.
- Type: String (email address)
- Required: No
- Default: None
- When to use: Automated deployments, skipping manual setup
PRIMO_SUPERUSER_PASSWORD
Password for the initial superuser account.
- Type: String
- Required: Only if
PRIMO_SUPERUSER_EMAILis set - Default: None
- Minimum: 8 characters
PRIMO_USER_EMAIL
Creates an initial regular user account.
- Type: String (email address)
- Required: No
- Default: None
- When to use: Create the initial Primo administrator. This account receives the server Developer role; it is not a restricted Content Editor.
PRIMO_USER_PASSWORD
Password for the initial regular user account.
- Type: String
- Required: Only if
PRIMO_USER_EMAILis set - Default: None
- Minimum: 8 characters
PRIMO_APP_URL
Sets the base URL for the application. Used for generating links in emails and backend processes.
- Type: String (URL)
- Required: No
- Default: PocketBase’s configured application URL; set the public HTTPS URL explicitly for automated setup
- When to use: Email notifications, API callbacks
Custom Domain Variables
These control how sites get a public address: an automatic subdomain on creation, and connecting a site’s own custom domain.PRIMO_BASE_DOMAIN
A base domain used to assign new sites a subdomain
(<site-slug>.<base-domain>) when they are created. The address works publicly
only after you configure wildcard DNS and TLS. Without it, new sites
start unassigned (editable but not publicly served) until a domain is connected.
- Type: String (domain)
- Required: No
- Default: Empty (new sites start unassigned)
- When to use: Multi-site instances where every site should be reachable immediately without manual DNS.
PRIMO_DOMAIN_PROVIDER
Selects how connecting a site’s own custom domain works. manual (the default)
shows the DNS records to add and leaves routing/TLS to your reverse proxy;
railway attaches the domain through Railway’s API and reports certificate
status back to the editor.
- Type: String (
manual|railway) - Required: No
- Default:
manual - When to use: Set to
railwaywhen the instance runs on Railway and you want custom domains attached automatically.
PRIMO_RAILWAY_TOKEN
A Railway project access token scoped to the same environment as Primo, used
only when PRIMO_DOMAIN_PROVIDER is railway. Create it in the Railway dashboard
under the project’s Settings → Tokens (environment-scoped within the project; use
the least-privileged token). A token for a different environment causes domain
provisioning to fail. The project/environment/service IDs Railway injects
automatically (RAILWAY_PROJECT_ID, etc.) supply the rest.
- Type: String (token)
- Required: Only when
PRIMO_DOMAIN_PROVIDER=railway - Default: Empty
Operations Variables
These adjust built-in safeguards. The defaults suit most deployments.PRIMO_RATE_LIMIT
Rate limiting is on by default. Signed-out requests are limited, including repeated sign-in attempts, which gives brute-force protection. Signed-in editors aren’t throttled.
- Type:
offto disable - Required: No
- Default: Enabled
- When to use: Your own proxy or firewall already rate-limits requests
This is read once: on the first start of a new instance, or the first start after upgrading to 3.2.7 or later. After that, change rate limits in the PocketBase admin UI (
/_/ → Settings → Rate limits).PRIMO_BACKUP_CRON
Schedule for automatic database backups, as a cron expression. Backups are stored on the data volume in pb_data/backups/, and the 7 most recent are kept.
- Type: Cron expression
- Required: No
- Default:
0 3 * * *(daily at 03:00)
This is read only on the first start of a new instance. After that, manage the schedule in the PocketBase admin UI (
/_/ → Settings → Backups). Backups on the same volume protect against mistakes, not against losing the volume; for off-site copies, configure S3 storage there too.PRIMO_ENABLE_USAGE_STATS
Controls CMS usage analytics, including server heartbeats and editor events. In the v3.3.1 source, self-hosted instances default to off and hosted mode defaults to on. The variable overrides this default when set.
- Type:
trueorfalse - Required: No
- Default:
falsefor self-hosted instances;truein hosted mode (PRIMO_HOSTED_MODE=true) in the v3.3.1 source
false to opt out, then restart or redeploy your CMS service. Use false explicitly when analytics must stay off. Verify the effective setting with curl -fsS https://cms.example.com/api/primo/info and check telemetry_enabled; do not rely only on the deployment mode.
See Usage analytics in the self-hosting guide for a short overview.
CORS_ALLOWED_ORIGINS
Controls the custom CORS middleware for requests from another origin. Leave it unset for ordinary same-origin CMS use. For an external dashboard, set a comma-separated list of complete origins, including the scheme and any port.
* allows any origin without credentials and is intended for public marketplace access. PRIMO_APP_URL does not configure CORS. Restart the service after changing this setting.
Common Configurations
Development Setup
Production with Manual Setup
Production with Automated Setup
PRIMO_USER_EMAIL; use PRIMO_SUPERUSER_EMAIL for the PocketBase dashboard.
Docker Compose Example
Railway Template
Railway automatically handles environment variables through their UI:- Deploy using the Railway button
- Set environment variables in Railway dashboard
- Apply the staged variable changes and redeploy the service
Security Best Practices
Never commit passwords to version control
Never commit passwords to version control
Use environment variables, secrets management, or encrypted files. Never hardcode passwords in
docker-compose.yml or other config files.Use strong passwords
Use strong passwords
Generate random passwords with at least 16 characters:
Rotate passwords regularly
Rotate passwords regularly
Change initial passwords after setup, especially for production environments.
Use secrets management
Use secrets management
For production deployments, use:
- Railway: Built-in secrets
- Docker Swarm: Docker secrets
- Kubernetes: Kubernetes secrets
- Vault: HashiCorp Vault
Limit who has access to environment variables
Limit who has access to environment variables
Environment variables contain sensitive information. Restrict access to deployment configurations.
Troubleshooting
Setup screen appears even with account variables set
Both email and password must be present when the initialization migration runs. Check container logs for validation errors and confirm the variables reached the service. Existing databases do not re-run account creation when you change these variables. To recover PocketBase access without deleting data, see Locked out of admin. In PocketBase, create or update a regularusers record with the intended server role for CMS access.
Account variables do not update existing passwords
Change an existing user’s password through PocketBase or the password-reset workflow. ChangingPRIMO_USER_PASSWORD or PRIMO_SUPERUSER_PASSWORD after initialization does not rotate the account password. You do not need to delete a database or Docker volume to recover access.
Next Steps
Deployment Guide
Learn how to deploy Primo to production
Troubleshooting
Solve common deployment issues