GraphQL Schema Design: Types, Mutations, Pagination

Facing API issues like N+1 queries, inconsistent interfaces, and unclear errors? We design GraphQL schemas tailored to your product's needs, not the database structure. Our team delivers turnkey projects—from analyzing types and mutations to pagination per Relay spec—ensuring reliable operation and ongoing support.

Development and maintenance of all types of websites:

Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:

Frequently Asked Questions

Latest works

  • Development of a web application for FEEDME
    Development of a web application for FEEDME
    1342
  • Development of an online store for the company FURNORO
    Development of an online store for the company FURNORO
    1304
  • Development of a web application for Enviok
    Development of a web application for Enviok
    1047
  • CRM development for Chasseurs
    CRM development for Chasseurs
    1094
  • Website development for SBH Partners
    Website development for SBH Partners
    1169
  • Website development for Red Pear
    Website development for Red Pear
    593

GraphQL Schema Design for Web Applications

We design GraphQL schemas that serve for years without workarounds. A bad schema leads to broken N+1 queries, ghost fields, and type UserOrError instead of proper error handling. Our approach: first analyze interface needs, then define types. Experience shows: a well-designed schema reduces frontend development time by 30% and eliminates 90% of query performance issues. Team resource savings can reach 40% during the integration phase.

The schema is product-oriented, not storage-oriented. REST endpoints often mirror the database structure. With GraphQL, it's the opposite: first determine what the UI needs, then design types. This cuts rework time by half compared to traditional REST. By ordering schema design from us, you get a ready-made contract for frontend and backend. We guarantee your team won't face inconsistent interfaces.

Nodes and Edges via Relay specification. If the project is medium-sized or larger, it's worth adopting a Relay-compatible structure upfront—it sets a standard for pagination and global IDs. Typically, this saves 30% of time on interface agreement within the team.

How to Avoid N+1 in GraphQL Schema?

Every field can trigger a separate database query. Without aggregation, you get the N+1 problem. The solution is DataLoader: it batches requests by keys. Also use @cacheControl for caching at the field level. In practice, this reduces database load by 3–5 times. For example, fetching 100 orders with nested items without DataLoader generates 101 queries; with batching, only 3-4.

Why We Use Relay Specification?

Relay provides a standard for pagination (cursor-based), global IDs, and refetching. This reduces discussions within the team and makes the schema predictable. Compare: cursor pagination works 10 times faster than offset-based when fetching beyond 1000 records, as it doesn't scan the entire result set.

Basic Types and Pagination

type Query {
  node(id: ID!): Node
  product(id: ID!): Product
  products(filter: ProductFilter, page: PaginationInput): ProductConnection!
  viewer: User
}

interface Node {
  id: ID!
}

type ProductConnection {
  edges: [ProductEdge!]!
  pageInfo: PageInfo!
  totalCount: Int!
}

type ProductEdge {
  node: Product!
  cursor: String!
}

type PageInfo {
  hasNextPage: Boolean!
  hasPreviousPage: Boolean!
  startCursor: String
  endCursor: String
}

input PaginationInput {
  first: Int
  after: String
  last: Int
  before: String
}

input ProductFilter {
  categoryIds: [ID!]
  priceMin: Decimal
  priceMax: Decimal
  inStock: Boolean
  search: String
  tags: [String!]
}

Comparison of Cursor vs. Offset Pagination

Criterion Cursor Pagination Offset Pagination
Performance on large datasets O(log n) O(n)
Consistency on inserts Stable Duplicates/misses
Implementation Slightly harder Easier
Relay support Yes No

Payload Pattern for Mutations

Never return a bare object type from a mutation. Use a payload wrapper containing the result and an array of userErrors.

type CreateOrderPayload {
  order: Order
  userErrors: [UserError!]!
}

type UserError {
  field: [String!]
  message: String!
  code: OrderErrorCode
}

enum OrderErrorCode {
  INSUFFICIENT_STOCK
  INVALID_ADDRESS
  PAYMENT_DECLINED
  PRODUCT_UNAVAILABLE
}

The difference between userErrors and GraphQL errors: userErrors are predictable business errors that the client must handle. GraphQL errors are unexpected situations (exceptions, network errors).

Directives for Access Control and Caching

directive @auth(requires: Role = USER) on FIELD_DEFINITION
directive @rateLimit(max: Int!, window: String!) on FIELD_DEFINITION
directive @cacheControl(maxAge: Int, scope: CacheControlScope) on FIELD_DEFINITION | OBJECT

enum Role {
  ADMIN
  MANAGER
  USER
  GUEST
}

enum CacheControlScope {
  PUBLIC
  PRIVATE
}

# Example usage
type Query {
  products: ProductConnection! @cacheControl(maxAge: 300, scope: PUBLIC)
  dashboard: DashboardStats! @auth(requires: MANAGER) @rateLimit(max: 60, window: "1m")
}

Versioning and Deprecation

GraphQL is not versioned via URL. Instead, use continuous evolution: new fields are added, old ones are marked @deprecated. This allows clients to migrate without breaking changes. According to the GraphQL specification, this approach is considered best practice.

type Product {
  id: ID!
  name: String!
  price: Decimal @deprecated(reason: "Use `pricing.basePrice` instead")
  pricing: ProductPricing!
  variants: [ProductVariant!]!
}

type ProductPricing {
  basePrice: Decimal!
  salePrice: Decimal
  currency: CurrencyCode!
}

How to Audit an Existing Schema in 3 Steps

  1. Field cartography. Collect all fields used by the client using tools like graphql-inspector. Cut off unused ones.
  2. Performance profiling. Measure TTFB of each request with Apollo Studio or Sentry. Identify N+1 queries.
  3. Optimization. Implement DataLoader for critical fields, add caching via @cacheControl. Reduce the number of joins.
Example folder structure for domains
schema/ base.graphql products.graphql orders.graphql users.graphql scalars.graphql directives.graphql 

Schema Splitting by Domains

For large projects, the schema is split into files by domain as shown above. This simplifies maintenance and review. In practice, this approach reduces merge conflict rate by 70%.

What's Included in Turnkey Schema Design

Stage Result
UI and business logic analysis List of required types and operations
Schema design .graphql files, field documentation
Review with frontend team Agreed contract
DataLoader integration N+1 query optimization
Deployment and monitoring Rate limiting, caching setup

Also includes team training on schema usage and one month of post-launch support. Get a consultation — let's discuss your project.

Timelines

Schema design for a medium-sized application (5-10 entities): 3–5 days. With review, documentation, and agreement: 1 week. Contact us to discuss your project — we'll estimate the scope and propose an optimal solution. Order turnkey schema design and get rid of N+1 problems and inconsistent interfaces. Our team has 5+ years of experience and has successfully completed over 100 projects across various domains.

GraphQL is not just a technology but a discipline of contract design. We guarantee the result will meet the specification and your team's expectations.