Self-host the web app
Self-hosting uses your own provider apps and infrastructure. Set SELF_HOSTED=true to disable hosted billing gates, and set NEXT_PUBLIC_ENABLED_SOCIAL_PROVIDERS to a comma-separated list of enabled provider IDs (or *). Providers are disabled for new connections unless enabled. Forem is supported when explicitly enabled.
Run locally
From the core repo:
yarn install
cp scheduler/.env.example scheduler/.env
Fill in scheduler/.env, then run:
yarn workspace @simple-post/scheduler db:migrate
yarn workspace @simple-post/scheduler dev
Required environment:
| Variable / service | Why |
|---|---|
DATABASE_URL (Postgres) | Users, sessions, accounts, posts, and schedules. |
S3_STORAGE_* | Uploaded media and thumbnails. See media storage. |
BETTER_AUTH_SECRET | App auth and session signing. |
SCHEDULER_ENCRYPTION_KEY | Encrypts connected account secrets. Generate with openssl rand -base64 32. |
RESEND_API_KEY, RESEND_FROM_ADDRESS | Email login. |
SCHEDULED_POST_DISPATCH_SECRET | Bearer token for the dispatch endpoint described below. |
NEXT_PUBLIC_APP_URL | Public origin used for OAuth callbacks, CLI authorization, and MCP metadata. Defaults to http://localhost:3000. |
| Social platform apps | *_CLIENT_ID / *_CLIENT_SECRET for X, Google, Meta (Facebook + Instagram + Threads), TikTok, LinkedIn, Pinterest, and Bluesky. See scheduler/.env.example for the full list. |
Dispatch scheduled posts
Run a trusted recurring worker that calls POST /api/internal/scheduled-posts/dispatch with Authorization: Bearer $SCHEDULED_POST_DISPATCH_SECRET. Starting the web process alone does not configure this external trigger. See the API dispatch example and the repository deployment instructions.
Keep OAuth redirect origins, NEXT_PUBLIC_APP_URL, and storage public URLs aligned with your deployment. Apply production migrations with prisma migrate deploy; use db:migrate only for local development. Release checklist.