Introduction

OverviewArchitectureAgent Experience

The product

This repository

Structure

Usage

Other

Setup

Environment Variables

Every environment variable the OPB Brain monorepo reads, which are required, and where each file lives

Every integration in this repository is configured through environment variables and reads its own. An integration whose variables are absent skips itself rather than failing the build, so only core infrastructure — the database and the cross-application URLs — is genuinely required.

Placeholders only

Every value on this page is an obvious placeholder. Real keys belong in .env.local files, which are gitignored, and as Worker secrets set with wrangler secret put. Never commit one, and never paste one into a documentation page or a task comment.

Minimum setup

These are the only variables needed to boot:

1. Database (Required)

Production and Worker preview use the D1 binding DB declared in each app's wrangler.jsonc. Apply migrations with bun run migrate (local) or bun run migrate:deploy (remote).

Optional tooling-only SQLite URL in packages/database/.env:

DATABASE_URL="file:./.prisma-tooling.db"

Do not provision Neon or any Postgres host for OPB Brain. Durable state is Cloudflare D1.

2. Local URLs (Pre-configured)

These are already set to sensible defaults for local development:

NEXT_PUBLIC_APP_URL="http://localhost:3000"
NEXT_PUBLIC_WEB_URL="http://localhost:3001"
NEXT_PUBLIC_API_URL="http://localhost:3002"
NEXT_PUBLIC_DOCS_URL="http://localhost:3004"
DEPLOY_ENV="development"

That's it! You can now run bun run dev and the app will start. Features like authentication, payments, analytics, email, and CMS will be disabled until you configure their environment variables.

Optional Features

The following environment variables enable additional features. You can add them as needed — any unconfigured integration will be gracefully skipped at runtime.

Authentication (Clerk)

Required for authentication, user, and organization management.

Add to apps/app/.env.local and apps/web/.env.local:

# Server
CLERK_SECRET_KEY="sk_test_..."

# Client
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY="pk_test_..."
NEXT_PUBLIC_CLERK_SIGN_IN_URL="/sign-in"
NEXT_PUBLIC_CLERK_SIGN_UP_URL="/sign-up"
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL="/"
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL="/"

Sign up at Clerk and create an application

Go to API Keys in your Clerk dashboard

Copy the Publishable key (starts with pk_) and Secret key (starts with sk_)

Content Management (BaseHub)

Required for the CMS functionality in packages/cms. If not configured, CMS queries will return empty results.

BASEHUB_TOKEN="bshb_..."

Create a BaseHub repository whose schema matches what @repo/cms queries

Navigate to Settings → API Tokens

Copy your Read Token (starts with bshb_pk_)

Email (Resend)

Required for sending transactional emails. If not configured, email features like the contact form will be disabled.

RESEND_TOKEN="re_..."
RESEND_FROM="noreply@yourdomain.com"

Get your API key from Resend

Payments (Stripe)

Required for subscription and payment functionality. If not configured, the Stripe client and payment webhooks will be disabled.

STRIPE_SECRET_KEY="sk_test_..."
STRIPE_WEBHOOK_SECRET="whsec_..."

Get your keys from Stripe Dashboard

For webhooks, install the Stripe CLI and run:

stripe listen --forward-to localhost:3000/api/webhooks/stripe

Analytics

Google Analytics

NEXT_PUBLIC_GA_MEASUREMENT_ID="G-..."

Create a GA4 property

PostHog

NEXT_PUBLIC_POSTHOG_KEY="phc_..."
NEXT_PUBLIC_POSTHOG_HOST="https://app.posthog.com"

Get your keys from PostHog

Observability

Observability is Cloudflare-native. Enable observability.enabled in each app wrangler.jsonc. No BETTERSTACK_* / SENTRY_* / LOGTAIL_* variables are used.

Optional product analytics (PostHog / GA) stay under Analytics above — they are not the host observability stack.

Security

Arcjet (Rate limiting & security)

ARCJET_KEY="ajkey_..."

Get your key from Arcjet

Real-time Features

Liveblocks (Collaboration)

LIVEBLOCKS_SECRET="sk_..."

Get your secret from Liveblocks

Notifications (Knock)

KNOCK_API_KEY="..."
KNOCK_SECRET_API_KEY="..."
KNOCK_FEED_CHANNEL_ID="..."
NEXT_PUBLIC_KNOCK_API_KEY="..."
NEXT_PUBLIC_KNOCK_FEED_CHANNEL_ID="..."

Get your keys from Knock

Feature Flags

FLAGS_SECRET="..."

Generate a random secret string for encrypting feature flag data.

Webhooks (Svix)

SVIX_TOKEN="..."

Get your token from Svix

Clerk Webhooks

CLERK_WEBHOOK_SECRET="whsec_..."

In your Clerk dashboard, go to Webhooks

Add a new endpoint pointing to https://your-domain.com/api/webhooks/clerk

Subscribe to the events you need (typically user.created, user.updated, etc.)

Copy the Signing Secret

Environment Variable Files

Variables live next to the application or package that reads them:

FilePurpose
apps/app/.env.localMain application variables
apps/web/.env.localMarketing website variables
apps/api/.env.localAPI server variables
packages/database/.envDatabase connection string
packages/cms/.env.localCMS configuration
packages/internationalization/.env.examplei18n configuration

The setup script automatically creates these files from .env.example templates. You only need to fill in the values.

Type Safety

Type safety is provided by @t3-oss/env-nextjs, which provides runtime validation and autocompletion for all environment variables. Each package defines its own environment variables in a keys.ts file with Zod validation schemas.

Validation Rules

Be as specific as possible with validation. For example, if a vendor secret starts with sec_, validate it as z.string().min(1).startsWith('sec_'). This makes your intent clearer and helps prevent errors at runtime.

Adding a New Environment Variable

To add a new environment variable:

  1. Add the variable to the relevant .env.local files
  2. Add validation to the server or client object in the package's keys.ts file

Example in packages/my-package/keys.ts:

import { createEnv } from "@t3-oss/env-nextjs";
import { z } from "zod";

export const keys = createEnv({
  server: {
    MY_NEW_SECRET: z.string().min(1),
  },
  client: {
    NEXT_PUBLIC_MY_VALUE: z.string().optional(),
  },
  runtimeEnv: {
    MY_NEW_SECRET: process.env.MY_NEW_SECRET,
    NEXT_PUBLIC_MY_VALUE: process.env.NEXT_PUBLIC_MY_VALUE,
  },
});

Deployment

When deploying to Cloudflare:

  1. Set non-secret values in each Worker's wrangler.jsonc vars block
  2. Set secrets with bunx wrangler secret put <NAME> — never in the config file, never in a commit
  3. Update URL variables (NEXT_PUBLIC_APP_URL, etc.) to production values

Stateful dependencies are bindings, not variables. DB (D1), BLOB (R2) and NEXT_INC_CACHE_KV (KV) are handed to the Worker by the runtime, so there is no connection string or access token to configure — or to leak.