Circle V2 API Docs
    Preparing search index...

    Code Style and Tooling

    Biome is the primary tool for both formatting and linting. There is no Prettier.

    Configuration lives in biome.json at the repo root.

    Setting Value
    Line width 120
    Indent style Spaces
    Indent width 2

    Run the formatter:

    pnpm format  # biome check --write .
    

    Biome's recommended rules are enabled. Notable additions:

    Rule Level Purpose
    noUndeclaredEnvVars (nursery) warn Encourages documenting env variable usage
    noRestrictedImports (apps/web) error Prevents importing @repo/db directly in the web app

    Test files (*.test.ts, *.test.tsx) have relaxed rules:

    • noExplicitAny: off
    • noNonNullAssertion: off

    This allows pragmatic test code without fighting the linter.

    Biome automatically organizes imports into groups separated by blank lines:

    // 1. Node builtins, third-party packages (excluding @repo)
    import { z } from "zod";
    import { TRPCError } from "@trpc/server";

    // 2. Internal @repo/* packages
    import { patientsRepo } from "@repo/db";
    import { authenticatedProcedure } from "@repo/trpc/procedures";

    // 3. App-level aliases (~/)
    import { Providers } from "~/lib/providers";

    // 4. Relative imports
    import { PatientForm } from "./components/PatientForm";

    The groups are configured in biome.json:

    {
    "assist": {
    "actions": {
    "source": {
    "organizeImports": {
    "level": "on",
    "options": {
    "groups": [
    [
    ":NODE:",
    ":PACKAGE:",
    ":PACKAGE_WITH_PROTOCOL:",
    ":URL:",
    "!@repo/**"
    ],
    ":BLANK_LINE:",
    "@repo/**",
    ":BLANK_LINE:",
    "~/**",
    ":PATH:"
    ]
    }
    }
    }
    }
    }
    }

    Test files have their own import order: mocks first, then vitest/test utilities, then everything else.

    ESLint is used only for Next.js-specific rules in apps/web. The config is in apps/web/eslint.config.mjs and uses @next/eslint-plugin-next (recommended + core-web-vitals).

    The lint script in apps/web runs both Biome and ESLint:

    {
    "lint": "biome check . && next lint"
    }

    All packages use TypeScript strict mode. The shared configs live in packages/typescript-config/:

    Config Used By Key Settings
    base.json Most packages strict: true, target: ES2022, module: NodeNext, noUncheckedIndexedAccess: true
    nextjs.json apps/web Extends base; module: ESNext, moduleResolution: Bundler, jsx: preserve
    react-library.json React packages Extends base with React/JSX support
    • strict: true: All strict checks enabled.
    • noUncheckedIndexedAccess: true: Array/object index access returns T | undefined.
    • isolatedModules: true: Ensures compatibility with transpilers.
    • declaration: true + declarationMap: true: Generates .d.ts files for package consumers.
    pnpm check-types  # Runs tsc --noEmit across all packages via Turbo
    

    Task definitions live in turbo.json:

    Task Dependencies Cached Notes
    build ^build Yes Outputs: .next/**; env vars included in cache key
    dev -- No Persistent task
    test ^build Yes Inputs: **/*.test.{ts,tsx}, .env*
    test:watch -- No Persistent task
    lint ^lint Yes
    check-types ^check-types Yes
    storybook:build ^build Yes Outputs: storybook-static/**

    Build and test cache keys include environment variables to ensure rebuilds when config changes:

    • BASE_URL, SUPABASE_URL, SUPABASE_ANON_KEY, DATABASE_URL
    • NEXT_PUBLIC_TRPC_URL, NEXT_PUBLIC_OAUTH_REDIRECT_URL
    • And more (see turbo.json env arrays).

    Defined in pnpm-workspace.yaml:

    packages:
    - "apps/*"
    - "packages/*"

    The root package.json pins zod to 4.3.6 across the workspace:

    {
    "pnpm": {
    "overrides": {
    "zod": "4.3.6"
    }
    }
    }
    {
    "engines": {
    "node": ">=20"
    },
    "packageManager": "pnpm@10.23.0"
    }

    Next: Testing