Default nullability
Flip Pothos's nullable-by-default to non-nullable when that matches your codebase better.
By default, Pothos fields and arguments are nullable. To make a field non-nullable you pass nullable: false; to make an arg required you pass required: true. This matches GraphQL's wire-level default — everything is nullable unless marked !.
In many codebases most values are non-nullable, so most fields end up as Type!. Flipping the default once on the builder saves passing nullable: false on every field.
const builder = new SchemaBuilder<{
DefaultFieldNullability: false;
}>({
defaultFieldNullability: false,
});DefaultFieldNullability on the generic and defaultFieldNullability in the constructor options have to agree; Pothos refuses to compile if they don't. With both set to false, every field declared from this builder defaults to non-nullable.
Using the flipped default
Once the default is non-nullable, you mark the genuinely-optional fields explicitly:
Race.implement({
fields: (t) => ({
// Non-nullable now, so SDL reads `id: ID!`.
id: t.exposeID('id'),
name: t.exposeString('name'),
// Opt back into nullable for genuinely optional fields.
motto: t.exposeString('motto', { nullable: true }),
}),
});Flipping argument defaults too
DefaultFieldNullability only affects output fields. Argument and input-field requiredness has its own slot, DefaultInputFieldRequiredness, which controls whether input fields and arguments default to required:
const builder = new SchemaBuilder<{
DefaultFieldNullability: false;
DefaultInputFieldRequiredness: true;
}>({
defaultFieldNullability: false,
defaultInputFieldRequiredness: true,
});With both flipped, the codebase reads as if everything is non-nullable and required by default, closer to TypeScript's defaults than to GraphQL's.
When not to flip
Nullability affects how a thrown error propagates: a nullable field can become null in place, while a non-nullable field pushes the error up to its nearest nullable ancestor. Defaulting to non-nullable means a single failing resolver can blank out a larger part of the response. The Handling errors guide covers this in full.
If your schema serves clients that can't gracefully handle partial responses (legacy mobile clients, brittle codegen), the nullable default may be the safer choice. When clients handle partial responses well, the non-nullable default keeps the schema aligned with your TypeScript types.