supabase-rb-rb
Database

Delete data

Delete rows that match the chained filters.

Delete rows via DELETE. Chain at least one filter to scope which rows are removed, then call .execute. PostgREST refuses an unfiltered DELETE unless you opt in explicitly via max_affected.

Signature

supabase.from(table).delete(count: nil, returning: "representation")

delete takes no positional argument — the rows-to-delete are determined entirely by the filters you chain after it.

Parameters

NameTypeRequiredDescription
countStringOptionalOne of "exact", "planned", "estimated". Adds Prefer: count=... so APIResponse#count is populated from the Content-Range header.
returningStringOptional"representation" (default) returns the deleted rows; "minimal" returns no body, which is faster for fire-and-forget deletes.

Returns

Returns
Supabase::Postgrest::FilterRequestBuilder

A chainable builder that mixes in FilterMixin — chain filters to scope the delete, then call .execute to fire the request and receive an APIResponse.

Example — delete one row by primary key

response = supabase
  .from("countries")
  .delete
  .eq("id", 250)
  .execute

response.data  # => [{ "id" => 250, "name" => "Wakanda", ... }]

Example — bulk delete with a compound filter

response = supabase
  .from("sessions")
  .delete
  .lte("expires_at", Time.now.utc.iso8601)
  .eq("revoked", false)
  .execute

response.data.length  # => however many rows were deleted

Example — fire-and-forget delete

returning: "minimal" returns no body, so data is []. Use this when you don't need the deleted rows back.

supabase
  .from("audit_log")
  .delete(returning: "minimal")
  .lt("created_at", "2025-01-01")
  .execute

Example — count what was deleted

response = supabase
  .from("sessions")
  .delete(count: "exact")
  .lte("expires_at", Time.now.utc.iso8601)
  .execute

response.count  # => N rows deleted

Example — guard a wide delete with max_affected

max_affected(N) adds Prefer: handling=strict,max-affected=N. PostgREST refuses the delete (returning 400) if the row count would exceed N. Use this any time the filter could match more rows than you intend to remove.

supabase
  .from("login_attempts")
  .delete
  .eq("ip", "203.0.113.7")
  .max_affected(1_000)
  .execute

Example — delete with in_ (multiple primary keys)

supabase
  .from("countries")
  .delete
  .in_("id", [250, 251, 252])
  .execute

PostgREST refuses unfiltered deletes (no eq/in_/etc. on the chain) unless max_affected is set.

On this page