Add src/lib/env.ts with runtime Zod validation for NEXT_PUBLIC_* variables. Update auth-server to use validated env instead of process.env directly. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> |
||
|---|---|---|
| convex | ||
| messages | ||
| src | ||
| .gitignore | ||
| .oxfmtrc.jsonc | ||
| .oxlintrc.json | ||
| AGENTS.md | ||
| CLAUDE.md | ||
| components.json | ||
| DEVELOPMENT.md | ||
| next.config.ts | ||
| package.json | ||
| pnpm-lock.yaml | ||
| postcss.config.mjs | ||
| README.md | ||
| tmuxi.template.yml | ||
| tsconfig.json | ||
SaaS template
This is not gonna make You rich, but it sure as hell will save you a lot of time!
This is production ready setup for Convex and Next SaaS.
Features
- Auth
- Stripe
- shadcn/create UI templte
- next intl
- next themes
- Backend/Frontend Tests
- Tmuxinator
- CICD
- accurate instructions
Development process
Environments
- Dev cloud environment - based on
developbranch - Prod cloud environment - based on
mainbranch
Getting Started
First, run the development server:
pnpm dev --webpack
Note
As of Next.js@16.2.1 turbopack is broken ant it spikes CPU usage by 900% and 8-9GiB of RAM usage, thus why we use webpack. Wait for 16.3.0 to migrate to turbopack
Convex setup
- Go on Coolify, search for Convex and set it up.
Important
Best case: copy config from here, paste it instead of Coolify's docker-compose file, then go into environment variables, copy them, paste them and the new docker-compose into an AI agent and tell him to properly map the envs to docker-compose so it's ready to deploy on coolify.
This works for Convex 1.34.0 (CLI+backend/dashboard)
services:
backend:
image: 'ghcr.io/get-convex/convex-backend:latest'
stop_grace_period: 10s
stop_signal: SIGINT
ports:
- '${PORT:-3210}:3210'
- '${SITE_PROXY_PORT:-3211}:3211'
volumes:
- 'data:/convex/data'
environment:
APPLICATION_MAX_CONCURRENT_MUTATIONS: '${APPLICATION_MAX_CONCURRENT_MUTATIONS:-16}'
APPLICATION_MAX_CONCURRENT_NODE_ACTIONS: '${APPLICATION_MAX_CONCURRENT_NODE_ACTIONS:-16}'
APPLICATION_MAX_CONCURRENT_QUERIES: '${APPLICATION_MAX_CONCURRENT_QUERIES:-16}'
APPLICATION_MAX_CONCURRENT_V8_ACTIONS: '${APPLICATION_MAX_CONCURRENT_V8_ACTIONS:-16}'
INSTANCE_NAME: '${INSTANCE_NAME}'
INSTANCE_SECRET: '${INSTANCE_SECRET}'
CONVEX_CLOUD_ORIGIN: '${SERVICE_URL_BACKEND}'
CONVEX_SITE_ORIGIN: '${SERVICE_URL_BACKEND_SITE}'
DISABLE_METRICS_ENDPOINT: '${DISABLE_METRICS_ENDPOINT:-true}'
DOCUMENT_RETENTION_DELAY: '${DOCUMENT_RETENTION_DELAY:-172800}'
DO_NOT_REQUIRE_SSL: '${DO_NOT_REQUIRE_SSL:-true}'
DISABLE_BEACON: '${DISABLE_BEACON:-false}'
REDACT_LOGS_TO_CLIENT: '${REDACT_LOGS_TO_CLIENT:-false}'
RUST_LOG: '${RUST_LOG:-info}'
RUST_BACKTRACE: '${RUST_BACKTRACE:-0}'
ACTIONS_USER_TIMEOUT_SECS: '${ACTIONS_USER_TIMEOUT_SECS:-600}'
HTTP_SERVER_TIMEOUT_SECONDS: '${HTTP_SERVER_TIMEOUT_SECONDS:-300}'
CONVEX_RELEASE_VERSION_DEV: '${CONVEX_RELEASE_VERSION_DEV:-}'
DATABASE_URL: '${DATABASE_URL:-}'
POSTGRES_URL: '${POSTGRES_URL:-}'
MYSQL_URL: '${MYSQL_URL:-}'
AWS_REGION: '${AWS_REGION:-}'
AWS_ACCESS_KEY_ID: '${AWS_ACCESS_KEY_ID:-}'
AWS_SECRET_ACCESS_KEY: '${AWS_SECRET_ACCESS_KEY:-}'
AWS_SESSION_TOKEN: '${AWS_SESSION_TOKEN:-}'
AWS_S3_FORCE_PATH_STYLE: '${AWS_S3_FORCE_PATH_STYLE:-}'
AWS_S3_DISABLE_SSE: '${AWS_S3_DISABLE_SSE:-}'
AWS_S3_DISABLE_CHECKSUMS: '${AWS_S3_DISABLE_CHECKSUMS:-}'
S3_ENDPOINT_URL: '${S3_ENDPOINT_URL:-}'
S3_STORAGE_EXPORTS_BUCKET: '${S3_STORAGE_EXPORTS_BUCKET:-}'
S3_STORAGE_SNAPSHOT_IMPORTS_BUCKET: '${S3_STORAGE_SNAPSHOT_IMPORTS_BUCKET:-}'
S3_STORAGE_MODULES_BUCKET: '${S3_STORAGE_MODULES_BUCKET:-}'
S3_STORAGE_FILES_BUCKET: '${S3_STORAGE_FILES_BUCKET:-}'
S3_STORAGE_SEARCH_BUCKET: '${S3_STORAGE_SEARCH_BUCKET:-}'
healthcheck:
test:
- CMD-SHELL
- 'curl -f http://localhost:3210/version'
interval: 5s
start_period: 10s
timeout: 5s
retries: 10
dashboard:
image: 'ghcr.io/get-convex/convex-dashboard:latest'
stop_grace_period: 10s
stop_signal: SIGINT
ports:
- '${DASHBOARD_PORT:-6791}:6791'
environment:
PORT: '6791'
NEXT_PUBLIC_DEPLOYMENT_URL: '${SERVICE_URL_BACKEND}'
NEXT_PUBLIC_LOAD_MONACO_INTERNALLY: '${NEXT_PUBLIC_LOAD_MONACO_INTERNALLY:-true}'
depends_on:
backend:
condition: service_healthy
volumes:
data: null
Then make sure to update domains and env vars accordingly
- Deploy the service(s - dashboard and the db). It has built-in persistent storage
- Connect to server with ssh, jump into a backend container with
docker exec -it <name> ./generate_admin_key.shYou'll receive Your admin key and You'll be able to log into dashboard
Admin key:
self-hosted-convex|010...
- Now Your base is ready. Go to .env.local and finish setting up the connection.
- Run
pnpm install(only if Your hosted Convex image is latest, else use a proper version) - After that You can run
npx convex devand You should be ready to go!
Tip
Remember to add 2 domains with ports in Your backend Coolify config:
- Actual backend domain e.g
https://convex-backend.mentat.ovh:3210- Backend actions domain e.g
https://backend-site-olnjg91x5ervt6j6owwgnlha.mentat.ovh:3211
Frontend setup
Time to pick a theme! Go to shadcn/create, create a theme, and simply use the received command to init this theme in Your project!
Better Auth
This project utilizes BetterAuth. To set it up:
pnpm dlx convex env set BETTER_AUTH_SECRET=$(openssl rand -base64 32)pnpm dlx convex env set SITE_URL=http://localhost:3000
Troubleshooting
dev/templates/convex-next-saas main !? ❯ npx convex dev
✖ Error: Unable to start push to https://backend-i8e44nvzhj8sxw4qm9tbu1f7.mentat.ovh
✖ Error fetching POST https://backend-i8e44nvzhj8sxw4qm9tbu1f7.mentat.ovh/api/deploy2/start_push 400 Bad Request: BadJsonBody: Failed to deserialize the JSON body into th
e target type: appDefinition: missing field `functions` at line 1 column 272745
Solution - ensure both CLI and convex self-hosted cloud images versions are the same. If not - I suggest upgrading whatever version is lower to be higher.