BaaS Service User Guide

Updated at:

This topic describes how to use BaaS Service (Supabase Compatible), including obtaining API credentials, performing data operations with language-specific SDKs, deploying Edge Functions, and leveraging AI-assisted development.

Obtain the Supabase URL and API key

Before using the Supabase SDK or calling the API, you must obtain the Supabase URL and API key for your service.

Supabase URL

The Supabase URL is the entry point of the API gateway. All client requests access the BaaS Service through this URL. URL format: <supabase_instance_ID>.polardbxaisupabase.rds.aliyuncs.com

API key types

Supabase provides two types of API keys for different scenarios:

Key type

Use case

Description

anonKey

Frontend / Client

Restricted by Row Level Security (RLS) policies. Can only access data permitted by RLS policies. Safe to expose in client-side code.

serviceRoleKey

Backend / Server

Bypasses all RLS policies and has full data access. Use only in trusted server-side environments.

Warning

Do not expose serviceRoleKey in frontend code. This key bypasses all Row Level Security policies, and a leak would allow unauthorized data access. Use it only in backend services and manage it through environment variables.

JWT Payload structure

API keys are essentially JWTs (JSON Web Tokens). Different key types contain different payloads. The following examples show the payload for each type:

  • anon key Payload

    {
      "iss": "supabase",
      "ref": "your-project-ref",
      "role": "anon",
      "iat": 1700000000,
      "exp": 2000000000
    }
  • service_role key Payload

    {
      "iss": "supabase",
      "ref": "your-project-ref",
      "role": "service_role",
      "iat": 1700000000,
      "exp": 2000000000
    }
  • Authenticated user Payload

    {
      "aud": "authenticated",
      "exp": 1700003600,
      "iat": 1700000000,
      "iss": "https://your-project-ref.supabase.co/auth/v1",
      "sub": "user-uuid-here",
      "email": "user@example.com",
      "role": "authenticated",
      "session_id": "session-uuid-here"
    }

SDK usage

Supabase provides official SDKs for multiple languages, supporting database CRUD operations, user authentication, real-time subscriptions, file uploads, and more. Select your development language to view the integration method.

Note

Note on table creation: Create and manage table schemas through the Dashboard using the Table Editor (visual) or SQL Editor. SDKs are used only for data read/write operations.

JavaScript / TypeScript

  • Installation

    npm install @supabase/supabase-js
  • Initialization and data operations

    import { createClient } from '@supabase/supabase-js'
    
    const supabase = createClient(
      '<YOUR_SUPABASE_URL>',
      '<YOUR_SUPABASE_ANON_KEY>'
    )
    
    // Sign up
    const { data: { user } } = await supabase.auth.signUp({
      email: 'user@example.com',
      password: 'password123'
    })
    
    // Sign in
    const { data: { session } } = await supabase.auth.signInWithPassword({
      email: 'user@example.com',
      password: 'password123'
    })
    
    // Insert data
    const { data } = await supabase.from('todos').insert({
      title: 'Learn Supabase',
      done: false
    }).select()
    
    // Query data
    const { data: todos } = await supabase.from('todos')
      .select('*')
      .eq('done', false)
      .order('created_at', { ascending: false })
    
    // Update data
    const { data: updated } = await supabase.from('todos')
      .update({ done: true })
      .eq('id', 1)
      .select()
    
    // Delete data
    await supabase.from('todos').delete().eq('id', 1)
    
    // Real-time subscription
    supabase.channel('todos-changes')
      .on('postgres_changes', {
        event: '*',
        schema: 'public',
        table: 'todos'
      }, (payload) => {
        console.log('Data changed:', payload)
      })
      .subscribe()
    
    // File upload
    await supabase.storage.from('avatars').upload('user1/avatar.png', file)

Python

  • Installation

    pip install supabase
  • Initialization and data operations

    import os
    from supabase import create_client, Client
    
    url: str = os.environ.get("YOUR_SUPABASE_URL")
    key: str = os.environ.get("YOUR_SUPABASE_ANON_KEY")
    supabase: Client = create_client(url, key)
    
    # Sign up
    res = supabase.auth.sign_up({"email": "user@example.com", "password": "password123"})
    
    # Sign in
    res = supabase.auth.sign_in_with_password({"email": "user@example.com", "password": "password123"})
    
    # Insert
    supabase.table("todos").insert({"title": "Learn Supabase", "done": False}).execute()
    
    # Query
    response = supabase.table("todos").select("*").eq("done", False).order("created_at", desc=True).execute()
    
    # Update
    supabase.table("todos").update({"done": True}).eq("id", 1).execute()
    
    # Delete
    supabase.table("todos").delete().eq("id", 1).execute()
    
    # File upload
    supabase.storage.from_("avatars").upload("user1/avatar.png", file_data)

Flutter / Dart

  • Installation

    flutter pub add supabase_flutter
  • Initialization and data operations

    import 'package:supabase_flutter/supabase_flutter.dart';
    
    Future<void> main() async {
      await Supabase.initialize(
        url: '<YOUR_SUPABASE_URL>',
        anonKey: '<YOUR_SUPABASE_ANON_KEY>',
      );
      runApp(MyApp());
    }
    
    final supabase = Supabase.instance.client;
    
    // Sign up
    await supabase.auth.signUp(email: 'user@example.com', password: 'password123');
    
    // Sign in
    await supabase.auth.signInWithPassword(email: 'user@example.com', password: 'password123');
    
    // Insert
    await supabase.from('todos').insert({'title': 'New task', 'done': false});
    
    // Query
    final data = await supabase.from('todos').select().eq('done', false).order('created_at');
    
    // Update
    await supabase.from('todos').update({'done': true}).eq('id', 1);
    
    // Delete
    await supabase.from('todos').delete().eq('id', 1);
    
    // File upload
    await supabase.storage.from('avatars').upload('user1/avatar.png', file);

Swift

Initialization and data operations

import Supabase

let client = SupabaseClient(
  supabaseURL: URL(string: "<YOUR_SUPABASE_URL>")!,
  supabaseKey: "<YOUR_SUPABASE_ANON_KEY>"
)

// Sign up
try await client.auth.signUp(email: "user@example.com", password: "password123")

// Sign in
try await client.auth.signIn(email: "user@example.com", password: "password123")

// Insert
try await client.from("todos").insert(["title": "New task", "done": false]).execute()

// Query
let todos: [Todo] = try await client.from("todos").select().eq("done", value: false).execute().value

// Update
try await client.from("todos").update(["done": true]).eq("id", value: 1).execute()

// Delete
try await client.from("todos").delete().eq("id", value: 1).execute()

Kotlin

Initialization and data operations

val supabase = createSupabaseClient(
    supabaseUrl = "<YOUR_SUPABASE_URL>",
    supabaseKey = "<YOUR_SUPABASE_ANON_KEY>"
) {
    install(Auth)
    install(Postgrest)
    install(Storage)
}

// Sign up
supabase.auth.signUpWith(Email) { email = "user@example.com"; password = "password123" }

// Sign in
supabase.auth.signInWith(Email) { email = "user@example.com"; password = "password123" }

// Insert
supabase.from("todos").insert(Todo(title = "New task", done = false))

// Query
val todos = supabase.from("todos").select { filter { eq("done", false) } }.decodeList<Todo>()

// Update
supabase.from("todos").update({ set("done", true) }) { filter { eq("id", 1) } }

// Delete
supabase.from("todos").delete { filter { eq("id", 1) } }

C#

Initialization and data operations

var url = Environment.GetEnvironmentVariable("YOUR_SUPABASE_URL") ?? throw new InvalidOperationException("Environment variable YOUR_SUPABASE_URL is not set.");
var key = Environment.GetEnvironmentVariable("YOUR_SUPABASE_ANON_KEY") ?? throw new InvalidOperationException("Environment variable YOUR_SUPABASE_ANON_KEY is not set.");
var supabase = new Supabase.Client(url, key);
await supabase.InitializeAsync();

// Sign up
await supabase.Auth.SignUp("user@example.com", "password123");

// Sign in
await supabase.Auth.SignIn("user@example.com", "password123");

// Insert
await supabase.From<Todo>().Insert(new Todo { Title = "New task", Done = false });

// Query
var todos = await supabase.From<Todo>().Filter("done", Operator.Equals, "false").Get();

// Update
await supabase.From<Todo>().Filter("id", Operator.Equals, "1").Update(new Todo { Done = true });

// Delete
await supabase.From<Todo>().Filter("id", Operator.Equals, "1").Delete();

Edge Functions

Edge Functions are serverless functions that run on the Supabase platform, powered by the Deno runtime with TypeScript support. You can use Edge Functions to implement custom business logic, third-party API integrations, webhook handling, and more.

Create a function

Create a TypeScript file as the function entry point. The following example implements a simple Hello World function:

// supabase/functions/hello-world/index.ts
import { serve } from "https://deno.land/std@0.168.0/http/server.ts"

Deno.serve(async (req: Request) => {
  const { name } = await req.json()

  const data = {
    message: `Hello ${name}!`,
  }

  return new Response(
    JSON.stringify(data),
    { headers: { "Content-Type": "application/json" } }
  )
})

Deploy a function

Deploy Edge Functions through the API:

curl -X POST "https://<YOUR_SUPABASE_URL>/functions/v1/deploy" \
  -H "Authorization: Bearer <YOUR_SUPABASE_SERVICE_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "slug": "hello-world",
    "name": "hello-world",
    "entrypoint_path": "./index.ts",
    "verify_jwt": true
  }'

Deployment parameter description:

Parameter

Type

Description

slug

STRING

The URL path identifier of the function, used for URL construction when invoking the function.

name

STRING

The display name of the function.

entrypoint_path

STRING

The relative path to the function entry file.

verify_jwt

BOOLEAN

Whether to verify the JWT token in requests. When set to true, requests without a valid token are rejected.

Invoke a function

After deployment, invoke the Edge Function with an HTTP POST request:

curl -X POST "https://<YOUR_SUPABASE_URL>/functions/v1/hello-world" \
  -H "Authorization: Bearer <YOUR_SUPABASE_ANON_KEY>" \
  -H "Content-Type: application/json" \
  -d '{"name": "World"}'

Manage functions

  • List functions

    curl -X GET "https://<YOUR_SUPABASE_URL>/functions/v1/" \
      -H "Authorization: Bearer <YOUR_SUPABASE_SERVICE_KEY>"
  • Update a function

    curl -X PUT "https://<YOUR_SUPABASE_URL>/functions/v1/hello-world" \
      -H "Authorization: Bearer <YOUR_SUPABASE_SERVICE_KEY>" \
      -H "Content-Type: application/json" \
      -d '{
        "entrypoint_path": "./index.ts",
        "verify_jwt": false
      }'
  • Delete a function

    curl -X DELETE "https://<YOUR_SUPABASE_URL>/functions/v1/hello-world" \
      -H "Authorization: Bearer <YOUR_SUPABASE_SERVICE_KEY>"

Use the SDK in functions

You can initialize a Supabase client inside Edge Functions and use the SDK to interact with the database. This approach automatically enforces RLS policies.

import { serve } from "https://deno.land/std@0.168.0/http/server.ts"
import { createClient } from "https://esm.sh/@supabase/supabase-js@2"

Deno.serve(async (req: Request) => {
  const supabase = createClient(
    Deno.env.get("<YOUR_SUPABASE_URL>") ?? "",
    Deno.env.get("<YOUR_SUPABASE_ANON_KEY>") ?? "",
    {
      global: {
        headers: { Authorization: req.headers.get("Authorization")! }
      }
    }
  )

  const { data, error } = await supabase
    .from("todos")
    .select("*")

  return new Response(
    JSON.stringify({ data, error }),
    { headers: { "Content-Type": "application/json" } }
  )
})

Connect directly to the PolarDB-X database

In Edge Functions, you can also use mysql2/promise to connect directly to the PolarDB-X database and execute raw SQL.

import { serve } from "https://deno.land/std@0.168.0/http/server.ts"
import mysql from "npm:mysql2/promise"

Deno.serve(async (req: Request) => {
  const connection = await mysql.createConnection({
    host: Deno.env.get("DB_HOST"),
    port: Number(Deno.env.get("DB_PORT") || 3306),
    user: Deno.env.get("DB_USER"),
    password: Deno.env.get("DB_PASSWORD"),
    database: Deno.env.get("DB_NAME"),
  })

  try {
    const [rows] = await connection.execute("SELECT * FROM todos WHERE completed = ?", [false])

    return new Response(
      JSON.stringify({ data: rows }),
      { headers: { "Content-Type": "application/json" } }
    )
  } finally {
    await connection.end()
  }
})
Important

When you access the database through the SDK, RLS policies are automatically enforced. When you connect directly to the database, all RLS policies are bypassed. Choose the appropriate access method based on your security requirements.

AI-assisted development

To improve development efficiency, we recommend loading the mysql-supabase-dev skill pack in your AI coding tool. This skill pack is optimized for BaaS Service (Supabase Compatible) scenarios and covers the following use cases:

  • SDK usage: Automatically generates SDK call code following best practices, including error handling and type definitions.

  • RLS policy authoring: Automatically generates Row Level Security policy SQL statements based on your business requirements.

  • SQL syntax mapping: Automatically maps PostgreSQL syntax to MySQL-compatible syntax for the PolarDB-X engine.

  • Edge Functions development: Assists with writing, debugging, and deploying Edge Functions.

  • Database migration scripts: Automatically generates migration files for schema changes.

Supported AI coding tools: Claude, Cursor, Codex, and Qoder.

Learn more

For more Supabase features and advanced usage, see the official Supabase documentation: Supabase official documentation