Skip to main content
Jet integrates with Supabase for authentication, database, storage, and edge functions.

Prerequisites

Supabase Account

Create a free account at supabase.com

Supabase CLI

Installed via npm (included in Jet’s devDependencies)

Quick Reference

Common Supabase CLI commands:
# Check Supabase status
npx supabase status

# Start local Supabase
npx supabase start

# Stop local Supabase
npx supabase stop

# Create new edge function
npx supabase functions new <function-name>

# Serve edge functions locally
npx supabase functions serve

# Create new migration
npx supabase migrations new <migration-name>

# Reset database (applies all migrations)
npx supabase db reset

Initial Setup

1

Set project ID

Update supabase/config.toml with a unique project ID:
project_id = "your-app-name"
This distinguishes your project from others on the same machine.
2

Start Supabase locally

npx supabase start
This starts:
  • Postgres database on port 54322
  • API server on port 54321
  • Studio (dashboard) on port 54323
  • Inbucket (email testing) on port 54324
First start takes a few minutes to download Docker images.
3

Get local credentials

After starting, Supabase displays:
API URL: http://localhost:54321
anon key: eyJhbGc...
service_role key: eyJhbGc...
4

Update .env file

Add credentials to .env:
NG_APP_SUPABASE_URL=http://localhost:54321
NG_APP_SUPABASE_PUBLISHABLE_OR_ANON_KEY=eyJhbGc...
5

Restart dev server

ng serve
Your app now connects to local Supabase.

Local Development

Accessing Services

Open http://localhost:54323 to access:
  • Table editor
  • SQL editor
  • Authentication users
  • Storage buckets
  • Edge functions

Database Migrations

Jet includes pre-built migrations in supabase/migrations/:
supabase/migrations/
├── 01_extensions.sql           # Enable required Postgres extensions
├── 02_schemas.sql              # Create custom schemas
├── 03_domains.sql              # Custom domain types
├── 04_types.sql                # Custom types
├── 05_tables.sql               # Create tables (profiles, etc.)
├── 06_rls_policies.sql         # Row Level Security policies
├── 07_indexes.sql              # Database indexes
├── 08_functions.sql            # Database functions
├── 09_triggers.sql             # Database triggers
├── 10_storage.sql              # Storage buckets
├── 11_storage_rls_policies.sql # Storage RLS policies
├── 12_crons.sql                # Scheduled jobs
└── 13_rbac.sql                 # Role-based access control

Creating Migrations

1

Generate migration file

npx supabase migrations new add_posts_table
Creates supabase/migrations/YYYYMMDDHHMMSS_add_posts_table.sql
2

Write SQL

-- Add posts table
CREATE TABLE public.posts (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
  title TEXT NOT NULL,
  content TEXT,
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Enable RLS
ALTER TABLE public.posts ENABLE ROW LEVEL SECURITY;

-- RLS Policies
CREATE POLICY "Users can read own posts"
  ON public.posts
  FOR SELECT
  USING (auth.uid() = user_id);

CREATE POLICY "Users can insert own posts"
  ON public.posts
  FOR INSERT
  WITH CHECK (auth.uid() = user_id);
3

Apply migrations

npx supabase db reset
This resets the database and applies all migrations in order.

Testing with Seed Data

Create seed data in supabase/seed.sql:
-- Insert test data
INSERT INTO public.posts (user_id, title, content)
VALUES 
  (auth.uid(), 'First Post', 'Hello from seed data'),
  (auth.uid(), 'Second Post', 'More test content');
Seed data is applied automatically on npx supabase db reset.

Linking a Remote Project

Connect your local development to a production Supabase project:
1

Create Supabase project

  1. Go to app.supabase.com
  2. Create a new project
  3. Note your project reference ID (from Settings → General)
2

Login to Supabase CLI

npx supabase login
3

Link project

npx supabase link --project-ref your-project-ref
4

Push migrations to remote

npx supabase db push
Applies local migrations to your remote database.
5

Get production credentials

From Supabase dashboard → Settings → API:
  • Project URL
  • anon/public key
6

Update production environment

Set these in your deployment platform:
NG_APP_SUPABASE_URL=https://your-project.supabase.co
NG_APP_SUPABASE_PUBLISHABLE_OR_ANON_KEY=your-production-key

Edge Functions

Supabase Edge Functions are serverless TypeScript functions that run on Deno.

Creating Edge Functions

1

Generate function

npx supabase functions new send-welcome-email
Creates supabase/functions/send-welcome-email/index.ts
2

Write function code

import { serve } from 'https://deno.land/[email protected]/http/server.ts'

serve(async (req) => {
  const { email, name } = await req.json()
  
  // Your function logic here
  console.log(`Sending welcome email to ${email}`)
  
  return new Response(
    JSON.stringify({ success: true }),
    { headers: { 'Content-Type': 'application/json' } }
  )
})
3

Test locally

npx supabase functions serve send-welcome-email
Test with curl:
curl -X POST http://localhost:54321/functions/v1/send-welcome-email \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","name":"Test User"}'
4

Deploy to production

npx supabase functions deploy send-welcome-email

Calling Edge Functions from Angular

import { inject } from '@angular/core';
import { SUPABASE_CLIENT } from '@jet/injection-tokens/supabase-client.injection-token';
import { SupabaseEdgeFunction } from '@jet/enums/supabase-edge-function.enum';

export class WelcomeService {
  readonly #supabase = inject(SUPABASE_CLIENT);

  async sendWelcomeEmail(email: string, name: string) {
    const { data, error } = await this.#supabase.functions.invoke(
      SupabaseEdgeFunction.SendWelcomeEmail,
      {
        body: { email, name }
      }
    );

    if (error) throw error;
    return data;
  }
}

Authentication Setup

Jet includes pre-configured authentication flows.

Email Configuration

Emails are caught by Inbucket at http://localhost:54324.No configuration needed.

OAuth Providers

Enable OAuth providers in supabase/config.toml:
[auth.external.google]
enabled = true
client_id = "env(GOOGLE_CLIENT_ID)"
secret = "env(GOOGLE_CLIENT_SECRET)"

[auth.external.github]
enabled = true
client_id = "env(GITHUB_CLIENT_ID)"
secret = "env(GITHUB_CLIENT_SECRET)"

Storage Setup

Jet includes a pre-configured avatars storage bucket.

Using Storage in Angular

import { inject } from '@angular/core';
import { SUPABASE_CLIENT } from '@jet/injection-tokens/supabase-client.injection-token';
import { SupabaseBucket } from '@jet/enums/supabase-bucket.enum';

export class ProfileService {
  readonly #supabase = inject(SUPABASE_CLIENT);

  async uploadAvatar(userId: string, file: File) {
    const { data, error } = await this.#supabase.storage
      .from(SupabaseBucket.Avatars)
      .upload(`${userId}/avatar.png`, file, {
        upsert: true
      });

    if (error) throw error;
    return data;
  }

  getAvatarUrl(userId: string) {
    return this.#supabase.storage
      .from(SupabaseBucket.Avatars)
      .getPublicUrl(`${userId}/avatar.png`).data.publicUrl;
  }
}

Role-Based Access Control (RBAC)

Jet includes RBAC setup in 13_rbac.sql.

App Roles

// src/app/enums/app-role.enum.ts
export enum AppRole {
  Admin = 'admin',
  User = 'user',
}

Checking User Roles

import { inject } from '@angular/core';
import { UserService } from '@jet/services/user/user.service';
import { AppRole } from '@jet/enums/app-role.enum';

export class AdminPageComponent {
  readonly #userService = inject(UserService);
  
  readonly isAdmin = computed(() => 
    this.#userService.role() === AppRole.Admin
  );
}

Removing RBAC

If you don’t need RBAC:
  1. Delete supabase/migrations/13_rbac.sql
  2. Remove role checks from code
  3. Reset database: npx supabase db reset

Removing Supabase

To remove Supabase completely:
1

Stop Supabase

npx supabase stop
2

Remove Supabase files

rm -rf supabase/
3

Uninstall dependencies

npm uninstall @supabase/supabase-js supabase
4

Remove Supabase code

Remove:
  • Supabase injection tokens
  • Auth services and guards
  • Profile services
  • Storage references
5

Update environment variables

Remove Supabase variables from .env and .env.example.

Troubleshooting

Check if Docker is running:
docker ps
If Docker isn’t running, start Docker Desktop.If ports are in use:
npx supabase stop
npx supabase start
Check migration syntax:
npx supabase db lint
Reset and try again:
npx supabase db reset
  1. Check environment variables are correct
  2. Verify site_url in supabase/config.toml:
    [auth]
    site_url = "http://localhost:4200"
    
  3. Check emails in Inbucket for confirmation links
Test with RLS disabled temporarily:
ALTER TABLE public.your_table DISABLE ROW LEVEL SECURITY;
Then add proper policies:
ALTER TABLE public.your_table ENABLE ROW LEVEL SECURITY;

CREATE POLICY "Users can read own data"
  ON public.your_table
  FOR SELECT
  USING (auth.uid() = user_id);

Best Practices

Enable Row Level Security on all tables:
ALTER TABLE public.posts ENABLE ROW LEVEL SECURITY;
Never disable RLS in production.
Never make schema changes directly in production. Always:
  1. Create migration locally
  2. Test with npx supabase db reset
  3. Push to production with npx supabase db push
Commit all migration files to Git. This ensures:
  • Reproducible database schema
  • Easy rollbacks
  • Team synchronization
Define Supabase references in enums:
export enum SupabaseTable {
  Profiles = 'profiles',
  Posts = 'posts',
}

export enum SupabaseBucket {
  Avatars = 'avatars',
  Documents = 'documents',
}

Build docs developers (and LLMs) love