Files
convex-monorepo/README.md
T
Gabriel Brown 8f09a423d4
Build and Push Next App / quality (push) Successful in 1m12s
Build and Push Next App / build-next (push) Successful in 2m20s
Read CI env from Infisical and give the local stack its own ports
CI reads Infisical staging as the read-only convexmonorepo-base-ci machine identity, runs the quality gate, and builds and pushes the image. The template is not deployed, so there is no Convex or VPS deploy step. The local stack moves to its own Compose name and ports so it runs beside the Payload template's, and it syncs the Convex runtime env. The scripts pick up Infisical account switching, dev-kill and a cache-safe CI install.
2026-10-01 14:55:35 -04:00

3.3 KiB

Convex Turbo Monorepo

A reusable Bun/Turborepo template with Next.js 16, Expo, self-hosted Convex, shared UI/config packages, Vitest, and Docker deployment.

Local setup

Requirements: Bun 1.3.14, Docker or Podman, Node 22, the Infisical CLI, jq, and flock.

bun install --frozen-lockfile
infisical login
infisical init
bun db:up
bun dev:next

The committed .infisical.json links this repository to its own Infisical project. Local commands read dev by default and never fall back to .env files. Select staging with INFISICAL_ENV=staging bun dev:next.

Local services:

  • Next.js: http://localhost:3000
  • Convex API: http://localhost:3250
  • Convex dashboard: http://localhost:6795

Next and Expo run on the host. Convex uses a self-hosted data volume and does not use Postgres by default. The commented POSTGRES_URL in Compose is an opt-in example for cloned projects that explicitly choose Convex-on-Postgres.

bun db:down        # stop; preserve Convex data
bun db:down:wipe   # remove the Convex volume and generated admin key

Normal bun db:up never contacts staging and does not start Postgres. It starts the local Convex backend and dashboard, generates a machine-local Convex admin key in .local/dev.generated.env when needed, deploys functions/schema, and configures local Convex Auth keys.

Physical devices cannot resolve their own localhost; override the public Convex URL with the development host's LAN address when testing Expo on-device.

Environment model

  • Local dev and staging: Infisical.
  • Generated local state: .local/<environment>.generated.env.
  • CI/CD: Infisical staging, read by the read-only convexmonorepo-base-ci machine identity and materialized only as a temporary runner file.
  • Docker compilation: explicit Compose build args; .env* stays outside the image context.

Run sh scripts/with-env dev -- <command> for an environment-aware command or sh scripts/export-env dev to materialize a temporary merged dotenv stream. Do not commit or maintain root .env files.

Development and quality

bun dev:next
bun dev:expo
bun lint:ws
bun format
bun lint
bun typecheck
bun test:unit
bun test:integration
bun test:component
SKIP_E2E=1 bun run ci:check

bun test:e2e starts the isolated local stack and currently performs generic stack smoke checks. It stops the stack afterward only when the stack was not already running. It skips in CI and when SKIP_E2E=1 is set.

Shared dependency versions belong in root catalogs. Edit the root catalog, run bun install, then bun lint:ws; do not run bun update inside a workspace.

Deployment

Production Compose retains the self-hosted Convex backend/dashboard and has no Postgres service by default. A commented POSTGRES_URL remains only as an optional Convex-on-Postgres example for cloned projects. Gitea runs the quality gate first, then builds the Next image and pushes SHA and latest tags. Each job reads Infisical staging through scripts/ci-export-env.mjs as the convexmonorepo-base-ci machine identity (Gitea secrets INFISICAL_CLIENT_ID and INFISICAL_CLIENT_SECRET).

The template itself is not deployed. A cloned app that is adds a convex-deploy job and the VPS deploy step from an app that already has them (StPeteIT, LashAddict, bill-tracker), plus its own Infisical project and machine identity.