Skip to main content

Documentation Index

Fetch the complete documentation index at: https://archie.com/docs/llms.txt

Use this file to discover all available pages before exploring further.

Mutations write data through the GraphQL API. Every table in the Data Model generates a fixed set of mutations automatically — you don’t write resolvers or input types by hand. The examples assume a students table with fields like firstName, lastName, email, age, and a city relationship.

Auto-generated mutations per table

For each table, Archie generates:
MutationWhat it does
create<TableName>Insert a single record.
create<TableName>ManyInsert multiple records in one request.
update<TableName>Update a single record by id.
delete<TableName>Delete a single record by id.
delete<TableName>ManyDelete multiple records by id.
upsert<TableName>Insert or update by a unique field — atomic. Generated for tables with at least one unique column.
GraphQL mutations overview in API Explorer

Single record mutations

Create

mutation {
  createStudents(
    input: {
      firstName: "John"
      lastName: "Doe"
      email: "john.doe@example.com"
      age: 24
      city: "2900562f-d036-486d-be98-9ebf064c27fe"
    }
  ) {
    id
    firstName
    email
    city {
      id
      nameCity
    }
  }
}
The input object’s shape comes directly from the table’s schema. Mandatory fields without a default must be present; optional fields can be omitted.

Update

mutation {
  updateStudents(
    id: "2685ec12-a4c7-491d-a155-d0b09190993b"
    input: { age: 23 }
  ) {
    id
    firstName
    age
  }
}
update is a partial update — only the fields in input change. Everything else stays as it was.

Delete

mutation {
  deleteStudents(id: "2685ec12-a4c7-491d-a155-d0b09190993b")
}
Returns true on success.

Multiple record mutations

Create many

mutation {
  createStudentsMany(
    inputs: [
      { firstName: "Michael", lastName: "Jones", email: "michael@example.com", age: 24 }
      { firstName: "William", lastName: "Miller", email: "william@example.com", age: 23 }
    ]
  ) {
    success
  }
}
createStudentsMany runs as a single transaction. If any record fails validation, none are inserted. For larger or dynamic batches, pass the inputs as a variable so you can reuse the operation:
mutation CreateStudents($inputs: [StudentsCreateInput!]!) {
  createStudentsMany(inputs: $inputs) {
    success
  }
}
{
  "inputs": [
    { "firstName": "Michael", "email": "michael@example.com", "age": 24 },
    { "firstName": "William", "email": "william@example.com", "age": 23 }
  ]
}

Delete many

mutation {
  deleteStudentsMany(
    ids: [
      "2685ec12-a4c7-491d-a155-d0b09190993b",
      "f47ac10b-58cc-4372-a567-0e02b2c3d479"
    ]
  )
}

Nested mutations

Instead of pre-creating related records and passing their foreign keys, you can express the entire graph in one operation. Every relationship field accepts one of:
  • create — insert a new related record inline.
  • connect — link to an existing record by a unique field.
  • connectOrCreate — find by a unique field; create if missing.
mutation {
  createDeal(
    input: {
      title: "Enterprise License"
      amount: 50000

      contact: {
        create: { firstName: "Juan", lastName: "Pérez", status: "LEAD" }
      }

      user: {
        connect: { id: "user-uuid-123" }
      }

      organization: {
        connectOrCreate: {
          where: { domain: "acme.com" }
          create: { name: "Acme Corp", domain: "acme.com" }
        }
      }
    }
  ) {
    id
    contact { id }
    organization { id }
  }
}
The whole nested mutation runs as one transaction. If any step fails, the entire operation rolls back — you won’t end up with half-created records.

Atomic upserts

Tables with at least one unique column get an upsert<TableName> mutation. Pass a where clause that targets the unique column, plus create and update payloads. Archie atomically checks if the record exists and runs the matching branch.
mutation {
  upsertContact(
    where: { email: "juan@example.com" }
    create: {
      firstName: "Juan"
      lastName: "Pérez"
      email: "juan@example.com"
      status: "LEAD"
    }
    update: {
      lastName: "Pérez Updated"
      status: "ACTIVE"
    }
  ) {
    id
    firstName
    lastName
    status
  }
}
Use upsert instead of “select then insert or update” — it eliminates the race condition between the two queries.

Permissions

Every mutation is checked against the per-role permissions in Role-Based Access. A user without write access to a table will receive an authorization error before the mutation runs. Field-level write rules apply too — fields a role isn’t allowed to write are rejected even if the rest of the input is valid.

FAQ

update requires the record to exist and is keyed by id. upsert is keyed by any unique column and creates the record if it doesn’t exist. Use upsert when you have an external identifier (an email, a Stripe customer ID) and you don’t know whether the record already exists.
The mutation fails before any data is written, with an error indicating which field is missing. The error includes the field name and the constraint that was violated.
Yes. createStudentsMany runs in one round-trip and one transaction; a client-side loop runs one round-trip per record and serializes them. Use bulk for any batch over a few records.
The default createXxxMany mutation returns success. Project a richer payload by selecting more fields in the response if your bulk mutation supports it, or run a follow-up query keyed on the unique values you inserted.