ProsewireDocs

Configuration map

Runtime, authentication, email, bootstrap, worker, and documentation-site settings for Prosewire.

Keep production configuration in the deployment platform’s secret store. Do not commit a populated .env file or bake secrets into an image.

Runtime and database

VariableRequiredPurpose
DATABASE_URLYesPostgres connection used by migrations, web, and worker
REDIS_URLWorkerRedis connection used by Effect DurableQueue for email delivery
PROSEWIRE_PUBLIC_URLProductionExternal origin used by the server for links such as invitations
NEXT_PUBLIC_PROSEWIRE_PUBLIC_URLProductionMatching browser-visible origin used by the authentication client
PROSEWIRE_DEPLOYMENTNoself-hosted for one implicit team or cloud for multiple explicit workspaces; defaults to self-hosted
PROSEWIRE_DEFAULT_BLOGNoDevelopment default publication slug; defaults to fieldnotes
PROSEWIRE_MIGRATIONS_DIRContainer defaultOverride the directory containing committed Drizzle migrations
POSTGRES_PASSWORDDefault Compose onlyPassword interpolated into the bundled Postgres service and application URL

Use the same DATABASE_URL for the migration, web, and worker processes. The worker reserves one Postgres connection for email outbox notifications and opens a small Effect SQL pool for workflow storage. Run exactly one worker process for each database. The web process writes email intents to Postgres and does not connect to Redis. In Compose, choose a URL-safe POSTGRES_PASSWORD because it is interpolated into a connection URL.

The Redis account must permit SCRIPT LOAD, EVALSHA, publish, subscribe, list, set, hash, string, and expiry commands. Use AOF persistence, replication, backups, and maxmemory-policy noeviction in production. Postgres retains the original email intent and the workflow result. Redis owns the queued delivery payload while the workflow waits. Back up both systems because losing Redis after Postgres marks an intent dispatched can leave an email workflow waiting for a queue item that no longer exists.

The two public URL values should be the same external HTTPS origin seen by users. Do not include a path suffix.

Authentication and email

VariableRequiredPurpose
BETTER_AUTH_SECRETYesUnique authentication secret of at least 32 characters
PROSEWIRE_ALLOW_SIGN_UPNoEnables first-owner bootstrap for self-hosted or open registration for Cloud; defaults to false
SMTP_URLProduction invitationsSMTP or SMTPS connection URL
EMAIL_FROMProduction emailSender identity; defaults to a localhost address in development

On self-hosted deployments, enable PROSEWIRE_ALLOW_SIGN_UP=true only to create the first owner. Direct registration closes automatically after the first account exists, even before that owner creates the team, but you should still set the value back to false and replace the web container after bootstrap. On Cloud, the flag keeps open registration available until you disable it. A valid, unexpired invitation still allows its invited email address to create an account in either deployment mode.

Test SMTP delivery and invitation links from the public origin before onboarding a team.

Self-hosted administrator bootstrap

VariableRequiredPurpose
PROSEWIRE_BOOTSTRAP_ADMIN_EMAILWith bootstrap passwordEmail for the first self-hosted administrator
PROSEWIRE_BOOTSTRAP_ADMIN_PASSWORDWith bootstrap emailTemporary password between 12 and 128 characters
PROSEWIRE_BOOTSTRAP_ADMIN_NAMENoDisplay name; defaults to Prosewire Admin

These variables need no separate enable flag. When both credentials exist, the one-shot migration job creates an administrator only if the installation has no users and no workspace. It marks that account for a required password change. The dashboard and authenticated mutations remain unavailable until the administrator replaces the temporary password. The change revokes every session, so the administrator signs in again before creating the first publication.

Remove the variables after the password change. Later migration runs do not reset a completed bootstrap account. Until the password changes, an operator can replace the temporary password value and rerun the migration job to recover access. This recovery works only for the sole matching bootstrap administrator before a workspace exists. Cloud deployments reject bootstrap administrator credentials.

Rolling and multi-instance deployments

VariableRequiredPurpose
NEXT_SERVER_ACTIONS_ENCRYPTION_KEYMulti-instance productionStable base64-encoded 32-byte key shared by web replicas and releases
NEXT_DEPLOYMENT_IDWeb buildRelease identifier baked into the web assets and shared by replicas running that image

Generate the server-action key with openssl rand -base64 32 and store it as a secret. Rotating it during a rollout can break requests created by a different replica or release.

Pass NEXT_DEPLOYMENT_ID to next build or as the bundled Docker build argument. Use an immutable version or commit, and run the same built image on every web replica for that release. Changing the variable on a running container does not rewrite its assets.

Worker configuration

VariableRequiredPurpose
PROSEWIRE_ANALYTICS_RETENTION_DAYSNoPositive integer controlling raw page-view retention; defaults to 365
PROSEWIRE_EMAIL_WORKER_CONCURRENCYNoConcurrent email deliveries inside the single worker; defaults to 4

The worker starts durable workflows for scheduled publishing, raw-view retention, outbox draining, and email delivery. Postgres LISTEN/NOTIFY normally starts the outbox workflow immediately. A 30-second scan catches notifications missed while the listener reconnects, and expired leases resume safely after a restart. The email workflow waits for an Effect DurableQueue worker in Redis. Delivery failures use exponential retry with a five-minute cap and finish as a typed workflow failure after 100 attempts.

The pinned Effect SQL runner supports durable single-process execution. Do not scale the worker command above one replica for the same database. Increase PROSEWIRE_EMAIL_WORKER_CONCURRENCY if SMTP capacity allows more parallel delivery. The migration role and worker database role need access to the Effect-owned cluster_* tables. The migration command creates them first, and worker startup repeats Effect’s idempotent migration check.

Development seed only

VariableRequired in developmentPurpose
ADMIN_EMAILYesEmail for the local seeded administrator
ADMIN_PASSWORDYesUnique password of at least 12 characters
PROSEWIRE_SEED_API_KEYNoOne-time local key of at least 24 characters with read and write scopes

The example values are local-only. Development web startup runs migrations and seed logic; production web startup does neither. Production uses the one-shot migration command and the optional self-hosted administrator bootstrap instead.

Development and test controls

PROSEWIRE_ALLOWED_DEV_ORIGINS is a comma-separated Next.js development-origin allowlist. PROSEWIRE_EXPOSE_TESTING_API=1 exposes framework testing support in production builds and is reserved for controlled acceptance tests; never enable it on a public deployment.

Documentation site

The separate Astro landing page and documentation site uses SITE_URL for canonical links, its sitemap, and robots.txt:

SITE_URL=https://docs.example.com pnpm --filter @prosewire/site build:production

On Vercel, VERCEL_PROJECT_PRODUCTION_URL supplies the origin when system environment variables are enabled. SITE_URL overrides it for manual or non-Vercel builds. A production build rejects a missing, local, reserved, or known dead origin. These variables configure the documentation site only; they do not configure the Prosewire publishing application.

Security checks

  • Use unique values per environment
  • Keep Postgres on a private network and require TLS for remote connections
  • Store API tokens as hashes and use the narrowest read/write scope
  • Rotate a compromised API key by creating a replacement, changing the consumer, then revoking the old key
  • Back up Postgres and test a restore before launch