--- title: Quickstart subtitle: 'Learn how to use Supabase Queues to add and read messages' --- This guide is an introduction to interacting with Supabase Queues via the Dashboard and official client library. Check out [Queues API Reference](/docs/guides/queues/api) for more details on our API. ## Concepts Supabase Queues is a pull-based Message Queue consisting of three main components: Queues, Messages, and Queue Types. ### Pull-Based Queue A pull-based Queue is a Message storage and delivery system where consumers actively fetch Messages when they're ready to process them - similar to constantly refreshing a webpage to display the latest updates. Our pull-based Queues process Messages in a First-In-First-Out (FIFO) manner without priority levels. ### Message A Message in a Queue is a JSON object that is stored until a consumer explicitly processes and removes it, like a task waiting in a to-do list until someone checks and completes it. ### Queue types Supabase Queues offers three types of Queues: - **Basic Queue**: A durable Queue that stores Messages in a logged table. - **Unlogged Queue**: A transient Queue that stores Messages in an unlogged table for better performance but may result in loss of Queue Messages. ## Create Queues To get started, navigate to the [Supabase Queues](/dashboard/project/_/integrations/queues/overview) Postgres Module under Integrations in the Dashboard and enable the `pgmq` extension. `pgmq` extension is available in Postgres version 15.6.1.143 or later. Supabase Dashboard Integrations page, showing the Queues Postgres Module On the [Queues page](/dashboard/project/_/integrations/queues/queues): - Click **Create queue** button - Name your queue Queue names can only be lowercase and hyphens and underscores are permitted. - Select your [Queue Type](#queue-types) - We recommend leaving Row Level Security (RLS) enabled. With it enabled, you don't need to set additional RLS on the queue tables. A screenshot showing the process to create a Queue from the Supabase Dashboard Every new Queue creates two tables in the `pgmq` schema. These tables are `pgmq.q_` to store and process active messages and `pgmq.a_` to store any archived messages. A "Basic Queue" creates `pgmq.q_` and `pgmq.a_` tables as logged tables. However, an "Unlogged Queue" creates `pgmq.q_` as an unlogged table for better performance while sacrificing durability. The `pgmq.a_` table is still created as a logged table so your archived messages remain safe and secure. ## Expose Queues to client-side consumers Queues, by default, are not exposed over the Supabase Data API and are only accessible via Postgres clients. However, you may grant client-side consumers access to your Queues by enabling the Supabase Data API and granting permissions to the Queues API, which is a collection of database functions in the `pgmq_public` schema that wraps the database functions in the `pgmq` schema. This is to prevent direct access to the `pgmq` schema and its tables (RLS is not enabled by default on any tables) and database functions. To get started, navigate to the [**Queues > Settings**](/dashboard/project/_/integrations/queues/settings) section of the Dashboard and enable **Expose Queues via PostgREST**. Once enabled, Supabase creates and exposes a `pgmq_public` schema containing database function wrappers to a subset of `pgmq`'s database functions. ### Add an RLS policy on your tables in `pgmq` schema [#enable-rls-on-your-tables-in-pgmq-schema] If you expose your pgmq schema with the Data API, for security purposes, you must enable Row Level Security (RLS) on all Queue tables (all tables in `pgmq` schema that begin with `q_`) Add an RLS policy for any Queues you want your client-side consumers to interact with, by clicking the _Add RLS Policy_ button on [the overview page of any Queue in the Dashboard](/dashboard/project/_/integrations/queues/queues). ### Grant permissions to `pgmq_public` database functions On top of enabling RLS and writing RLS policies on the underlying Queue tables, you must grant the correct permissions to the `pgmq_public` database functions for each Data API role. The permissions required for each Queue API database function: | **Operations** | **Permissions Required** | | ------------------- | ------------------------ | | `send` `send_batch` | `Select` `Insert` | | `read` `pop` | `Select` `Update` | | `archive` `delete` | `Select` `Delete` | To manage your queue permissions, click on the Queue Settings cog button on [the overview page of any Queue in the Dashboard](/dashboard/project/_/integrations/queues/queues). Screenshot highlighting the Queue Settings button on the Queues overview page in the Supabase Dashboard Then enable the required roles permissions. | ROLE | Select | Insert | Update | Delete | | ------------- | ------- | ------- | ------- | ------- | | anon | | | | | | authenticated | enabled | enabled | enabled | enabled | | postgres | enabled | enabled | enabled | enabled | | service_role | enabled | enabled | enabled | enabled | You should never expose `postgres` and `service_role` roles client-side. ### Enqueueing and dequeueing messages Once you have created your Queue, you can begin enqueueing and dequeueing Messages. ```tsx import { createClient } from '@supabase/supabase-js' const supabaseUrl = 'supabaseURL' const supabaseKey = 'supabaseKey' const supabase = createClient(supabaseUrl, supabaseKey) const QueuesTest: React.FC = () => { //Add a Message const sendToQueue = async () => { const result = await supabase.schema('pgmq_public').rpc('send', { queue_name: 'foo', message: { hello: 'world' }, sleep_seconds: 30, }) console.log(result) } //Dequeue Message const popFromQueue = async () => { const result = await supabase.schema('pgmq_public').rpc('pop', { queue_name: 'foo' }) console.log(result) } return (

Queue Test Component

) } export default QueuesTest ```
<$Show if="sdk:dart"> ```dart import 'package:supabase_flutter/supabase_flutter.dart'; final supabase = Supabase.instance.client; // Add a Message Future sendToQueue() async { final result = await supabase.schema('pgmq_public').rpc('send', params: { 'queue_name': 'foo', 'message': {'hello': 'world'}, 'sleep_seconds': 30, }); print(result); } // Dequeue Message Future popFromQueue() async { final result = await supabase.schema('pgmq_public').rpc('pop', params: { 'queue_name': 'foo', }); print(result); } ``` <$Show if="sdk:swift"> ```swift import Supabase let supabase = SupabaseClient( supabaseURL: URL(string: "supabaseURL")!, supabaseKey: "supabaseKey" ) // Add a Message func sendToQueue() async throws { let result = try await supabase .schema("pgmq_public") .rpc("send", params: [ "queue_name": AnyJSON.string("foo"), "message": AnyJSON.object(["hello": "world"]), "sleep_seconds": AnyJSON.integer(30) ]) .execute() print(result) } // Dequeue Message func popFromQueue() async throws { let result = try await supabase .schema("pgmq_public") .rpc("pop", params: ["queue_name": "foo"]) .execute() print(result) } ``` <$Show if="sdk:python"> ```python from supabase import create_client, Client supabase_url = "supabaseURL" supabase_key = "supabaseKey" supabase: Client = create_client(supabase_url, supabase_key) # Add a Message def send_to_queue(): result = supabase.schema("pgmq_public").rpc( "send", { "queue_name": "foo", "message": {"hello": "world"}, "sleep_seconds": 30, } ).execute() print(result) # Dequeue Message def pop_from_queue(): result = supabase.schema("pgmq_public").rpc( "pop", {"queue_name": "foo"} ).execute() print(result) ```