What is an object type in GraphQL SDL, and which of its fields may declare arguments?
answer
- A named type and its field list
- Arguments hang off a field definition
- Not a privilege of the root fields
- Name, type, optional default literal
- Argument types come from the input side
basics
~20 sAn object type is a named type holding a list of fields. Arguments belong to a field rather than to the type, so any field at any depth may declare them - not just the fields on the query root.
solid answer
~50 sAn object type is declared with `type Name { ... }` and holds a list of fields; each field has a name, an optional argument list and a result type, and fields typed by other object types are what make the schema a graph. Arguments are declared **per field**, so a field several levels down parameterises itself exactly the way a root field does - `statements(year: Int!, page: Int = 1)` on an `Account` is as legal as `account(id: ID!)` on the query root. An argument declaration is a name, a type and an optional default value. Argument types are restricted to input types - scalars, enums, input objects and list or Non-Null wrappers of those - so an object type, interface or union can never be an argument type. Arguments are matched by name, never by position, and a field has exactly one argument list: there is no overloading.
code
graphql · 22 linestype Query {
account(id: ID!): Account
}
type Account {
id: ID!
iban: String!
balanceMinor: Int!
statements(year: Int!, page: Int = 1): [Statement!]!
}
type Statement {
id: ID!
closingBalanceMinor: Int!
transactions(minAmountMinor: Int = 0): [Transaction!]!
}
type Transaction {
id: ID!
amountMinor: Int!
description: String!
}go deeper
Be ready to write a small object type from memory and point at the three parts of a field definition: name, optional arguments, type. Then say plainly that arguments may sit on any field, not just the root.
Explain the mechanics: argument types are restricted to the input side, defaults must be constant literals, arguments are matched by name, and a field has exactly one argument list with no overloading.
Show the design consequence. Nested arguments let a client shape data where the shaping is needed instead of forcing a flat root field per combination, and a new nullable or defaulted argument is additive for every existing document.
Own the boundary question: which parameters belong on a field at all versus being encoded in the graph's shape. Argument surface is API surface, and every argument you publish is one you must keep honouring.
## The object type is the workhorse of the schema Almost everything a GraphQL server can return is an object type. It is declared with the `type` keyword, a name, and a brace-delimited **field list**: ```graphql type Account { id: ID! iban: String! balanceMinor: Int! statements(year: Int!, page: Int = 1): [Statement!]! } ``` Each entry in that list is a **field definition**, and a field definition has three parts: a name, an optional argument list in parentheses, and - after the colon - the field's type. The type may be a scalar, an enum, another object type, an interface, a union, or a list or Non-Null wrapper of those. When a field's type is another object type, the schema stops being a flat table listing and becomes a graph: `Account.statements` points at `Statement`, whose own `transactions` field points at `Transaction`, and a client can walk that chain in one document. A field list is not optional decoration. An object type with no fields is not a valid type, because a client must be able to select *something* from it; every selection on an object-typed field has to name at least one field of that type. ## Arguments belong to fields, not to types This is the point interviewers are usually probing. Beginners internalise the shape of the query root - `account(id: ID!)`, `search(term: String!)` - and conclude that parameters are something you pass "into the API" at the entry point. They are not. **An argument list is part of a field definition, and every field definition may have one.** `Account.statements` above takes `year` and `page`. `Statement.transactions` can take `minAmountMinor`. Nothing distinguishes a root field here: the query root is simply whichever object type the schema names as the entry point, and its fields are ordinary fields of an ordinary object type. Why this matters in practice: it means a client can shape data *at the point in the graph where the shaping is needed*, instead of the server having to expose a flattened root field for every combination. Without nested arguments a bank statements graph would need `accountStatementsForYear(accountId:, year:)` at the root; with them, `account(id:) { statements(year:) }` composes the same thing out of two independently useful fields. The symmetric point: interface types declare fields with arguments too, and an object type implementing an interface has to carry those arguments through. The declaration lives on the field either way. ## What an argument declaration contains Three things, two of them mandatory: * **A name** - unique within that field's argument list. * **A type** - restricted to *input* types. The input side of the type system is scalars, enums and input object types, plus list and Non-Null wrappers of those. Object types, interfaces and unions are output-only: they can be the type of a field, never the type of an argument. A schema that declares `statements(filter: Account)` is invalid and fails when the server builds it, not when a client sends something. * **An optional default value**, written `= literal`. The default must be a constant literal; it cannot reference a variable or another argument. The reason for the input/output split is structural rather than arbitrary. Output types carry things that make no sense on the way in - their own fields take arguments, they participate in interfaces and unions, and a client selects a subset of them. An argument value is data being handed over whole, so it needs a type kind with no arguments and no selection. ## Named, not positional, and never overloaded Arguments are supplied by name at the call site, so order is irrelevant in both directions: the schema may declare `(year, page)` and a document may write `(page: 3, year: 2024)`. There is no positional form; `statements(2024, 3)` is a syntax error, not a shorthand. Being named has two consequences worth being able to state. First, **adding a new argument that is nullable or defaulted does not break any existing document**, because every existing document simply omits it - the same change to a positional API would shift every call site. Second, an omitted argument is not an error by itself: it falls back to its default if it has one, and otherwise counts as not provided. There is exactly **one argument list per field**. GraphQL has no overloading - you cannot declare `transactions(limit: Int)` and `transactions(since: String)` as two variants of the same field. Variation is expressed as more arguments on one field, or as genuinely different fields. ## Selecting the same field twice Because the argument values live in the document rather than in the schema, one selection set can ask for the same field with different arguments. The two selections need different response keys, which is what field aliasing is for; the schema side needs no help - the field is declared once and applied twice. ## What this leaf is not about How a server hands those declared argument values to the code sitting behind the field, and what happens if that code ignores them, is execution's business rather than the type system's. On the schema side the contract is complete once the field, its arguments and their types are written down.
- Can a field argument be typed as an object type such as `Account`?No. Argument types are limited to input types - scalars, enums, input object types, and list or Non-Null wrappers of those. Object types, interfaces and unions are output-only, because they carry their own arguments and are selected from rather than supplied whole. A schema that declares an object type as an argument type is invalid and fails when the server builds the schema, long before any client sends a document.
- Does the argument order in a document have to match the order in the schema?No. Arguments are matched by name in both the definition and the call site, so `statements(page: 3, year: 2024)` and `statements(year: 2024, page: 3)` are the same selection. There is no positional syntax at all - writing `statements(2024, 3)` is a parse error. An argument left out entirely falls back to its default value if it has one.
- Can one field be overloaded with two different argument lists?No. A field definition carries exactly one argument list, and a field name is unique within its type, so GraphQL has no overloading. If a field genuinely needs two modes of use, express that as extra arguments on the single list - typically nullable ones the caller picks between - or declare two differently named fields. Documents distinguish uses by the values they pass, not by which signature they match.
A parameterised field is a question the graph will answer at that exact point. Every node in the graph is allowed to ask you for details, not just the front door.
saying these in an interview costs you the question
- Says only root fields can take arguments
- Passes arguments positionally, by declaration order
- Declares an object type as an argument type
- Thinks arguments are declared on the type, not the field
- Believes one field can carry two argument lists
- Assumes an omitted argument is always an error