Skip to main content

Overview

GraphQL mutations allow you to create, update, and delete data in your Supabase database. All mutations respect Row Level Security policies.
GraphQL mutations are currently in beta. The API is functional but may receive updates.

Insert Data

Insert Single Row

Insert a single row into a table:
mutation {
  insertIntoCountriesCollection(
    objects: [{
      name: "Denmark",
      code: "DK",
      capital: "Copenhagen"
    }]
  ) {
    records {
      id
      name
      code
      capital
    }
  }
}

Response

{
  "data": {
    "insertIntoCountriesCollection": {
      "records": [
        {
          "id": 42,
          "name": "Denmark",
          "code": "DK",
          "capital": "Copenhagen"
        }
      ]
    }
  }
}
records
array
Array of inserted records.

Insert Multiple Rows

Insert multiple rows at once:
mutation {
  insertIntoCountriesCollection(
    objects: [
      { name: "Denmark", code: "DK", capital: "Copenhagen" },
      { name: "Norway", code: "NO", capital: "Oslo" },
      { name: "Sweden", code: "SE", capital: "Stockholm" }
    ]
  ) {
    records {
      id
      name
      code
    }
    affectedCount
  }
}
affectedCount
integer
Number of rows inserted.

Insert with Variables

Use variables for dynamic inserts:
mutation InsertCountry(
  $name: String!,
  $code: String!,
  $capital: String
) {
  insertIntoCountriesCollection(
    objects: [{
      name: $name,
      code: $code,
      capital: $capital
    }]
  ) {
    records {
      id
      name
    }
  }
}
Variables:
{
  "name": "Finland",
  "code": "FI",
  "capital": "Helsinki"
}

Update Data

Update Rows

Update rows matching a filter:
mutation {
  updateCountriesCollection(
    filter: { code: { eq: "US" } },
    set: { name: "United States of America" }
  ) {
    records {
      id
      name
      code
    }
    affectedCount
  }
}
filter
object
required
Filter to select rows to update.
set
object
required
Fields to update with new values.

Update Multiple Fields

mutation {
  updateCountriesCollection(
    filter: { id: { eq: 1 } },
    set: {
      name: "United States of America",
      capital: "Washington, D.C.",
      population: 331000000
    }
  ) {
    records {
      id
      name
      capital
      population
    }
  }
}

Update with Variables

mutation UpdateCountry(
  $id: BigInt!,
  $name: String!
) {
  updateCountriesCollection(
    filter: { id: { eq: $id } },
    set: { name: $name }
  ) {
    records {
      id
      name
    }
  }
}
Variables:
{
  "id": 1,
  "name": "USA"
}

Update Multiple Rows

mutation {
  updateCountriesCollection(
    filter: { population: { lt: 1000000 } },
    set: { category: "small" }
  ) {
    affectedCount
  }
}

Delete Data

Delete Rows

Delete rows matching a filter:
mutation {
  deleteFromCountriesCollection(
    filter: { id: { eq: 1 } }
  ) {
    records {
      id
      name
    }
    affectedCount
  }
}
filter
object
required
Filter to select rows to delete.
Always include a filter when deleting to avoid removing all rows.

Delete with Variables

mutation DeleteCountry($id: BigInt!) {
  deleteFromCountriesCollection(
    filter: { id: { eq: $id } }
  ) {
    records {
      id
      name
    }
  }
}
Variables:
{
  "id": 1
}

Delete Multiple Rows

mutation {
  deleteFromCountriesCollection(
    filter: {
      code: { in: ["XX", "YY", "ZZ"] }
    }
  ) {
    affectedCount
  }
}

Upsert Data

Insert or update based on conflict:
mutation {
  insertIntoCountriesCollection(
    objects: [{
      id: 1,
      name: "United States of America",
      code: "US"
    }],
    onConflict: {
      constraint: "countries_pkey",
      update: ["name"]
    }
  ) {
    records {
      id
      name
      code
    }
  }
}
onConflict
object
Conflict resolution strategy.

Batching Mutations

Execute multiple mutations in a single request:
mutation BatchOperations {
  insertCountry: insertIntoCountriesCollection(
    objects: [{ name: "Denmark", code: "DK" }]
  ) {
    affectedCount
  }
  
  updateCountry: updateCountriesCollection(
    filter: { code: { eq: "US" } },
    set: { name: "USA" }
  ) {
    affectedCount
  }
  
  deleteCountry: deleteFromCountriesCollection(
    filter: { code: { eq: "XX" } }
  ) {
    affectedCount
  }
}

Relationships

Insert a country with cities:
mutation {
  insertIntoCountriesCollection(
    objects: [{
      name: "Denmark",
      code: "DK",
      cities: {
        create: [
          { name: "Copenhagen", population: 794128 },
          { name: "Aarhus", population: 285273 }
        ]
      }
    }]
  ) {
    records {
      id
      name
      citiesCollection {
        edges {
          node {
            name
            population
          }
        }
      }
    }
  }
}

Error Handling

Validation Errors

Handle validation errors in the response:
{
  "errors": [
    {
      "message": "null value in column \"name\" violates not-null constraint",
      "locations": [{ "line": 2, "column": 3 }],
      "path": ["insertIntoCountriesCollection"]
    }
  ]
}

Constraint Violations

{
  "errors": [
    {
      "message": "duplicate key value violates unique constraint \"countries_code_key\"",
      "locations": [{ "line": 2, "column": 3 }],
      "path": ["insertIntoCountriesCollection"]
    }
  ]
}

Transactions

All mutations in a single GraphQL request are executed in a transaction:
mutation TransferBalance(
  $senderId: UUID!,
  $receiverId: UUID!,
  $amount: Numeric!
) {
  debit: updateAccountsCollection(
    filter: { id: { eq: $senderId } },
    set: { balance: { decrement: $amount } }
  ) {
    affectedCount
  }
  
  credit: updateAccountsCollection(
    filter: { id: { eq: $receiverId } },
    set: { balance: { increment: $amount } }
  ) {
    affectedCount
  }
}
If any mutation in the request fails, all mutations are rolled back.

Optimistic Updates

Return updated data immediately:
mutation UpdateCountryPopulation(
  $id: BigInt!,
  $population: BigInt!
) {
  updateCountriesCollection(
    filter: { id: { eq: $id } },
    set: { population: $population }
  ) {
    records {
      id
      name
      population
      updatedAt
    }
  }
}

Row Level Security

Mutations respect RLS policies:
-- Users can only update their own data
CREATE POLICY "Users can update own data"
  ON countries
  FOR UPDATE
  USING (auth.uid() = user_id)
  WITH CHECK (auth.uid() = user_id);

Best Practices

Prevent accidental bulk operations by always including specific filters:
filter: { id: { eq: $id } }
Never interpolate values into mutation strings - use variables:
mutation UpdateUser($id: UUID!, $name: String!) { ... }
Always request the updated fields to confirm changes:
records { id name updatedAt }
Check for errors in the response and handle them appropriately.

Next Steps

Queries

Learn about querying data

Client Libraries

Use GraphQL with client SDKs