GraphQL Schema Types & Query Operations Markdown Table Template
A GraphQL schema already describes itself through introspection, so why keep a table? Because SDL shows shapes, not policy. It will not tell a mobile developer which root fields need a token, which ones are scheduled for removal, or whether a null return means “not found” or “you may not see this”. This table is for frontend and partner developers choosing operations, and for reviewers checking a schema change PR.
Edit This Template
Edit cells, add rows, or sort — the Markdown updates livePaste cells from Excel or Google Sheets into the first header to replace the table · Tab / Enter / arrows move · Shift+F10 opens row & column actions
When to Use This Table
The detail that matters most is nullability. In GraphQL, a resolver error on a non-null field propagates null up to the nearest nullable parent, so declaring getTable(id: ID!): Table! means a missing record must come back as an error in the errors array, while Table (nullable) lets you return null for not-found. Clients write different code for each, which is why the Return Type column has to match the SDL character for character.
A useful table is generated from the printed schema rather than typed from memory, lists one row per root field on Query, Mutation, and Subscription, and records how auth is actually enforced. A poor one drifts from the deployed schema, mixes argument lists into the field name, and marks deprecated fields without saying what replaces them or when they disappear.
What Goes in Each Column
| Column | Alignment | What to put here |
|---|---|---|
| Operation / Type | center :---: | The root type the field lives on: Query, Mutation, or Subscription, centered. Sort rows by this column so readers find all write operations together. For object-type field references (fields on User or Table), put the parent type name here instead. |
| Field Name | left :--- | Just the field name in backticks, such as getTable, without the argument list. Arguments have their own column; repeating them here (as getTable(id: ID!)) creates two places to update when the signature changes. Use the exact casing from the schema, which is conventionally camelCase. |
| Arguments (Inputs) | left :--- | Each argument as name: Type, comma-separated, including default values (limit: Int = 20). When a mutation takes a single input object such as CreateTableInput!, name it here and document its fields in a separate input-type table rather than squeezing them into one cell. |
| Return Type | left :--- | The exact SDL type with every list and non-null wrapper: [Template!]! is a non-null list of non-null items, [Template] allows both the list and its items to be null. Abstract return types (interfaces and unions) go in by name; define their members in a separate table. |
| Auth Required | center :---: | The GraphQL spec has no auth model, so state the real mechanism: Public, a token type, or a role (Bearer JWT, admin role). Note field-level rules too, because a public query can still return a type whose sensitive fields need extra permissions. |
| Deprecation | center :---: | An em dash for active fields; for deprecated ones, the replacement field in backticks and a removal date. Mirror the reason string in the schema’s @deprecated directive so GraphiQL, IDE plugins, and this table say the same thing. |
How to Fill It In
- 1Print the deployed schema rather than reading source files:
printSchema(schema)in graphql-js, orrover graph introspect <endpoint>with Apollo Rover against staging. Introspection output is the truth clients see, including fields added by plugins or federation. - 2Create one row per field on the root types. Copy argument lists and return types verbatim from the printed SDL, then reread the nullability markers, since
!is the easiest character to drop when copying by hand. - 3Determine auth per field from the code that enforces it, such as schema directives, resolver guards, or gateway policy. Then verify by sending an anonymous request for each Public row to staging and confirming it succeeds.
- 4Search the SDL for
@deprecatedand add each match with its replacement. Before setting a removal date, check field usage from your gateway or tracing data so you do not remove something a client still calls. - 5Keep the table honest in CI: run a schema diff (for example
graphql-inspector diff old.graphql new.graphql) on every PR, and update the table in the same PR when the diff reports added, changed, or deprecated fields.
Ready-to-Paste Variations
Object type field reference
For documenting the fields of one type (here Table). Nullability gets its own column so readers can scan for fields that may be missing.
| Field | Type | Nullable | Description |
| :--- | :--- | :---: | :--- |
| `id` | `ID!` | No | Opaque identifier; serialized as a string |
| `title` | `String!` | No | Display title, 1–120 characters |
| `rowCount` | `Int!` | No | Number of body rows (32-bit signed) |
| `sizeBytes` | `BigInt` | Yes | Custom scalar; exceeds Int range for large files |
| `owner` | `User` | Yes | Null when the owner account was deleted |
| `columns` | `[Column!]!` | No | Always a list; may be empty |Unions and interfaces
Union members are separated by a pipe in SDL, which also splits Markdown cells, so each one is escaped as \| even inside backticks.
| Abstract type | Kind | Definition | Resolved by |
| :--- | :---: | :--- | :--- |
| `SearchResult` | Union | `union SearchResult = Table \| Template \| User` | `__typename` on each result |
| `Node` | Interface | `interface Node { id: ID! }` | Implemented by `Table`, `Template`, `User` |
| `MutationError` | Union | `union MutationError = ValidationError \| NotFoundError` | Returned in payload `errors` field |Built-in scalar quick reference
The five scalars every GraphQL server provides, with the limits that cause real bugs.
| Scalar | Serialized as | Range / notes |
| :--- | :--- | :--- |
| `Int` | JSON number | Signed 32-bit: −2,147,483,648 to 2,147,483,647 |
| `Float` | JSON number | Double precision; NaN and Infinity are not allowed |
| `String` | JSON string | UTF-8 text |
| `Boolean` | JSON boolean | `true` or `false` |
| `ID` | JSON string | Accepts string or integer input; not meant to be human-readable |Common Mistakes
Using
Intfor millisecond timestamps, file sizes, money in minor units, or database bigint IDs.Intis a signed 32-bit integer, and the current Unix time in milliseconds is already far above its maximum. UseIDfor identifiers and a custom scalar (such asBigIntorDateTime) for large numbers and timestamps.Marking every field non-null because it “should always exist”.
If a non-null field’s resolver throws, the null propagates upward and can blank out the whole parent object or even
data. Keep fields that depend on other services or permissions nullable, and document whatnullmeans.Writing the full signature in Field Name and the arguments again in the next column.
Put only the name in the first column. One source per fact means a signature change touches one cell, and the table can be compared against the schema automatically.
Removing a deprecated field on the announced date without checking usage.
Deprecation is a request, not a guarantee. Check operation or field usage metrics first, contact the remaining callers, and only then delete the field and its row.
Writing “Yes” in the auth column.
Name the scheme and the role. “Yes” tells an integrator nothing about which token to obtain or why a call returns a forbidden error.
Related Markdown Table Templates
Browse all 50 templatesREST & GraphQL API Parameters
Document REST endpoints, GraphQL query fields, request payload types, requirements, and default fallback values.
Relational Database Table DDL Schema
Document database tables, column names, SQL types, nullability, keys (PK/FK), default values, and column semantics.
Cross-Language Data Type Mapping
Map fundamental data types across TypeScript, Python, SQL (PostgreSQL), Rust, and JSON standards.
GraphQL Schema Types & Query Operations: Frequently Asked Questions
What is the difference between [User!]! and [User]!?
[User!]! guarantees a list (possibly empty) whose items are never null. [User]! guarantees the list but allows null items, which typically appear when resolving one item fails while the others succeed. Clients must handle null entries in the second case.
Why document the schema in a table when GraphiQL already shows it?
Explorers show types, not policy. Partners without access to your playground, reviewers reading a PR, and people searching your docs need auth rules, deprecation timelines, and intent, none of which introspection carries.
Can arguments and input fields be deprecated?
The October 2021 spec edition allows @deprecated on field definitions and enum values. Deprecating arguments and input fields was added later through an RFC that graphql-js 16 implements, so check your server and client tooling before relying on it.
Should mutations return the object or a payload type?
A payload type such as TablePayload! is easier to evolve: you can add fields like errors or clientMutationId later without breaking clients. Returning the bare object locks the mutation to that shape.