Skriuw Documentation
Self-hosting and operations

Environment variables

Every variable Skriuw reads, whether it is required, its default, and what stops working when it is unset. Grouped by subsystem, matching .env.example.

Reference for every variable Skriuw reads. The canonical template is .env.example at the repo root. Copy it to .env (self-host) or .env.local (local dev). Anything marked optional degrades gracefully: the related surface hides or falls back instead of crashing.

Variables prefixed NEXT_PUBLIC_ are inlined into the client bundle at build time. On a prebuilt Docker image they are frozen to the values used at build, so changing them at runtime has no effect. See Self-host with Docker for the custom-domain rebuild.

Database

VariableRequiredEffect
DATABASE_URLYesPostgres connection string used by Prisma and the PrismaPg adapter. Use sslmode=verify-full for managed Postgres (Neon, RDS). sslmode=disable is only for the local Compose container.

Auth (Better Auth)

VariableRequiredEffect
BETTER_AUTH_SECRETYesSigns sessions. Minimum 32 chars. Generate with openssl rand -base64 32.
BETTER_AUTH_URLYes in productionServer base URL for the trusted-origins CSRF check. If unset it falls back to the maintainer domain and auth breaks. Set to your own origin.
NEXT_PUBLIC_BETTER_AUTH_URLYes in productionClient base URL read by createAuthClient. Set to the same value as BETTER_AUTH_URL. Build-time inlined.
GITHUB_CLIENT_IDOptionalGitHub OAuth. Leave both GitHub vars empty to hide the GitHub sign-in button.
GITHUB_CLIENT_SECRETOptionalGitHub OAuth secret.
GOOGLE_CLIENT_IDOptionalGoogle OAuth. Leave both Google vars empty to hide the button.
GOOGLE_CLIENT_SECRETOptionalGoogle OAuth secret.

OAuth redirect URIs follow the pattern <your-origin>/api/auth/callback/<provider>.

AI

VariableRequiredEffect
AI_KEYS_ENCRYPTION_SECRETYesEncrypts user-supplied provider keys at rest (AES). Minimum 32 chars.
GEMINI_API_KEYOptionalServer-side fallback Google Generative AI key, used when a user has no saved key. Named GEMINI_* for backcompat.
GROQ_API_KEYOptionalServer-side fallback Groq key.

With no fallback keys set, AI still works for any user who saves their own key in settings.

Analytics

Self-hosted Remco Analytics. All optional. With NEXT_PUBLIC_ANALYTICS_URL unset (or NEXT_PUBLIC_ANALYTICS_ENABLED not "true"), client analytics stays off.

VariableRequiredEffect
NEXT_PUBLIC_ANALYTICS_URLOptionalBrowser SDK ingest base URL (posts to {url}/e).
NEXT_PUBLIC_ANALYTICS_ENABLEDOptionalSet "false" to disable client analytics entirely.
ANALYTICS_URLOptionalServer-side ingest base URL for trackServerEvent.
INGEST_SECRETOptionalBearer token for server-side ingest. Must match the ingestion service. Required only for server-side auth events.

Realtime collaboration

Collaboration runs on a Cloudflare Worker in apps/collab/, not the Docker stack. Leave NEXT_PUBLIC_PARTYKIT_HOST blank to keep collaboration disabled, which is the correct default for self-host. Setup steps live in Collaboration setup.

VariableRequiredEffect
COLLAB_AUTH_SECRETOnly for collabShared HMAC secret. The app signs room tokens with it, the Worker verifies them. They must match or every socket returns 401.
NEXT_PUBLIC_PARTYKIT_HOSTOnly for collabHost the browser opens the Yjs WebSocket to. Blank disables collab. A value pointing at a Worker that is not running makes every socket 401. Build-time inlined.

Cover uploads

Used when a user has not connected their own storage in Settings, Data and sync. Without either option below, cover uploads fall back to theme gradients.

Option A, self-hostable S3-compatible bucket (MinIO, R2, B2) with public reads:

VariableRequiredEffect
DEFAULT_STORAGE_S3_BUCKETOption ABucket name. All four core S3 vars must be set together.
DEFAULT_STORAGE_S3_REGIONOption ABucket region.
DEFAULT_STORAGE_S3_ACCESS_KEY_IDOption AAccess key.
DEFAULT_STORAGE_S3_SECRET_ACCESS_KEYOption ASecret key.
DEFAULT_STORAGE_S3_ENDPOINTOptionalCustom endpoint for MinIO, R2, or B2.
DEFAULT_STORAGE_S3_PUBLIC_BASE_URLOptionalPublic base URL for serving uploaded files.

Option B, Vercel Blob:

VariableRequiredEffect
BLOB_READ_WRITE_TOKENOption BAuto-provided by Vercel when a Blob store is attached. Used only if DEFAULT_STORAGE_S3_BUCKET is unset.

On this page