Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1871,7 +1871,7 @@ export const realtime: NavMenuConstant = {
name: 'Deep dive',
url: undefined,
items: [
{ name: 'Quotas', url: '/guides/realtime/quotas', enabled: billingEnabled },
{ name: 'Limits', url: '/guides/realtime/limits', enabled: billingEnabled },
{
name: 'Pricing',
url: '/guides/realtime/pricing' as `/${string}`,
Expand Down
4 changes: 3 additions & 1 deletion apps/docs/content/guides/ai/langchain.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ Prepare you database with the relevant tables:

```sql
-- Enable the pgvector extension to work with embedding vectors
create extension vector;
create extension vector
with
schema extensions;

-- Create a table to store your documents
create table documents (
Expand Down
9 changes: 5 additions & 4 deletions apps/docs/content/guides/auth/auth-email-templates.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,9 @@ const { data, error } = await supabase.auth.verifyOtp({ email, token, type: 'ema
- Create your own custom email link to redirect the user to a page where they can click on a button to confirm the action

```html
<a href="{{ .SiteURL }}/confirm-signup?confirmation_url={{ .ConfirmationURL }}"
>Confirm your signup</a
>
<a href="{{ .SiteURL }}/confirm-signup?confirmation_url={{ .ConfirmationURL }}">
Confirm your signup
</a>
```

- The button should contain the actual confirmation link which can be obtained from parsing the `confirmation_url={{ .ConfirmationURL }}` query parameter in the URL.
Expand All @@ -156,7 +156,8 @@ You can customize the email link in the email template to redirect the user to a
```html
<a
href="https://api.example.com/v1/authenticate?token_hash={{ .TokenHash }}&type=invite&redirect_to={{ .RedirectTo }}"
>Accept the invite
>
Accept the invite
</a>
```

Expand Down
6 changes: 5 additions & 1 deletion apps/docs/content/guides/database/extensions/pgjwt.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ title: 'pgjwt: JSON Web Tokens'
description: 'Encode and decode JWTs in PostgreSQL'
---

{/* supa-mdx-lint-disable-next-line Rule004ExcludeWords */}
<Admonition type="note">

Supabase creates and handles JWT for you. It is built into the platform. **If you use Postgres version 15 or earlier**, you don't need the pgjwt extension, and it is safe to disable. For more information on how Supabase handles JWTs, read the [Supabase and JWTs documentation](/docs/guides/auth/jwts#supabase-and-jwts)

</Admonition>

<Admonition type="deprecation">

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,5 @@ This prevents the policy `( (select auth.uid()) = user_id )` from running for an
## More resources

- [Testing your database](/docs/guides/database/testing)
- [Row Level Security and Supabase Auth](/docs/guides/database/postgres/row-level-security)
- [RLS Guide and Best Practices](https://github.com/orgs/supabase/discussions/14576)
- Community repo on testing RLS using [pgTAP and dbdev](https://github.com/usebasejump/supabase-test-helpers/tree/main)
6 changes: 3 additions & 3 deletions apps/docs/content/guides/deployment/going-into-prod.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,10 @@ After developing your project and deciding it's production ready, you should run
| Create or Verify an MFA challenge | `/auth/v1/factors/:id/challenge` `/auth/v1/factors/:id/verify` | IP Address | 15 requests per minute (with bursts up to 30 requests) |
| Anonymous sign-ins | `/auth/v1/signup`[^2] | IP Address | 30 requests per hour (with bursts up to 30 requests) |

### Realtime quotas
### Realtime limits

- Review the [Realtime quotas](/docs/guides/realtime/quotas).
- If you need quotas increased you can always [contact support](/dashboard/support/new).
- Review the [Realtime limits](/docs/guides/realtime/limits).
- If you need limits increased you can always [contact support](/dashboard/support/new).

### Abuse prevention

Expand Down
8 changes: 4 additions & 4 deletions apps/docs/content/guides/realtime/getting_started.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ let channel = supabase.channel("room:lobby:messages") {

```python
# Create a channel with a descriptive topic name
channel = supabase.channel('room:lobby:messages', params={config={private= True }})
channel = supabase.channel('room:lobby:messages', params={'config': {'private': True }})
```

</TabPanel>
Expand Down Expand Up @@ -501,14 +501,14 @@ BEGIN
-- Send custom notification when new message is created
IF TG_OP = 'INSERT' THEN
PERFORM realtime.send(
'room:' || NEW.room_id::text || ':notifications',
'message_created',
jsonb_build_object(
'message_id', NEW.id,
'user_id', NEW.user_id,
'room_id', NEW.room_id,
'created_at', NEW.created_at
),
'message_created',
'room:' || NEW.room_id::text || ':notifications',
true -- private channel
);
END IF;
Expand Down Expand Up @@ -688,7 +688,7 @@ Now that you understand the basics, dive deeper into each feature:

- **[Architecture](/docs/guides/realtime/architecture)** - Understand how Realtime works under the hood
- **[Benchmarks](/docs/guides/realtime/benchmarks)** - Performance characteristics and scaling considerations
- **[Quotas](/docs/guides/realtime/quotas)** - Usage limits and best practices
- **[Limits](/docs/guides/realtime/limits)** - Usage limits and best practices

### Integration guides

Expand Down
63 changes: 63 additions & 0 deletions apps/docs/content/guides/realtime/limits.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
---
id: 'limits'
title: 'Realtime Limits'
description: 'Understanding Realtime limits'
sidebar_label: 'Limits'
---

Our cluster supports millions of concurrent connections and message throughput for production workloads.

<Admonition type="note">

Upgrade your plan to increase your limits. Without a spend cap, or on an Enterprise plan, some limits are still in place to protect budgets. All limits are configurable per project. [Contact support](/dashboard/support/new) if you need your limits increased.

</Admonition>

## Limits by plan

| | Free | Pro | Pro (no spend cap) | Team | Enterprise |
| ----------------------------------------------------------------------------------- | -------- | -------- | ------------------ | -------- | ---------- |
| **Concurrent connections** | 200 | 500 | 10,000 | 10,000 | 10,000+ |
| **Messages per second** | 100 | 500 | 2,500 | 2,500 | 2,500+ |
| **Channel joins per second** | 100 | 500 | 2,500 | 2,500 | 2,500+ |
| **Channels per connection** | 100 | 100 | 100 | 100 | 100+ |
| **Presence keys per object** | 10 | 10 | 10 | 10 | 10+ |
| **Presence messages per second** | 20 | 50 | 1,000 | 1,000 | 1,000+ |
| **Broadcast payload size** | 256 KB | 3,000 KB | 3,000 KB | 3,000 KB | 3,000+ KB |
| **Postgres change payload size ([**read more**](#postgres-changes-payload-limit))** | 1,024 KB | 1,024 KB | 1,024 KB | 1,024 KB | 1,024+ KB |

Beyond the Free and Pro Plan you can customize your limits by [contacting support](/dashboard/support/new).

## Limit errors

When you exceed a limit, errors will appear in the backend logs and client-side messages in the WebSocket connection.

- **Logs**: check the [Realtime logs](/dashboard/project/_/database/realtime-logs) inside your project Dashboard.
- **WebSocket errors**: Use your browser's developer tools to find the WebSocket initiation request and view individual messages.

<Admonition type="tip" label="Realtime Inspector">

You can use the [Realtime Inspector](https://realtime.supabase.com/inspector/new) to reproduce an error and share those connection details with Supabase support.

</Admonition>
Some limits can cause a Channel join to be refused. Realtime will reply with one of the following WebSocket messages:

### `too_many_channels`

Too many channels currently joined for a single connection.

### `too_many_connections`

Too many total concurrent connections for a project.

### `too_many_joins`

Too many Channel joins per second.

### `tenant_events`

Connections will be disconnected if your project is generating too many messages per second. `supabase-js` will reconnect automatically when the message throughput decreases below your plan limit. An `event` is a WebSocket message delivered to, or sent from a client.

## Postgres changes payload limit

When this limit is reached, the `new` and `old` record payloads only include the fields with a value size of less than or equal to 64 bytes.
63 changes: 0 additions & 63 deletions apps/docs/content/guides/realtime/quotas.mdx

This file was deleted.

2 changes: 1 addition & 1 deletion apps/docs/content/guides/storage/vector/limits.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: 'Vector Bucket Limits'
subtitle: 'Understanding capacity, quotas, and billing for vector buckets.'
subtitle: 'Understanding capacity, limits, and billing for vector buckets.'
---

<Admonition type="caution" title="This feature is in alpha">
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/content/troubleshooting/exhaust-disk-io.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ database_id = "4844905d-1456-44a1-858e-7a4995e5054c"

Disk IO refers to two metrics: throughput in Megabits per Second and IOPS which are Input/Output Operations per Second. Depending on the compute add-on of your instance you will have [different baseline performances](/docs/guides/platform/compute-add-ons#compute-size).

Smaller compute instances can burst and exceed their baseline performance for a short quota of time every day. This is represented as your Disk IO Budget and once your Disk IO Budget is consumed, your instance reverts back to its baseline performance. Learn more about [choosing the right compute instance for consistent disk performance](/docs/guides/platform/compute-add-ons#choosing-the-right-compute-instance-for-consistent-disk-performance).
Smaller compute instances can burst and exceed their baseline performance for a short period of time every day. This is represented as your Disk IO Budget and once your Disk IO Budget is consumed, your instance reverts back to its baseline performance. Learn more about [choosing the right compute instance for consistent disk performance](/docs/guides/platform/compute-add-ons#choosing-the-right-compute-instance-for-consistent-disk-performance).

## Depleting your disk IO budget

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ For example, if you have a chat application that uses Supabase Realtime and you

This quota applies to all Supabase projects, including self-hosted projects, but you can increase it depending on your use case. For hosted Supabase projects, select the plan that fits your Realtime usage and reach out if you need custom quotas. For those self-hosting Supabase, you can set those limits yourself by setting the `max_concurrent_users` field on the tenant record (see: https://supabase.com/docs/guides/self-hosting/realtime/config).

You can learn more about Realtime quotas here: https://supabase.com/docs/guides/realtime/quotas#quotas-by-plan
You can learn more about Realtime limits here: https://supabase.com/docs/guides/realtime/limits#limits-by-plan
1 change: 1 addition & 0 deletions apps/docs/public/humans.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Chris Gwilliams
Chris Martin
Chris Stockton
Chris Ward
Clayton Kast
Craig Cannon
Cuong Do
Danny White
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ export const AuthProvidersForm = () => {
isActive = authConfig && (authConfig as any)['EXTERNAL_WEB3_SOLANA_ENABLED']
} else if (providerSchema.title.includes('X / Twitter (OAuth 2.0)')) {
isActive = authConfig && (authConfig as any)['EXTERNAL_X_ENABLED']
} else if (providerSchema.title === 'Twitter (Deprecated)') {
isActive = authConfig && (authConfig as any)['EXTERNAL_TWITTER_ENABLED']
} else {
isActive =
authConfig &&
Expand Down
Loading
Loading