GraphQL SDL (Schema Definition Language) â Complete Syntax Guide
In this tutorial, you will learn about Graphql SDL (Schema Definition Language). We cover key concepts, practical examples, and best practices to help you master this topic.
GraphQL Schema Definition Language (SDL) is the syntax used to describe the types, fields, and relationships in a GraphQL API, serving as the contract between client and server.
What You'll Learn
You will learn SDL syntax for defining object types, scalars, enums, interfaces, unions, and input types, along with field modifiers, directives, and schema organization patterns.
Why SDL Matters
The schema is the single source of truth for every GraphQL API. A well-written SDL schema communicates intent, enables tooling (autocomplete, validation, Code Generation), and prevents ambiguity between frontend and backend teams. DodaTech's Durga Antivirus Pro uses SDL to define types for Device, Threat, User, and Scan, and the schema is checked into version control as the contract that both the React dashboard team and the Go backend team agree on.
flowchart TB
A["SDL Schema"] --> B["Object Types\n(type Device { ... })"]
A --> C["Scalars\n(scalar DateTime)"]
A --> D["Enums\n(enum Severity { LOW })"]
A --> E["Interfaces\n(interface Node { ... })"]
A --> F["Unions\n(union Result = A | B)"]
A --> G["Input Types\n(input Input { ... })"]
A --> H["Directives\n(@deprecated, @skip)"]
style A fill:#dbeafe,stroke:#2563eb
style B fill:#fef3c7,stroke:#d97706
style C fill:#fef3c7,stroke:#d97706
style D fill:#fef3c7,stroke:#d97706
style E fill:#fef3c7,stroke:#d97706
style F fill:#fef3c7,stroke:#d97706
style G fill:#fef3c7,stroke:#d97706
style H fill:#fef3c7,stroke:#d97706
Prerequisites: Basic GraphQL concepts. Familiarity with JSON and type systems is helpful.
SDL Syntax Basics
SDL is a human-readable syntax for defining GraphQL types:
# This is a comment in SDL
type Device {
id: ID!
name: String!
os: String!
version: String
lastScan: DateTime
user: User!
threats: [Threat!]!
}
Each field has a name, a type, and optional modifiers. The ! means non-nullable. [ ] denotes a list.
Object Type Definition
Object types represent entities in your API:
type User {
id: ID!
email: String!
displayName: String!
role: UserRole!
devices: [Device!]!
createdAt: DateTime!
}
type Device {
id: ID!
name: String!
os: String!
version: String
user: User!
threats: [Threat!]!
scans: [Scan!]!
}
Naming convention: types are PascalCase, fields are camelCase. Object types can reference each other, forming the relationship graph.
The Query and Mutation Types
These are special root types that define API entry points:
type Query {
devices: [Device!]!
device(id: ID!): Device
threats(severity: Severity): [Threat!]!
user(id: ID!): User
}
type Mutation {
createDevice(input: CreateDeviceInput!): Device!
updateDevice(id: ID!, input: UpdateDeviceInput!): Device!
deleteDevice(id: ID!): DeleteResponse!
}
# Example query using the schema
query {
device(id: "dev-001") {
name
os
user {
displayName
email
}
}
}
# Expected response
{
"data": {
"device": {
"name": "Office-PC",
"os": "Windows 11",
"user": {
"displayName": "Alice Smith",
"email": "alice@dodatech.com"
}
}
}
}
Field Modifiers
Modifiers control nullability and cardinality:
type Example {
basic: String # Nullable string
required: String! # Non-null string
list: [String] # Nullable list of nullable strings
nonNullItems: [String!] # Nullable list of non-null strings
nonNullList: [String]! # Non-null list of nullable strings
strict: [String!]! # Non-null list of non-null strings
}
Best practice: use [String!]! for most list fields â the list always exists (may be empty) and every item is guaranteed valid.
Directives
Directives add metadata and behavior to schema elements:
type Device {
id: ID!
name: String!
os: String!
version: String @deprecated(reason: "Use 'osVersion' instead")
osVersion: String
user: User!
}
# Query directives
query GetDevices($includeScans: Boolean!) {
devices {
id
name
scans @include(if: $includeScans) {
id
status
}
}
}
Built-in directives: @deprecated, @skip, @include, @specifiedBy. Custom directives enable features like authentication (@auth) and formatting.
Common Mistakes
1. Using Reserved Names for Types
Query, Mutation, Subscription, String, Int, Float, Boolean, and ID are reserved. You cannot create a type named Query (that IS the root query type).
2. Forgetting Non-Null Modifiers on Key Fields
Every type should have a non-null id: ID! field. Nullable IDs make cache normalization impossible in Apollo Client.
3. Inconsistent Naming Conventions
Mixing snake_case and camelCase confuses clients. GraphQL convention is camelCase for fields and PascalCase for types.
4. Not Using Description Strings
Without descriptions (" " string literals in SDL), GraphiQL and generated docs show no guidance. Document every type and field:
"Represents a device running Durga Antivirus Pro"
type Device {
"Unique device identifier"
id: ID!
"Human-readable device name"
name: String!
}
5. Circular Reference Without Nullable Fields
If User has devices: [Device!]! and Device has user: User!, you must ensure at least one side can be null to avoid an impossible-to-resolve chain.
Practice Questions
- What does the
!symbol mean in SDL? - What is the difference between
typeandinputin SDL? - What are the five built-in scalar types in GraphQL?
- How do you add descriptions to types and fields?
- What is the purpose of the
@deprecateddirective?
Answers:
- Non-nullable â the field will always return a value and cannot be null. If the resolver returns null, GraphQL propagates the null upward.
typedefines output objects with resolvers.inputdefines argument structures without resolvers (used for mutation arguments).String,Int,Float,Boolean,ID. Custom scalars (likeDateTime) extend this set.- Use string literals before the type or field definition:
"Description here"on the line above. These appear in GraphiQL and generated documentation. @deprecated(reason: "...")marks a field as deprecated in the schema. Tools display the reason and suggest alternatives. Clients should migrate away from deprecated fields.
Challenge: Write an SDL schema for DodaTech's antivirus alert system. Include types for Alert (id, message, severity, device, createdAt), User (id, email, alerts, role), Device (id, name, os, user, alerts), an AlertSeverity enum, input types for creating and updating alerts, and root Query/Mutation types with pagination support.
FAQ
Mini Project
Create an SDL file for a complete Durga Antivirus Pro API. Include types for User, Device, Threat, Scan, Alert, and Subscription. Add input types for all mutations, enums for severity and device status, and descriptions on every type and field.
What's Next
| Topic | Description |
|---|---|
| Custom Scalars | Extending the scalar type system |
| Enums in Depth | Defining enum values and use cases |
| Types & Schema Design | Schema design best practices |
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro