studio-best-practices

bởi supabase

Các phương pháp hay nhất về React và TypeScript cho Supabase Studio. Sử dụng khi viết

npx skills add https://github.com/supabase/supabase --skill studio-best-practices

Studio Best Practices

Applies to apps/studio/**/*.{ts,tsx}.

Boolean Naming

Use descriptive prefixes — derive from existing state rather than storing separately:

  • is — state/identity: isLoading, isPaused, isNewRecord
  • has — possession: hasPermission, hasData
  • can — capability: canUpdateColumns, canDelete
  • should — conditional behavior: shouldFetch, shouldRender

Extract complex conditions into named variables:

// ❌ inline multi-condition
{
  !isSchemaLocked && isTableLike(selectedTable) && canUpdateColumns && !isLoading && <Button />
}

// ✅ named variable
const canShowAddButton =
  !isSchemaLocked && isTableLike(selectedTable) && canUpdateColumns && !isLoading
{
  canShowAddButton && <Button />
}

Derive booleans — don't store them:

// ❌ stored derived state
const [isFormValid, setIsFormValid] = useState(false)
useEffect(() => {
  setIsFormValid(name.length > 0 && email.includes('@'))
}, [name, email])

// ✅ derived
const isFormValid = name.length > 0 && email.includes('@')

Component Structure

See vercel-composition-patterns skill for compound component and composition patterns.

Keep components under 200–300 lines. Split when you see:

  • Multiple distinct UI sections
  • Complex conditional rendering
  • Multiple unrelated useState calls
  • Hard to understand at a glance

Co-locate sub-components in the same directory as the parent. Avoid barrel re-export files.

Extract repeated JSX patterns into small components.

Data Fetching

All data fetching uses TanStack Query (React Query). See studio-queries skill for query/mutation patterns and studio-error-handling skill for error display conventions.

Loading / Error / Success Pattern

Top level:

const { data, error, isLoading, isError, isSuccess } = useQuery(...)

if (isLoading) return <GenericSkeletonLoader />
if (isError) return <AlertError error={error} subject="Failed to load data" />
if (isSuccess && data.length === 0) return <EmptyState />
return <DataDisplay data={data} />

Use early returns — avoid deeply nested conditionals.

Inline:

<div>
  {isLoading && <InlineLoader />}
  {isError && <InlineError error={error} />}
  {isSuccess && data.length === 0 && <EmptyState />}
  {isSuccess && data.length > 0 && <DataDisplay data={data} />}
</div>

State Management

Keep state as local as possible; lift only when needed.

Group related form state with react-hook-form rather than multiple useState calls. See studio-ui-patterns skill for form layout and component conventions.

// ❌ multiple related useState
const [name, setName] = useState('')
const [email, setEmail] = useState('')

// ✅ grouped with react-hook-form
const form = useForm<FormValues>({ defaultValues: { name: '', email: '' } })

Custom Hooks

Extract complex or reusable logic into hooks. Return objects, not arrays:

// ❌ array return (hard to extend)
return [value, toggle]

// ✅ object return
return { value, toggle, setTrue, setFalse }

Event Handlers

  • Prop callbacks: on prefix (onClose, onSave)
  • Internal handlers: handle prefix (handleSubmit, handleCancel)

Use useCallback for handlers passed to memoized children; avoid unnecessary inline arrow functions.

Conditional Rendering

// Simple show/hide
<>{isVisible && <Component />}</>

// Binary choice
<>{isLoading ? <Spinner /> : <Content />}</>

// Multiple conditions — use early returns, not nested ternaries
if (isLoading) return <Spinner />
if (isError) return <Error />
return <Content />

Performance

useMemo for genuinely expensive computations (measured, not assumed). Don't wrap everything — only optimize when you have a measured problem or are passing values to memoized children.

TypeScript

Define prop interfaces explicitly. Use discriminated unions for complex state:

type AsyncState<T> =
  | { status: 'idle' }
  | { status: 'loading' }
  | { status: 'success'; data: T }
  | { status: 'error'; error: Error }

Avoid as any / as Type casts. Validate at boundaries with zod:

// ❌ type cast
const user = apiResponse as User

// ✅ zod parse
const user = userSchema.parse(apiResponse)
// or safe:
const result = userSchema.safeParse(apiResponse)

Testing

Extract logic into .utils.ts pure functions and test exhaustively. See the studio-testing skill for the full testing strategy and decision tree.

Thêm skills từ supabase

studio-e2e-tests
supabase
Viết và chạy các bài kiểm tra E2E Playwright cho Supabase Studio. Sử dụng khi được yêu cầu.
official
vitest
supabase
Khung kiểm thử đơn vị nhanh Vitest được hỗ trợ bởi Vite với API tương thích Jest. Sử dụng khi viết kiểm thử, giả lập, cấu hình phủ mã, hoặc làm việc với kiểm thử…
official
skill-creator
supabase
Hướng dẫn toàn diện để tạo các kỹ năng mô-đun nhằm mở rộng khả năng của Claude với kiến thức chuyên môn và quy trình làm việc. Kỹ năng bao gồm tệp SKILL.md bắt buộc với frontmatter YAML và hướng dẫn markdown, cùng các tài nguyên tùy chọn (script, tài liệu tham khảo, nội dung) được tổ chức theo mục đích và tải dần để tiết kiệm ngữ cảnh. Thiết kế kỹ năng xoay quanh các ví dụ sử dụng cụ thể; xác định các script có thể tái sử dụng cho các tác vụ xác định, tệp tham khảo cho kiến thức miền, và nội dung cho...
official
supabase
supabase
Sử dụng khi thực hiện BẤT KỲ tác vụ nào liên quan đến Supabase. Kích hoạt: các sản phẩm Supabase (Cơ sở dữ liệu, Xác thực, Hàm biên, Thời gian thực, Lưu trữ, Vectơ, Cron, Hàng đợi); máy khách…
official
supabase-server
supabase
Sử dụng khi viết mã phía máy chủ với Supabase — Edge Functions, ứng dụng Hono, trình xử lý webhook hoặc bất kỳ backend nào cần xác thực Supabase và tạo máy khách.
official
clickhouse-logs-queries
supabase
Write, review, and migrate Supabase logs queries against the ClickHouse-backed `logs` table (the `logs.all.otel` analytics endpoint). Use this whenever a task…
official
dev-toolbar-review
supabase
Sử dụng khi xem xét các PR liên quan đến packages/dev-tools/, packages/common/posthog-client.ts,
official
e2e-studio-tests
supabase
Chạy các bài kiểm tra e2e trong ứng dụng Studio. Sử dụng khi được yêu cầu chạy kiểm tra e2e, chạy kiểm tra studio, kiểm tra playwright, hoặc kiểm tra tính năng.
official