Open-Source Wikis

/

Supabase

/

How to contribute

/

Patterns and conventions

supabase/supabase

Patterns and conventions

Conventions that the existing code consistently follows. New code should mirror them.

TypeScript

  • The whole repo is TS / TSX. Plain .js is reserved for tool config (postcss.config.cjs, tailwind.config.js).
  • Strict mode is on. pnpm typecheck runs tsc --noEmit per package via Turborepo (pnpm typecheck at the root passes --continue).
  • any is heavily discouraged — Studio's eslint ratchet specifically tracks @typescript-eslint/no-explicit-any and only allows it to decrease over time.
  • Shared tsconfig lives in packages/tsconfig. Apps and packages extend from there.

React

  • Hooks-first. Class components are not in use.

  • React-Query (@tanstack/react-query v5) is the data-fetching standard for Studio. The convention is one folder per domain in apps/studio/data/<domain>/:

    apps/studio/data/auth/
    ├── auth-config-query.ts
    ├── auth-config-update-mutation.ts
    ├── user-query.ts
    ├── user-update-mutation.ts
    └── keys.ts          // exposes `authKeys` for invalidation
    • *-query.tsuseQuery wrappers.
    • *-mutation.tsuseMutation wrappers (also export an <X>Variables type).
    • keys.ts → strongly-typed query-key factories.
  • valtio is the small global-state library used for ephemeral cross-component state in Studio (apps/studio/state/).

  • react-hook-form + zod for forms. @hookform/resolvers ties them together.

File and folder names

  • Studio components folders are PascalCase (Auth/, BranchManagement/, SQLEditor/).
  • Files within a feature are PascalCase for components (UserDropdown.tsx) and kebab-case for hooks / utilities (error-patterns.ts, handle-error.ts).
  • Data-layer files are kebab-case (auth-config-query.ts).
  • New shared UI components in packages/ui use kebab-case file names (button.tsx).

Styling

  • Tailwind only. No CSS modules. No inline styles for design tokens.
  • Use semantic tokens — bg-muted, text-foreground-light, border-default, text-brand, etc. Hardcoded hex / gray-* is a code smell.
  • Tailwind config is rooted at the workspace; per-package tailwind.config.js files are stubs for IntelliSense.
  • Class composition uses cn() from 'ui' (a clsx + tailwind-merge wrapper).

Imports

  • Never import workspace packages by relative path. Always use the alias:

    import { useUserQuery } from 'data/auth/user-query';
    import { Button } from 'ui';
  • ESLint's no-restricted-imports is ratcheted in Studio — moving a file shouldn't introduce new banned import paths.

  • Re-exports from barrel files are discouraged in Studio; eslint-plugin-barrel-files flags them.

  • Imports are auto-sorted by @ianvs/prettier-plugin-sort-imports (Prettier).

Naming

  • React-Query keys use a per-domain factory:

    export const authKeys = {
      all: () => ['auth'] as const,
      user: (id: string) => ['auth', 'user', id] as const,
    };
  • Mutation hook names are imperative: useUpdateAuthConfigMutation, useDeleteUserMutation.

  • Query hook names are descriptive: useAuthConfigQuery, useUserQuery.

Error handling

  • Studio's data layer centralizes error normalization in apps/studio/data/handleError.ts and error-patterns.ts. New fetchers should go through these helpers so users see consistent messages.
  • UI surfaces use react-error-boundary and Studio's components/interfaces/ErrorHandling/ for top-level boundaries.

SQL

  • All Studio SQL is generated from packages/pg-meta/src/* rather than written ad-hoc. Each generator returns a { sql, zod } pair so callers can validate the response shape with Zod.
  • Never interpolate user input into SQL strings. packages/pg-meta/src/pg-format/ provides safe format/literal/ident helpers.
  • A custom Studio ESLint rule, studio/require-safe-sql-fragment (in apps/studio/eslint-rules/), enforces this on new code.

Telemetry

  • All product events live in packages/common/telemetry-constants.ts. Adding a new event means adding a typed constant there, then dispatching it via the helpers in packages/common/telemetry.tsx.
  • Studio uses PostHog through packages/common/posthog-client.ts. Consent is handled by packages/common/consent-state.ts.

Feature flags

  • Server-evaluated flags are read through packages/common/configcat.ts.
  • Client-side enabled-features are exposed via packages/common/feature-flags.tsx and packages/common/enabled-features/.
  • Adding a new flag: extend the type union in enabled-features/, add the ConfigCat key, and gate the feature behind useFlag('your-flag').

Markdown / docs

  • Docs use MDX with several custom remark/rehype plugins under apps/docs/lib/mdx/.
  • apps/docs/spec/ holds the SDK / Config / CLI specs that drive generated reference pages — change the spec, not the rendered page.
  • Linting is performed by supa-mdx-lint (root supa-mdx-lint.config.toml).

Common workflows captured as repo idioms

  • Adding a redirect: extend apps/www/lib/redirects.js.
  • Adding a Studio feature flag toggle: usually under components/interfaces/Settings/FeaturePreviews/ plus a ConfigCat entry.
  • Adding a new design-system component: edit packages/ui or packages/ui-patterns, then update apps/design-system/config/docs.ts, content/docs/, and registry/. Re-run pnpm --filter design-system build:registry.
  • Adding a /go/* page: add a typed page object in apps/www/_go/, register in apps/www/_go/index.tsx. The route app/go/[slug]/page.tsx picks it up automatically.

Cross-reference

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Patterns and conventions – Supabase wiki | Factory