# 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 `develop` branch - Prod cloud environment - based on `main` branch ## Getting Started First, run the development server: ```bash 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 [Source of truth](https://github.com/get-convex/convex-backend/blob/main/self-hosted/README.md) 1. Go on Coolify, search for Convex and set it up. > [!IMPORTANT] > Best case: [copy config from here](https://github.com/get-convex/convex-backend/blob/main/self-hosted/docker/docker-compose.yml), 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 2. Deploy the service(s - dashboard and the db). It has built-in persistent storage 3. Connect to server with ssh, jump into a **backend** container with `docker exec -it ./generate_admin_key.sh` You'll receive Your admin key and You'll be able to log into dashboard ``` Admin key: self-hosted-convex|010... ``` 4. Now Your base is ready. Go to .env.local and finish setting up the connection. 5. Run `pnpm install` (only if Your hosted Convex image is latest, else use a proper version) 6. After that You can run `npx convex dev` and You should be ready to go! >[!TIP] > Remember to add 2 domains with ports in Your backend Coolify config: > > 1. Actual backend domain e.g `https://convex-backend.mentat.ovh:3210` > 2. Backend actions domain e.g `https://backend-site-olnjg91x5ervt6j6owwgnlha.mentat.ovh:3211` ### Frontend setup Time to pick a theme! Go to [shadcn/create](https://ui.shadcn.com/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: 1. `pnpm dlx convex env set BETTER_AUTH_SECRET=$(openssl rand -base64 32)` 2. `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.