Update data
Patch rows that match the chained filters.
Patch existing rows via PATCH. Pass a Hash of column-value updates, chain at least one filter to scope which rows are touched, then call .execute. Updates with no filter are rejected by PostgREST unless you've used max_affected to opt in explicitly.
Signature
supabase.from(table).update(json, count: nil, returning: "representation")Parameters
| Name | Type | Required | Description |
|---|---|---|---|
json | Hash | Required | Map of column → new value. Columns omitted from the Hash are left alone. Nested JSONB values can be patched by passing the whole new JSON object — partial JSONB merges are not supported by PostgREST. |
count | String | Optional | One of "exact", "planned", "estimated". Adds Prefer: count=... so APIResponse#count is populated from the Content-Range header. |
returning | String | Optional | "representation" (default) returns the updated rows; "minimal" returns no body, which is faster for fire-and-forget writes. |
Returns
A chainable builder that mixes in FilterMixin — chain filters to scope the update, then call .execute to fire the request and receive an APIResponse.
Example — update a single row by primary key
response = supabase
.from("countries")
.update(name: "Türkiye")
.eq("id", 99)
.execute
response.data # => [{ "id" => 99, "name" => "Türkiye", ... }]Example — bulk update with a compound filter
response = supabase
.from("orders")
.update(status: "shipped", shipped_at: Time.now.utc.iso8601)
.eq("status", "ready_to_ship")
.lte("created_at", "2026-06-01")
.execute
response.data.length # => however many rows matchedExample — fire-and-forget update
returning: "minimal" returns no body, so data is []. Use this when you don't need the updated rows back.
supabase
.from("audit_log")
.update(seen: true, returning: "minimal")
.eq("user_id", 42)
.executeExample — count the affected rows
response = supabase
.from("orders")
.update({ archived: true }, count: "exact")
.eq("status", "completed")
.execute
response.count # => N rows updatedExample — guard a bulk update with max_affected
max_affected(N) adds Prefer: handling=strict,max-affected=N. PostgREST refuses the update (returning 400) if the row count would exceed N. This is the safe way to issue an unfiltered-looking update.
supabase
.from("invoices")
.update(due_at: nil)
.eq("status", "voided")
.max_affected(50)
.executeUpdates with no filters do NOT silently update every row — PostgREST refuses the request unless max_affected has explicitly opted in.