Supabase Database Setup for Web Application

Our company is engaged in the development, support and maintenance of sites of any complexity. From simple one-page sites to large-scale cluster systems built on micro services. Experience of developers is confirmed by certificates from vendors.
Development and maintenance of all types of websites:
Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Showing 1 of 1 servicesAll 2065 services
Supabase Database Setup for Web Application
Medium
from 1 business day to 3 business days
FAQ
Our competencies:
Development stages
Latest works
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    822
  • image_crm_chasseurs_493_0.webp
    CRM development for Chasseurs
    847
  • image_website-sbh_0.png
    Website development for SBH Partners
    999
  • image_website-_0.png
    Website development for Red Pear
    451

Setting Up Supabase for Web Application

Supabase is an open source Firebase alternative based on PostgreSQL. Includes database, authentication, realtime subscriptions, file storage and Edge Functions. Suitable for rapid development and projects where development speed is crucial.

Creating a project

Via dashboard.supabase.com — select region, set database password. For self-hosted:

git clone --depth 1 https://github.com/supabase/supabase
cd supabase/docker
cp .env.example .env
# Edit .env: POSTGRES_PASSWORD, JWT_SECRET, ANON_KEY, SERVICE_ROLE_KEY
docker compose up -d

Client connection

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!
)

// For server-side operations — service role key
export const supabaseAdmin = createClient<Database>(
  process.env.SUPABASE_URL!,
  process.env.SUPABASE_SERVICE_ROLE_KEY!
)

Generating types from schema

npx supabase gen types typescript --project-id your-project-id > src/types/database.types.ts

This gives autocomplete and type checking when working with tables.

Schema and Row Level Security

-- Profile table (extends 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 — each user sees only their own
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);

-- Public profiles — everyone can read
CREATE POLICY "profiles_select_public" ON profiles
  FOR SELECT USING (true);
-- Posts table with 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);

Authentication

// Sign up
const { data, error } = await supabase.auth.signUp({
  email: '[email protected]',
  password: 'password',
  options: {
    data: { username: 'john_doe' }  // additional data in user_metadata
  }
})

// OAuth (Google, GitHub, etc.)
await supabase.auth.signInWithOAuth({
  provider: 'google',
  options: { redirectTo: `${window.location.origin}/auth/callback` }
})

// Get current user
const { data: { user } } = await supabase.auth.getUser()

// Subscribe to session changes
supabase.auth.onAuthStateChange((event, session) => {
  if (event === 'SIGNED_IN') router.push('/dashboard')
  if (event === 'SIGNED_OUT') router.push('/login')
})

CRUD operations

// Insert with return
const { data: post, error } = await supabase
  .from('posts')
  .insert({ title, content, user_id: user.id })
  .select()
  .single()

// Query with filters and 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)  // pagination

// Full-text search (PostgreSQL tsquery)
const { data } = await supabase
  .from('posts')
  .select('*')
  .textSearch('content', query, { config: 'english', type: 'websearch' })

Realtime subscriptions

// Subscribe to new records
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()

// Unsubscribe on unmount
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' }
  })
})
# Deploy function
supabase functions deploy send-notification

File storage

// Upload avatar
const { data, error } = await supabase.storage
  .from('avatars')
  .upload(`${user.id}/avatar.jpg`, file, {
    cacheControl: '3600',
    upsert: true
  })

// Get public URL
const { data: { publicUrl } } = supabase.storage
  .from('avatars')
  .getPublicUrl(`${user.id}/avatar.jpg`)

Timelines

Supabase project setup with authentication, RLS policies and basic CRUD: 1–2 days. Adding realtime, Edge Functions, storage and frontend integration: 2–3 more days. Self-hosted deployment with backup and monitoring configuration: 1–2 more days.