Настройка Supabase для веб-приложения
Supabase — open source альтернатива Firebase на базе PostgreSQL. Включает базу данных, аутентификацию, realtime-подписки, хранилище файлов и Edge Functions. Хорошо подходит для быстрого старта и проектов, где важна скорость разработки.
Создание проекта
Через dashboard.supabase.com — выбрать регион, задать пароль базы. Для self-hosted:
git clone --depth 1 https://github.com/supabase/supabase
cd supabase/docker
cp .env.example .env
# Отредактировать .env: POSTGRES_PASSWORD, JWT_SECRET, ANON_KEY, SERVICE_ROLE_KEY
docker compose up -d
Подключение клиента
import { createClient } from '@supabase/supabase-js'
import type { Database } from './database.types'
export const supabase = createClient<Database>(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
// Для серверных операций — service role key
export const supabaseAdmin = createClient<Database>(
process.env.SUPABASE_URL!,
process.env.SUPABASE_SERVICE_ROLE_KEY!
)
Генерация типов из схемы
npx supabase gen types typescript --project-id your-project-id > src/types/database.types.ts
Это даёт автодополнение и проверку типов при работе с таблицами.
Схема и Row Level Security
-- Таблица профилей (расширение auth.users)
CREATE TABLE profiles (
id uuid PRIMARY KEY REFERENCES auth.users ON DELETE CASCADE,
username text UNIQUE,
avatar_url text,
bio text,
updated_at timestamptz DEFAULT now()
);
-- RLS — каждый видит только своё
ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;
CREATE POLICY "profiles_select_own" ON profiles
FOR SELECT USING (auth.uid() = id);
CREATE POLICY "profiles_update_own" ON profiles
FOR UPDATE USING (auth.uid() = id);
-- Публичные профили — читают все
CREATE POLICY "profiles_select_public" ON profiles
FOR SELECT USING (true);
-- Таблица постов с RLS
CREATE TABLE posts (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
user_id uuid REFERENCES auth.users NOT NULL,
title text NOT NULL,
content text,
is_public boolean DEFAULT false,
created_at timestamptz DEFAULT now()
);
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;
CREATE POLICY "posts_select_public_or_own" ON posts
FOR SELECT USING (
is_public = true OR auth.uid() = user_id
);
CREATE POLICY "posts_insert_own" ON posts
FOR INSERT WITH CHECK (auth.uid() = user_id);
CREATE POLICY "posts_update_own" ON posts
FOR UPDATE USING (auth.uid() = user_id);
CREATE POLICY "posts_delete_own" ON posts
FOR DELETE USING (auth.uid() = user_id);
Аутентификация
// Регистрация
const { data, error } = await supabase.auth.signUp({
email: '[email protected]',
password: 'password',
options: {
data: { username: 'john_doe' } // дополнительные данные в user_metadata
}
})
// OAuth (Google, GitHub, etc.)
await supabase.auth.signInWithOAuth({
provider: 'google',
options: { redirectTo: `${window.location.origin}/auth/callback` }
})
// Получение текущего пользователя
const { data: { user } } = await supabase.auth.getUser()
// Подписка на изменения сессии
supabase.auth.onAuthStateChange((event, session) => {
if (event === 'SIGNED_IN') router.push('/dashboard')
if (event === 'SIGNED_OUT') router.push('/login')
})
CRUD операции
// Вставка с возвратом
const { data: post, error } = await supabase
.from('posts')
.insert({ title, content, user_id: user.id })
.select()
.single()
// Запрос с фильтрами и JOIN
const { data: posts } = await supabase
.from('posts')
.select(`
id, title, created_at,
profiles ( username, avatar_url ),
tags ( name )
`)
.eq('is_public', true)
.order('created_at', { ascending: false })
.range(0, 23) // пагинация
// Полнотекстовый поиск (PostgreSQL tsquery)
const { data } = await supabase
.from('posts')
.select('*')
.textSearch('content', query, { config: 'russian', type: 'websearch' })
Realtime подписки
// Подписка на новые записи
const channel = supabase
.channel('posts-feed')
.on('postgres_changes', {
event: 'INSERT',
schema: 'public',
table: 'posts',
filter: 'is_public=eq.true'
}, (payload) => {
setPosts(prev => [payload.new as Post, ...prev])
})
.subscribe()
// Отписка при размонтировании
return () => supabase.removeChannel(channel)
Edge Functions
// supabase/functions/send-notification/index.ts
import { serve } from 'https://deno.land/[email protected]/http/server.ts'
import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'
serve(async (req) => {
const { userId, message } = await req.json()
const supabase = createClient(
Deno.env.get('SUPABASE_URL')!,
Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!
)
await supabase
.from('notifications')
.insert({ user_id: userId, message })
return new Response(JSON.stringify({ ok: true }), {
headers: { 'Content-Type': 'application/json' }
})
})
# Деплой функции
supabase functions deploy send-notification
Хранилище файлов
// Загрузка аватара
const { data, error } = await supabase.storage
.from('avatars')
.upload(`${user.id}/avatar.jpg`, file, {
cacheControl: '3600',
upsert: true
})
// Получение публичной ссылки
const { data: { publicUrl } } = supabase.storage
.from('avatars')
.getPublicUrl(`${user.id}/avatar.jpg`)
Сроки
Настройка Supabase-проекта с аутентификацией, RLS-политиками и базовым CRUD: 1–2 дня. Добавление realtime, Edge Functions, хранилища и интеграции с фронтендом: ещё 2–3 дня. Self-hosted деплой с настройкой бэкапов и мониторинга: 1–2 дня дополнительно.







