CSV to GraphQL Mutation Generator

Turn a CSV into ready-to-run GraphQL createX mutation calls, one per row.

Free in-browser tool that maps CSV headers to GraphQL argument names and generates one createX mutation per row with correctly typed scalars — strings quoted, numbers and booleans bare. Produces a ready-to-run GraphQL document. No data is transmitted. It runs free in your browser on Gera Tools, with nothing uploaded.

Last updated Source: Gera Tools

How does it decide whether a value is a string or a number?

Each value is type-inferred. A value that parses as a finite number becomes a bare GraphQL number, true/false becomes a boolean, an empty cell becomes null, and everything else is emitted as a double-quoted string with internal quotes and backslashes escaped.

When you need to seed a GraphQL API or import a spreadsheet of records, writing one mutation per row by hand is slow. This tool reads your CSV and emits a GraphQL document with one createX call per row, inferring the right scalar type for every value — so strings are quoted, numbers and booleans are bare, and empty cells become null.

How it works

  1. Parse the CSV with an RFC 4180 parser that respects quoted fields containing commas, newlines and escaped "" quotes. The first row supplies the field names.
  2. Infer each value’s type so the GraphQL is syntactically correct:
    • empty → null
    • true / false (case-insensitive) → boolean
    • a finite number → numeric literal
    • anything else → a double-quoted string, with " and \ escaped
  3. Emit the mutation. Each row becomes mutationField(arg1: value1, arg2: value2) { id }. You can output one operation per row, or alias all rows into a single document (row0: createUser(...) { id }) so the batch runs in one request.
mutation Seed {
  row0: createUser(name: "Ada", age: 36, active: true) { id }
  row1: createUser(name: "Linus", age: 54, active: false) { id }
}

Single operations vs. aliased batch document

Two output modes serve different needs:

Single operation per row generates one named mutation CreateX { ... } per CSV row. This is useful when you want to paste and run them individually, or when your GraphQL server does not allow multiple root fields in one operation. The downside is that you must execute them one at a time.

Aliased batch document combines all rows into a single mutation Seed { row0: ..., row1: ..., row2: ... }. The server receives one request and executes all mutations in it, making seeding much faster. The aliases (row0, row1, …) also let you identify individual successes and failures in the response, since GraphQL returns each alias as a separate key.

Most production GraphQL servers support aliased multi-field mutations, but some have depth limits or disable batching by default — check your server’s settings if the batched document is rejected.

Type inference edge cases

The inference rules follow GraphQL scalar conventions:

CSV cellInferred GraphQL typeReasoning
(empty)nullNo value
true or falseBooleanCase-insensitive
42 or -3.14Int / FloatFinite JSON-style number
007StringLeading zero implies identifier, not number
1,000StringComma formatting is not a GraphQL number
"hello, world"StringEmbedded comma preserved by RFC 4180 parser

The rule for leading-zero preservation is intentional. Postcodes, phone extension numbers, and product codes that look numeric should stay as strings. If you need one treated as a number, remove the leading zero in the source CSV.

Adapting the output for input types

The generated mutations use positional scalar arguments directly. If your schema uses an input type — for example createUser(input: CreateUserInput!) — you need to wrap the generated arguments:

# Generated (flat arguments)
createUser(name: "Ada", age: 36) { id }

# Adapted for input type
createUser(input: { name: "Ada", age: 36 }) { id }

This is a two-second edit after generation. Alternatively, rename the CSV header row to match your schema’s exact field names so the generated arguments align without any manual correction.

Tips and notes

  • Header names are used verbatim as argument names — make sure they match your schema’s input fields (or rename the CSV header row).
  • Quote a numeric-looking value in the CSV (e.g. a postcode or phone number) by wrapping it in "…" if you want it kept as a string; otherwise it is inferred as a number.
  • The selection set defaults to { id }; change it after generation if your mutation returns a different shape.
  • Everything runs locally, so the CSV’s contents stay on your device.