К основному содержанию
правило

supabase — правило для Cursor: что делает и как установить

Задаёт стандарты написания SQL, моделирования схем и политик безопасности для проектов на Supabase в Cursor.

Установить в Cursor · Вручную: положить файлы Все способы и платформы ↓
.cursor/rules/supabase.mdc
Открыть на GitHub

Что делает supabase

Правило внедряет строгие требования к архитектуре базы данных Postgres в проектах на Supabase. Оно заставляет редактор использовать строчный синтаксис SQL, имена в snake_case, обязательные первичные ключи вида bigint generated always as identity и явные комментарии к каждой созданной таблице через COMMENT ON TABLE.

В части производительности и структуры запросов шаблон требует оборачивать сложные подзапросы в CTE (WITH), а также обязательно создавать индексы для каждого внешнего ключа, поскольку Postgres не индексирует их сама.

Главный упор сделан на безопасность данных. Правило настаивает на включении Row-Level Security (RLS) для каждой таблицы, запрещает функции SECURITY DEFINER без жёсткой очистки search_path = '' и предписывает запускать процедуры от имени вызывающего пользователя через SECURITY INVOKER.

Какие задачи решает

  • настроить политики Row-Level Security (RLS) без утечек данных
  • создать таблицы с первичными ключами identity и индексами на внешних ключах
  • оформить SQL-миграции в едином стиле с CTE вместо вложенных подзапросов
  • защитить хранимые процедуры с помощью SECURITY INVOKER и search_path

Примеры запросов агенту

  • Напиши миграцию для таблицы профилей пользователей с внешним ключом на auth.users и индексом
  • Создай безопасную хранимую функцию для обновления профиля с проверкой auth.uid()
  • Добавь политики RLS для таблицы заказов, чтобы пользователи видели только свои записи

Как установить supabase

Вручную: положить файлы

.cursor/rules/supabase.mdc

Во frontmatter: description, globs, alwaysApply

По шагам, с командами для каждой платформы: Cursor rules: файлы .mdc, четыре режима и замена .cursorrules

Вопросы о supabase

Как установить правило supabase в Cursor?

Скопируйте содержимое правила в файл .cursor/rules/supabase.mdc в корне вашего репозитория.

Что делает правило supabase?

Оно инструктирует ассистента Cursor генерировать SQL-код по стандартам Supabase: включать RLS, индексировать внешние ключи, форматировать запросы через CTE и задавать безопасные параметры функций.

Почему правило требует очищать search_path в функциях?

При использовании SECURITY DEFINER пустой search_path = '' предотвращает подмену объектов из других схем и защищает базу от эскалации привилегий.

Исходный текст

supabase.mdc · CC0-1.0
---
description: Comprehensive guidelines for writing high-performance, secure, and maintainable Supabase applications, covering SQL style, data modeling, security, and testing.
globs: **/*
---
# Supabase Best Practices

This guide outlines the definitive best practices for developing with Supabase, ensuring your projects are secure, performant, and maintainable. Adhere to these rules for consistent, high-quality code.

## 1. SQL Style & Code Organization

Consistency is paramount. Follow these rules for all SQL schema, migrations, and functions.

### 1.1 Naming Conventions
- **Identifiers:** Use `snake_case` for all table, column, and function names. Names must begin with a letter and contain only letters, numbers, and underscores.
- **Keywords:** Always use lowercase for SQL keywords (e.g., `select`, `from`, `where`).
- **Table Names:** Prefer plural, `snake_case` names (e.g., `users`, `products`).
- **Column Names:** Prefer singular, `snake_case` names (e.g., `id`, `name`, `created_at`).
- **Foreign Keys:** Use `singular_table_name_id` (e.g., `user_id` for `users` table).
- **Triggers:** Prefix with a numeric order (e.g., `_200_update_timestamp`) as triggers run in lexicographical order.

❌ BAD
```sql
CREATE TABLE UserProfiles (
    UserID INT PRIMARY KEY,
    UserName VARCHAR(255)
);
SELECT UserID FROM UserProfiles;
```

✅ GOOD
```sql
CREATE TABLE user_profiles (
    id bigint generated always as identity primary key,
    user_name text not null,
    user_id bigint references users (id) -- Example FK
);
SELECT id FROM user_profiles;

-- Trigger naming for ordered execution
CREATE TRIGGER _200_update_user_profile_timestamp
BEFORE UPDATE ON user_profiles
FOR EACH ROW EXECUTE FUNCTION update_timestamp();
```

### 1.2 Formatting & Readability
- **Indentation:** Use consistent indentation for clauses and arguments.
- **Aliases:** Always use explicit `AS` for aliases. Make them meaningful.
- **Boolean Operators:** Place `AND`/`OR` at the beginning of the line for multi-line `WHERE` clauses.
- **Parentheses:** Align closing parentheses with the starting line of the expression.

❌ BAD
```sql
SELECT t.client_id, DATE(t.created_at) day
FROM telemetry t, users u
WHERE t.user_id = u.id AND t.submission_date > '2019-07-01'
GROUP BY 1, 2;
```

✅ GOOD
```sql
SELECT
    t.client_id AS client_identifier,
    DATE(t.created_at) AS created_day
FROM
    telemetry AS t
INNER JOIN
    users AS u ON t.user_id = u.id
WHERE
    t.submission_date > '2019-07-01'
    AND t.sample_id = '10'
GROUP BY
    t.client_id,
    created_day;
```

### 1.3 Common Table Expressions (CTEs)
- **Prefer CTEs:** Use CTEs (`WITH` clauses) for complex queries to improve readability and modularity over nested subqueries.

❌ BAD
```sql
SELECT
    (SELECT COUNT(*) FROM orders WHERE user_id = u.id) AS order_count,
    u.email
FROM
    users AS u;
```

✅ GOOD
```sql
WITH user_order_counts AS (
    SELECT
        user_id,
        COUNT(*) AS order_count
    FROM
        orders
    GROUP BY
        user_id
)
SELECT
    u.email,
    uoc.order_count
FROM
    users AS u
LEFT JOIN
    user_order_counts AS uoc ON u.id = uoc.user_id;
```

## 2. Data Modeling & Schema Design

Design your schema for clarity, integrity, and performance.

### 2.1 Primary Keys
- **Standard PK:** Every table *must* have an `id` column of type `bigint generated always as identity primary key`.

❌ BAD
```sql
CREATE TABLE products (
    product_code text PRIMARY KEY,
    name text
);
```

✅ GOOD
```sql
CREATE TABLE products (
    id bigint generated always as identity primary key,
    product_code text unique not null,
    name text not null
);
```

### 2.2 Foreign Key Indexes
- **Always Index FKs:** PostgreSQL does *not* automatically index foreign keys. Always add an index to every foreign key column to prevent expensive lookups, especially for reverse relations.

❌ BAD
```sql
CREATE TABLE orders (
    id bigint generated always as identity primary key,
    user_id bigint references users (id)
);
-- Missing index on user_id
```

✅ GOOD
```sql
CREATE TABLE orders (
    id bigint generated always as identity primary key,
    user_id bigint references users (id)
);
CREATE INDEX ON orders (user_id);
```

### 2.3 Table Comments
- **Document Tables:** Always add a descriptive comment to each table using `COMMENT ON TABLE`.

❌ BAD
```sql
CREATE TABLE posts (
    id bigint generated always as identity primary key,
    title text
);
```

✅ GOOD
```sql
CREATE TABLE posts (
    id bigint generated always as identity primary key,
    title text not null,
    content text
);
COMMENT ON TABLE posts IS 'Blog posts published by users.';
```

## 3. Security Best Practices

Security is non-negotiable. Implement these measures from day one.

### 3.1 Row-Level Security (RLS)
- **Enable RLS Everywhere:** Enable RLS on *every* table in your database, especially those exposed via API. This is your primary defense.

❌ BAD
```sql
CREATE TABLE sensitive_data (
    id bigint generated always as identity primary key,
    secret text
);
-- RLS NOT ENABLED
```

✅ GOOD
```sql
CREATE TABLE sensitive_data (
    id bigint generated always as identity primary key,
    secret text,
    user_id uuid references auth.users(id)
);
ALTER TABLE sensitive_data ENABLE ROW LEVEL SECURITY;
CREATE POLICY select_own_secrets ON sensitive_data FOR SELECT USING (auth.uid() = user_id);
```

### 3.2 Function Security
- **Default to `SECURITY INVOKER`:** Functions should run with the permissions of the calling user. Use `SECURITY DEFINER` only when absolutely necessary and with extreme caution.
- **Explicit `search_path`:** If using `SECURITY DEFINER`, *always* set `search_path = ''` and use fully-qualified names (e.g., `public.table_name`) to prevent privilege escalation via malicious objects in other schemas.

❌ BAD
```sql
CREATE FUNCTION get_all_users()
RETURNS SETOF users
LANGUAGE plpgsql
SECURITY DEFINER -- Dangerous without search_path
AS $$
BEGIN
    RETURN QUERY SELECT * FROM users;
END;
$$;
```

✅ GOOD
```sql
CREATE FUNCTION get_current_user_profile()
RETURNS SETOF user_profiles
LANGUAGE plpgsql
SECURITY INVOKER -- Default and safer
SET search_path = '' -- Always set, even for INVOKER for clarity
AS $$
BEGIN
    RETURN QUERY SELECT * FROM public.user_profiles WHERE user_id = auth.uid();
END;
$$;

-- If SECURITY DEFINER is truly needed (rare):
CREATE FUNCTION admin_only_function()
RETURNS void
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = '' -- CRITICAL for SECURITY DEFINER
AS $$
BEGIN
    -- Use fully qualified names for ALL objects
    INSERT INTO public.audit_log (action) VALUES ('Admin function executed');
END;
$$;
```

### 3.3 Grant Permissions
- **Table-level `SELECT/DELETE`:** Grant `SELECT` and `DELETE` permissions at the table level.
- **Column-level `INSERT/UPDATE`:** Grant `INSERT` and `UPDATE` permissions at the column level for explicitness and to avoid optimizer issues.
- **Avoid Column-level `SELECT`:** This severely limits optimizations and functionality (e.g., `SELECT *`, `RETURNING *`).
- **Avoid Table-level `INSERT/UPDATE`:** Lacks explicitness.

❌ BAD
```sql
GRANT SELECT (id, name) ON users TO authenticated; -- Avoid column-level SELECT
GRANT INSERT ON users TO authenticated; -- Avoid table-level INSERT
```

✅ GOOD
```sql
GRANT SELECT ON users TO authenticated;
GRANT DELETE ON users TO authenticated;
GRANT INSERT (name, email) ON users TO authenticated;
GRANT UPDATE (name, email) ON users TO authenticated;
```

## 4. Performance & Query Optimization

Optimize your database interactions for speed and efficiency.

### 4.1 Prefer `LANGUAGE SQL` for Functions
- **Inlining:** Use `LANGUAGE sql` over `LANGUAGE plpgsql` for functions whenever possible. SQL functions can often be inlined by the query planner, leading to significant performance gains.

❌ BAD
```sql
CREATE FUNCTION add_one(a int)
RETURNS int
LANGUAGE plpgsql
AS $$
BEGIN
    RETURN a + 1;
END;
$$;
```

✅ GOOD
```sql
CREATE FUNCTION add_one(a int)
RETURNS int
LANGUAGE sql
IMMUTABLE -- Declare as IMMUTABLE if results depend only on inputs
AS $$
    SELECT a + 1;
$$;
```

### 4.2 Function Volatility
- **Immutable/Stable Defaults:** Declare functions as `IMMUTABLE` (returns same result for same inputs, no side effects) or `STABLE` (results change only within a single scan, no side effects) where appropriate. Default to `VOLATILE` only if the function modifies data or has external side effects. This allows PostgreSQL to optimize queries more effectively.

## 5. Testing & Linting

Ensure your database schema and functions are robust and error-free.

### 5.1 Database Testing
- **`supabase test db`:** Use the Supabase CLI (`supabase test db`) with `pgTAP` for comprehensive database unit and integration testing. Integrate this into your CI/CD pipeline.

### 5.2 Database Linting
- **`supabase db lint`:** Leverage `supabase db lint` (powered by `plpgsql_check`) to catch typing errors, unused variables, dead code, and potential SQL injection vulnerabilities early.

### 5.3 Type-Safe Query Builders
- **Kysely for Edge Functions:** For application code, especially in Edge Functions, use type-safe query builders like Kysely with `deno-postgres`. This provides compile-time guarantees and excellent autocompletion.

```typescript
// Example using Kysely in a Supabase Edge Function
import { Kysely, PostgresDialect } from 'kysely';
import { Pool } from 'https://deno.land/x/[email protected]/mod.ts'; // Deno Postgres driver

interface Database {
  users: {
    id: number;
    email: string;
    created_at: Date;
  };
  posts: {
    id: number;
    user_id: number;
    title: string;
  };
}

const db = new Kysely<Database>({
  dialect: new PostgresDialect({
    pool: new Pool({
      database: 'postgres',
      hostname: Deno.env.get('DB_HOSTNAME'),
      user: 'postgres',
      password: Deno.env.get('DB_PASSWORD'),
      port: 5432,
      tls: { caCertificates: [Deno.env.get('DB_SSL_CERT')!] },
    }, 1), // Single connection pool for Edge Functions
  }),
});

// Type-safe query example
const user = await db.selectFrom('users')
  .where('id', '=', 1)
  .select(['id', 'email'])
  .executeTakeFirst();

console.log(user?.email); // Autocompletion and type safety
```

© sanjeed5 · CC0-1.0 · sanjeed5/awesome-cursor-rules-mdc

Похожие правила IDE

Все правила IDE по теме «Данные и базы» →
supabase-security-audit davila7 Слэш-команда прогоняет аудит безопасности проекта на Supabase: проверяет RLS-политики, права ролей, ключи API и настройки аутентификации. 1 020установок supabase-schema-architect davila7 Субагент проектирует схемы PostgreSQL в Supabase, планирует миграции и пишет политики RLS. Пригодится, когда база растёт и надо навести порядок в доступе. 3 839установок sql-sp-generation официальный github Правило задаёт Copilot стиль для SQL: имена таблиц, ключи, транзакции, параметры и оформление хранимых процедур. ★ 40 478звёзд репо scala-spark официальный github Набор инструкций для GitHub Copilot по разработке на Apache Spark в Scala. Помогает писать быстрые трансформации, настраивать партиционирование и избегать падений памяти. ★ 40 478звёзд репо r официальный github Задаёт Copilot правила генерации кода на R: стиль проекта, безопасность, работа с путями и данными. Пригодится, если в репозитории есть .R, .Rmd или .qmd файлы. ★ 40 478звёзд репо power-bi-security-rls-best-practices официальный github Набор инструкций по настройке Row-Level Security (RLS) в Power BI. Помогает генерировать шаблоны DAX, SQL-предикаты и код для Embedded-аналитики. ★ 40 478звёзд репо power-bi-report-design-best-practices официальный github Правило помогает выбирать визуализации и проектировать структуру отчётов Power BI. Пригодится, когда нужно продумать страницу, диаграмму или навигацию. ★ 40 478звёзд репо power-bi-devops-alm-best-practices официальный github Правило для GitHub Copilot: подсказывает агенту, как вести Power BI-проект в Git, собирать CI/CD и раскатывать отчёты по средам. ★ 40 478звёзд репо

Из того же набора240

Весь набор →
three-js Правило для Cursor задаёт стандарты разработки на three.js: обработка ошибок WebGL, ленивая загрузка ассетов, оптимизация цикла рендера и освобождение ресурсов. ★ 3 580звёзд репо terraform Задаёт стандарты написания манифестов Terraform для Cursor: структуру каталогов, именование, блокировки стейта и правила модулей. ★ 3 580звёзд репо tensorflow Правило задаёт ориентиры для Python-кода с TensorFlow: модели на tf.keras, конвейеры данных на tf.data и компиляцию функций через @tf.function. Пригодится для настройки проекта машинного обучения. ★ 3 580звёзд репо tauri Правило для Cursor задаёт, как писать Rust-бэкенд в Tauri: команды, глобальное состояние, ошибки и безопасность. Пригодится, когда фронтенд уже есть, а Rust-часть растёт. ★ 3 580звёзд репо tailwind Задаёт стандарты верстки на Tailwind CSS: структуру токенов, порядок утилитных классов и правила доступности интерфейса. ★ 3 580звёзд репо sveltekit Правило задаёт структуру SvelteKit-проектов, работу с Svelte 5 runes, маршрутизацией, тестами и серверным кодом. Подходит для Cursor. ★ 3 580звёзд репо svelte Правило для Cursor задаёт, как писать компоненты Svelte 5: руны вместо старой реактивности, типизация и ключи в списках. Пригодится, если проект уже на Svelte 5. ★ 3 580звёзд репо stripe Правило задаёт практики для платёжных сценариев Stripe: от Checkout Sessions и Payment Intents до обработки ошибок и вебхуков. ★ 3 580звёзд репо

Спонсоры проекта

Компании, которые помогают держать аналитику открытой