8

Mins

Supabase Cascade: Mastering Relational Data Deletion

Managing relational data in Supabase isn’t just about inserting rows—it’s also about deleting them intelligently. In this post, you'll learn how to implement cascade deletes using PostgreSQL's CASCADE clause within Supabase tables.

supabase-on-delete-cascade

CONTENT

Key Takeaways

  • Supabase supports PostgreSQL’s ON DELETE rules to manage relational data consistency.

  • Options include CASCADE, RESTRICT, SET NULL, SET DEFAULT, NO ACTION, and deferred NO ACTION.

  • Each rule fits different needs: auto-cleanup, strict integrity, fallback references, or complex workflows.

What is Supabase?

In a world increasingly driven by data, developers seek platforms that are powerful, scalable, and developer-friendly. Supabase is an open-source backend-as-a-service (BaaS) built on top of PostgreSQL, aiming to provide a Firebase alternative. It gives you instant APIs, authentication, real-time subscriptions, and more — all by just connecting to your PostgreSQL database.

Think of it as "PostgreSQL with batteries included." Supabase empowers teams to build full-stack applications faster, with less friction and better performance, thanks to the robust SQL database and modern tooling.

How Do We Delete Table Data in Supabase?

Deleting data in Supabase (or PostgreSQL, more broadly) is as simple as executing a SQL command or using Supabase's client libraries (like supabase-js).

Example via SQL:

DELETE FROM bookings WHERE id = 101
DELETE FROM bookings WHERE id = 101
DELETE FROM bookings WHERE id = 101

Example via Supabase JS:

This works fine when the table is standalone or has no dependencies. However, when the data is related to other tables — say, bookings linked to users or properties — deleting a row can have unintended consequences. That’s where ON DELETE rules come in.

How to Delete Data With Relationships?

Let’s say you have a basic real estate booking system with the following tables:

Table Schema Definition

Table

Columns

Notes


users

id, name

Primary table for users (hosts & guests)


properties

id, title, host_id (FK to users.id)

Each property is hosted by a user


bookings

id, property_id (FK to properties.id), guest_id (FK to users.id)

Each booking links a guest and property


ERD (Entity Relationship Diagram)

Example Modal Table With Mock Data

Users

id

name

1

Alice Host

2

Bob Guest

3

Charlie Guest

Properties

id

title

host_id

10

Ocean-view Condo

1

11

Mountain Retreat

1

Bookings

id

property_id

guest_id

100

10

2

101

11

3

To delete data safely and consistently, especially in a relational schema like this, it's essential to define ON DELETE rules on foreign key constraints.

This leads us to the concept of Cascade behaviour in Supabase/PostgreSQL.

Exploring Cascade

Let’s dive into the types of ON DELETE rules and their real-world implications.

CASCADE

Definition: When a row in the parent table is deleted, all matching rows in the child table are automatically deleted.

Example Scenario:

A host deletes their account. All their properties and the bookings related to those properties should also be deleted to maintain consistency.

Schema:

ALTER TABLE properties
ADD CONSTRAINT fk_host
FOREIGN KEY (host_id)
REFERENCES users(id)
ON DELETE CASCADE

ALTER TABLE properties
ADD CONSTRAINT fk_host
FOREIGN KEY (host_id)
REFERENCES users(id)
ON DELETE CASCADE

ALTER TABLE properties
ADD CONSTRAINT fk_host
FOREIGN KEY (host_id)
REFERENCES users(id)
ON DELETE CASCADE

Outcome:

  • Delete user → their properties get deleted.

  • Properties deleted → bookings referencing them also get deleted.

Use With Caution: Can remove a large amount of data unintentionally.

RESTRICT

Definition: Prevents deletion of a row if it is referenced by any row in another table.

Example Scenario:

A guest has active bookings. Their account should not be deletable to avoid broken records.

Schema:

ALTER TABLE bookings
ADD CONSTRAINT fk_guest
FOREIGN KEY (guest_id)
REFERENCES users(id)
ON DELETE RESTRICT

ALTER TABLE bookings
ADD CONSTRAINT fk_guest
FOREIGN KEY (guest_id)
REFERENCES users(id)
ON DELETE RESTRICT

ALTER TABLE bookings
ADD CONSTRAINT fk_guest
FOREIGN KEY (guest_id)
REFERENCES users(id)
ON DELETE RESTRICT

Outcome:

Trying to delete a guest with bookings results in an error.

Best For: Critical referential enforcement.

SET NULL

Definition: When a parent row is deleted, the referencing foreign key in the child table is set to NULL.

Example Scenario:

A host deletes their account, but you want to keep their property listings. The host reference becomes NULL.

Schema:

ALTER TABLE properties
ADD CONSTRAINT fk_host
FOREIGN KEY (host_id)
REFERENCES users(id)
ON DELETE SET NULL

ALTER TABLE properties
ADD CONSTRAINT fk_host
FOREIGN KEY (host_id)
REFERENCES users(id)
ON DELETE SET NULL

ALTER TABLE properties
ADD CONSTRAINT fk_host
FOREIGN KEY (host_id)
REFERENCES users(id)
ON DELETE SET NULL

Outcome:

  • User deleted → host_id becomes NULL in properties

Note: Ensure host_id column allows NULL values.

SET DEFAULT

Definition: When the parent is deleted, the child’s foreign key is set to a default value.

Example Scenario:

Have a placeholder user (e.g. ID 999) representing "Deleted User". Use this as fallback reference.

Schema:

ALTER TABLE properties
ALTER COLUMN host_id SET DEFAULT 999;

ALTER TABLE properties
ADD CONSTRAINT fk_host
FOREIGN KEY (host_id)
REFERENCES users(id)
ON DELETE SET DEFAULT

ALTER TABLE properties
ALTER COLUMN host_id SET DEFAULT 999;

ALTER TABLE properties
ADD CONSTRAINT fk_host
FOREIGN KEY (host_id)
REFERENCES users(id)
ON DELETE SET DEFAULT

ALTER TABLE properties
ALTER COLUMN host_id SET DEFAULT 999;

ALTER TABLE properties
ADD CONSTRAINT fk_host
FOREIGN KEY (host_id)
REFERENCES users(id)
ON DELETE SET DEFAULT

Outcome:

  • User deleted → host_id becomes 999

Important: The default value must exist in the referenced table.

NO ACTION

Definition: Prevents deletion if referenced rows exist, but checks after the current transaction.

Example Scenario:

You're deleting multiple things — a user and their properties — within the same transaction. NO ACTION allows all deletes to happen before throwing errors.

Schema:

ALTER TABLE bookings
ADD CONSTRAINT fk_property
FOREIGN KEY (property_id)
REFERENCES properties(id)
ON DELETE NO ACTION

ALTER TABLE bookings
ADD CONSTRAINT fk_property
FOREIGN KEY (property_id)
REFERENCES properties(id)
ON DELETE NO ACTION

ALTER TABLE bookings
ADD CONSTRAINT fk_property
FOREIGN KEY (property_id)
REFERENCES properties(id)
ON DELETE NO ACTION

Outcome:

  • Errors only if references still exist after transaction is complete.

Useful For: Complex transaction workflows.

NO ACTION INITIALLY DEFERRED

Definition: A deferred form of NO ACTION where the foreign key constraint is checked at the end of the transaction, not immediately.

Example Scenario:

You're removing a user, their properties, and bookings in one transaction. Deferred checking allows full deletion sequencing.

Schema:

ALTER TABLE bookings
ADD CONSTRAINT fk_property
FOREIGN KEY (property_id)
REFERENCES properties(id)
ON DELETE NO ACTION
DEFERRABLE INITIALLY DEFERRED

ALTER TABLE bookings
ADD CONSTRAINT fk_property
FOREIGN KEY (property_id)
REFERENCES properties(id)
ON DELETE NO ACTION
DEFERRABLE INITIALLY DEFERRED

ALTER TABLE bookings
ADD CONSTRAINT fk_property
FOREIGN KEY (property_id)
REFERENCES properties(id)
ON DELETE NO ACTION
DEFERRABLE INITIALLY DEFERRED

Outcome:

  • Constraint is only evaluated at COMMIT time.

Use When: You need advanced multi-step deletions.

Summary Table

Constraint Type

Behavior

Best Use Case

CASCADE

Deletes child rows automatically

Auto-cleanup of related data

RESTRICT

Prevents delete if child rows exist

Enforcing strict data integrity

SET NULL

Nullifies foreign key in child rows

Preserve data but remove relationships

SET DEFAULT

Replaces FK with default value

Use a fallback entity for traceability

NO ACTION

Delays delete check to transaction end

Multi-delete scenarios

NO ACTION INITIALLY DEFERRED

Same as NO ACTION but deferred to commit

Advanced workflows with deferred constraint checking

Common Errors and Debugging CASCADE Issues in Supabase

Using ON DELETE CASCADE in Supabase (PostgreSQL) is powerful — but when something breaks, it’s rarely obvious why.

Here are the most common issues teams run into, and how to debug them.

1. Cascade not working as expected

What happens:
You delete a parent record, but related rows don’t get deleted.

Common causes:

  • Foreign key constraint not set with ON DELETE CASCADE

  • Constraint added incorrectly or after data was inserted

  • Wrong column referenced in the relationship

How to fix:

  • Check your foreign key definition in the Supabase dashboard or SQL editor

  • Ensure it explicitly includes ON DELETE CASCADE

  • Recreate the constraint if needed

2. Existing data not cascading

What happens:
New records cascade correctly, but older data doesn’t behave the same way.

Why this happens:

  • The constraint was added after the data already existed

  • Existing rows may violate the constraint rules

Fix:

  • Clean or backfill inconsistent data

  • Reapply constraints properly

3. Accidental mass deletion

What happens:
Deleting one record removes way more data than expected.

Why this happens:

  • Multiple tables are chained with cascade relationships

  • One delete triggers a full cascade chain

How to avoid it:

  • Always map relationships before enabling cascade

  • Test deletes in a staging environment

  • Use soft deletes (is_deleted) if needed

4. Row-Level Security (RLS) conflicts

What happens:
Delete operation fails or behaves inconsistently.

Why this happens:

  • RLS policies block cascading deletes

  • Permissions are not properly configured

Fix:

  • Ensure delete policies allow the operation

  • Check if cascading actions respect user roles

5. Foreign key constraint errors

Error example:

“update or delete on table violates foreign key constraint”

Why this happens:

  • ON DELETE CASCADE is not enabled

  • Default behavior (RESTRICT) is blocking deletion

Fix:

  • Update constraint to include cascade

  • Or manually delete dependent rows before deleting parent

6. Debugging tips that save time

Instead of guessing, follow a simple checklist:

  • Inspect foreign key constraints in SQL

  • Check relationship chains between tables

  • Verify RLS policies

  • Test deletes on sample data

  • Use logs or Supabase dashboard queries 

Final Thoughts

Understanding ON DELETE actions is essential when building a robust Supabase (or PostgreSQL) application. Whether you're building a booking platform, a blog, or a social app data integrity is key. Use cascading rules thoughtfully based on your application's needs.

Further Reading:

Stay tuned for more in-depth Supabase guides!

Frequently asked questions

Frequently asked questions

Q1. What is Supabase and how is it different from Firebase?

Supabase is an open-source backend-as-a-service built on PostgreSQL, while Firebase is a proprietary NoSQL-based platform by Google. Supabase gives you full SQL power, relational data modeling, and more control over your backend compared to Firebase’s document-based approach.

Q2. When should I use ON DELETE CASCADE in Supabase?

You should use ON DELETE CASCADE when related data should automatically be cleaned up to avoid orphan records. It works best for tightly coupled data like users → posts → comments, where removing the parent logically requires removing all dependent data.

Q3. Why is my ON DELETE CASCADE not working?

This usually happens when the foreign key constraint was not defined with ON DELETE CASCADE, or it was added after existing data was inserted. Always verify the constraint definition and ensure relationships are correctly configured.

Q4. What is the safest ON DELETE option to use?

RESTRICT is generally the safest because it prevents accidental deletions by blocking the operation if related data exists. It’s ideal when maintaining strict data integrity is more important than convenience.

Q5. Can ON DELETE CASCADE cause data loss?

Yes and that’s the scary part. If multiple tables are chained with cascade rules, deleting one parent row can trigger a large chain of deletions. Always test in staging before applying cascade rules in production.

Q6. What is the difference between SET NULL and SET DEFAULT?

SET NULL removes the relationship by setting the foreign key to null, while SET DEFAULT replaces it with a predefined value (like a fallback user). Use SET NULL when relationships are optional, and SET DEFAULT when you want traceability.

Q7. How does Row-Level Security (RLS) affect deletes in Supabase?

Supabase enforces Row-Level Security policies during delete operations, including cascades. If your policies don’t allow deletion, even a valid cascade operation can fail — so permissions must be configured correctly.

SHARE