GraphQL Arguments â Query and Field Arguments Explained
In this tutorial, you will learn about Graphql Arguments. We cover key concepts, practical examples, and best practices to help you master this topic.
GraphQL arguments let clients pass parameters to queries, mutations, and individual fields, enabling precise data fetching and server-side filtering.
What You'll Learn
You will learn how to define arguments in SDL, pass arguments from queries, use required and optional arguments, implement argument validation, and design intuitive argument APIs.
Why Arguments Matter
Arguments are how clients tell the server what data they want. Without arguments, every query returns everything â no filtering, no pagination, no personalization. Arguments turn a static endpoint into a dynamic API. DodaTech's Durga Antivirus Pro uses arguments for filtering threats by severity, paginating device lists, querying specific time ranges, and fetching data for individual users.
flowchart LR
A["Query: threats(\n severity: CRITICAL\n since: DateTime!\n limit: Int = 20\n)"] --> B["Resolver receives:\n args = { severity: 'CRITICAL',\n since: Date('2026-06-01'),\n limit: 20 }"]
B --> C["Filter data by\narguments"]
C --> D["Return matching\nresults"]
style A fill:#dbeafe,stroke:#2563eb
style B fill:#fef3c7,stroke:#d97706
Prerequisites: GraphQL queries and resolver fundamentals.
Defining Arguments in SDL
Arguments are defined in parentheses after the field name:
type Query {
# Required argument
device(id: ID!): Device
# Optional argument with default
threats(severity: Severity, limit: Int = 20, offset: Int = 0): [Threat!]!
# Multiple arguments
devices(status: DeviceStatus, search: String, sortBy: String): [Device!]!
# Argument on a specific field (not just top-level)
user(id: ID!): User
}
type User {
devices(status: DeviceStatus): [Device!]!
threats(since: DateTime!, limit: Int = 10): [Threat!]!
}
Arguments on individual fields enable field-level filtering â fetching only a user's critical threats, for example.
Passing Arguments from Queries
# Required argument
query GetDevice {
device(id: "dev-001") {
id
name
os
}
}
# Optional arguments
query GetCriticalThreats {
threats(severity: CRITICAL, limit: 5, offset: 0) {
id
name
detectedAt
}
}
# Field-level argument
query GetUserDevices {
user(id: "user-001") {
name
email
devices(status: ONLINE) {
id
name
os
}
}
}
// Expected response
{
"data": {
"user": {
"name": "Alice Smith",
"email": "alice@dodatech.com",
"devices": [
{ "id": "dev-001", "name": "Office-PC", "os": "Windows 11" },
{ "id": "dev-003", "name": "Server-01", "os": "Ubuntu 24.04" }
]
}
}
}
Variable Arguments
Using variables keeps queries clean and reusable:
query GetFilteredThreats($severity: Severity, $limit: Int, $since: DateTime!) {
threats(severity: $severity, limit: $limit, since: $since) {
id
name
severity
detectedAt
}
}
# Variables
{
"severity": "CRITICAL",
"limit": 10,
"since": "2026-06-01T00:00:00Z"
}
Argument Resolver Implementation
const resolvers = {
Query: {
threats: (parent, args, context) => {
const { severity, limit = 20, offset = 0, since } = args;
let results = context.db.threats;
// Filter by severity (optional)
if (severity) {
results = results.filter(t => t.severity === severity);
}
// Filter by date (required since argument)
if (since) {
const sinceDate = new Date(since);
results = results.filter(t => new Date(t.detectedAt) >= sinceDate);
}
// Paginate
return results.slice(offset, offset + limit);
},
},
User: {
// Field-level resolver with arguments
devices: (parent, args, context) => {
const { status } = args;
let userDevices = context.db.devices.filter(
d => d.userId === parent.id
);
if (status) {
userDevices = userDevices.filter(d => d.status === status);
}
return userDevices;
},
},
};
Required vs Optional Arguments
type Query {
# Required â must always be provided
device(id: ID!): Device
# Optional â can be omitted, null if not provided
threats(severity: Severity): [Threat!]!
# Optional with default â can be omitted, uses default value
devices(limit: Int = 20): [Device!]!
# Mix of required and optional
userDevices(userId: ID!, status: DeviceStatus, limit: Int = 10): [Device!]!
}
Default values only work for scalar types and enums. Use the ! after the argument name to make it required.
Common Mistakes
1. Too Many Required Arguments
Requiring 5+ arguments on every query makes the API painful to use. Make non-essential arguments optional with sensible defaults.
2. Not Using Variable for Arguments
Hardcoding argument values in queries prevents Caching and reuse. Always use $variable syntax for dynamic values.
3. Forgetting Default Values for Pagination
Always provide defaults for limit and offset to prevent unlimited result sets: limit: Int = 20, offset: Int = 0.
4. Duplicating Arguments on Every Query
If 10 queries all need the same userId argument, consider putting it in context (authentication) instead. D.R.Y for arguments too.
5. Using JSON for Complex Arguments
Instead of filter(filter: JSON), define a FilterInput input type with typed fields. JSON arguments bypass all validation.
Practice Questions
- What is the difference between required and optional arguments?
- How do default argument values work?
- Can arguments be defined on individual fields (not just root queries)?
- What is the variable syntax for passing arguments?
- Why prefer input types over multiple flat arguments?
Answers:
- Required arguments (with
!) must be provided by the client. Optional arguments (without!) can be omitted and will be null if not provided. - Default values (
limit: Int = 20) apply when the client omits the argument. They only work for scalars and enums, not for input types. - Yes â any field can accept arguments:
user(id: ID!)ordevices(status: DeviceStatus). The resolver for that field receives the arguments. $variableName: Typein the query signature, thenfield(variableName: $variableName)in the query body. Variables are passed in a separate JSON object.- Input types group related arguments into a single object, making mutation signatures cleaner and enabling reuse across multiple mutations.
Challenge: Design the argument API for DodaTech's global search feature. Include required query string, optional filters (type, severity, dateRange, status), pagination with defaults, sorting options, and field-level arguments for result highlights.
FAQ
Mini Project
Design a rich argument system for DodaTech's threat analytics dashboard. Include filters (severity, dateRange, deviceId, threatType), pagination (limit, offset), sorting (sortBy, sortOrder), aggregation options (groupBy, interval), and field-level arguments on dashboard widgets (timeframe, comparison).
What's Next
| Topic | Description |
|---|---|
| Directives Guide | Schema and query directives |
| Input Types | Structured mutation arguments |
| Mutations Guide | Mutation patterns and practices |
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro