Skip to content
API Design Learn/GraphQL at Scale
Browsing as a guest. Sign in to save your progress and earn XP as you complete chapters.

Custom Scalars

6 min read

You'll learn to

  • -Define a custom GraphQL scalar with serialize/parseValue/parseLiteral logic for a domain-specific type
  • -Know when a custom scalar is the right tool versus just using String with documented formatting conventions

GraphQL's built-in scalars (`Int`, `Float`, `String`, `Boolean`, `ID`) don't cover every kind of value an API needs to represent precisely - a date, a URL, or an email address could technically be sent as a `String`, but that throws away the opportunity to validate and document the value's actual shape at the schema level.

Defining a Custom Scalar

Declaring a custom scalar in the schema
scalar DateTime

type Order {
  id: ID!
  placedAt: DateTime!
}
The serialize/parseValue/parseLiteral logic behind the scalar
from datetime import datetime

class DateTimeScalar:
    def serialize(self, value: datetime) -> str:
        # Python datetime -> ISO 8601 string, going OUT to the client
        return value.isoformat() + "Z"

    def parse_value(self, value: str) -> datetime:
        # incoming variable value -> Python datetime, going IN from the client
        return datetime.fromisoformat(value.rstrip("Z"))

    def parse_literal(self, node) -> datetime:
        # incoming inline literal in the query string itself
        return datetime.fromisoformat(node.value.rstrip("Z"))

A scalar needs three functions: `serialize` (internal representation to wire format, for responses), `parseValue` (wire format to internal representation, for variables), and `parseLiteral` (wire format to internal representation, for values written directly in the query string). Once defined, `DateTime` behaves like any built-in scalar in the schema - but with validation and consistent formatting enforced centrally, in one place, rather than every resolver that touches a date reimplementing its own parsing and formatting.

When a Custom Scalar Is Worth It

  • -The value has a well-defined, validatable format (dates, URLs, email addresses, currency amounts) where "is this actually valid" is a real, checkable question - not just any string.
  • -The same kind of value appears across many fields and types, making centralized validation and formatting logic worth the setup cost.
  • -Clients benefit from knowing the field is specifically a `DateTime` rather than an opaque `String`, for their own tooling (client-side type generation, form validation) to take advantage of.

For a one-off, rarely-used field where the "format" is really just documentation ("this string happens to look like X"), a plain `String` with a clear description in the schema is often simpler and perfectly adequate - custom scalars earn their setup cost when validation and reuse genuinely matter, not as a default for every field that isn't a plain number or boolean.

A custom scalar's validation runs automatically as part of GraphQL's own request parsing, before any resolver code executes - an invalid `DateTime` value is rejected by the framework itself, not silently accepted and passed through to a resolver that might not check it.

Interview Signal is part of Pro

See a real weak answer next to a real strong one for this exact topic.

Quiz is part of Pro

Test what you just read with a short quiz, and bank the XP.

Ready to Build This?

Design Custom Scalars Lab in the API Design Lab's GraphQL Mastery act.

ScaleDojo Logo
Initializing ScaleDojo