Learn GraphQL - Schema-First vs Code-First Approach
Episode 30 of 51

Learn GraphQL - Schema-First vs Code-First Approach

Episode 30 compares two approaches to building schemas: schema-first with SDL and code-first with libraries like Type-GraphQL and Pothos. You'll learn class-based schemas with decorators, dependency injection, Pothos plugins, and a guide to choosing based on your team and project needs.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

So far you've been writing schemas as separate SDL files — that's the schema-first approach. Episode 30 introduces the alternative: code-first, where the schema is generated directly from TypeScript code.

We'll compare the two philosophies, practice Type-GraphQL with decorators and dependency injection, look at Pothos as the modern successor, then close with a guide to choosing the right approach.

Schema-First Development

SDL as the Source of Truth

The schema-first approach (which you used in episodes 3-7) makes the SDL file the source of truth, then attaches resolvers to the schema:

Schema-first in SDL
type Query {
  users: [User!]!
}
 
type User {
  id: ID!
  username: String!
}

Its strengths: the schema is easy for non-programmers to review, frontend collaboration can start before the backend (via mocks, episode 29), and it's language-agnostic. Its weaknesses: duplication between SDL and TypeScript types, plus manually written resolver maps that are prone to type errors without codegen.

Supporting Tooling

Modern schema-first is usually paired with GraphQL Code Generator (episode 23) so TypeScript types are generated automatically from SDL — overcoming most of its weaknesses.

Code-First Development

Schema from Code

The code-first approach reverses the direction: you write TypeScript classes with decorators, and the GraphQL schema is generated from that code. No duplication — the TypeScript types are the single source of truth:

  • Type-GraphQL: class-based schema with decorators, the most mature.
  • Nexus: the code-first approach popular early on, now continued by Pothos.
  • Pothos: Nexus's successor with a powerful plugin system.
  • GraphQL-Modules: code-first schema modularization.

Type-GraphQL

Class-Based Schema with Decorators

Install Type-GraphQL
npm install type-graphql graphql class-validator reflect-metadata
JSObject type with a decorator
import { ObjectType, Field, ID } from "type-graphql";
 
@ObjectType()
export class User {
  @Field(() => ID)
  id: string;
 
  @Field()
  username: string;
}

Note that @Field() defines the schema field, and resolvers are also methods in classes:

JSResolver as a method
import { Resolver, Query, Arg } from "type-graphql";
 
@Resolver()
export class UserResolver {
  @Query(() => User)
  async user(@Arg("id") id: string) {
    return this.userService.findById(id);
  }
}

Dependency Injection

Class resolvers enable dependency injection — dependencies are injected into the constructor, making the code easy to test:

JSDependency injection
import { Service } from "typedi";
 
@Service()
@Resolver()
export class UserResolver {
  constructor(private userService: UserService) {}
}

Build the schema from all resolvers:

JSBuild a Type-GraphQL schema
import { buildSchema } from "type-graphql";
 
const schema = await buildSchema({
  resolvers: [UserResolver, PostResolver],
  container: Container,
});

With Container from typedi, the whole dependency graph is managed automatically. This is why Type-GraphQL is very popular for large, structured applications.

Pothos GraphQL

Modern Code-First with Plugins

Pothos is a newer code-first approach with advanced type safety and a plugin system:

Install Pothos
npm install @pothos/core
JSPothos schema
import SchemaBuilder from "@pothos/core";
 
const builder = new SchemaBuilder({});
 
builder.objectType("User", {
  fields: (t) => ({
    id: t.exposeID("id"),
    username: t.exposeString("username"),
    posts: t.field({
      type: [Post],
      resolve: (user) => db.posts.findByAuthor(user.id),
    }),
  }),
});
 
const schema = builder.toSchema();

Pothos excels at type inference — resolver types are automatically inferred from the implementation — and has plugins for prisma, relay, scope auth, and many more. Migration from Nexus is fairly straightforward because the writing patterns are similar.

Comparison and Selection Guide

When to Use Schema-First

  • Large teams with many non-programmer members who need to review the schema.
  • Frontend developed in parallel with the backend (the schema is needed first for mocks).
  • A graph shared across languages (for example Python and Go at once).

When to Use Code-First

  • TypeScript end-to-end, wanting automatically synchronized types without codegen.
  • Complex business logic that needs wrapping in structured classes.
  • Wanting dependency injection and high testability.
Decision summary
schema-first -> cross-team collaboration, mixed languages
code-first  -> full TypeScript, large structure, DI

Additional considerations: team size and project complexity. Small teams on full TypeScript tend to choose code-first; enterprises with many consumers and strict schema review often choose schema-first plus codegen. There's no absolutely wrong answer — consistency matters more than the choice itself.

Conclusion

Key takeaways:

  • Schema-first makes SDL the source of truth; best for cross-team collaboration.
  • Code-first generates the schema from TypeScript code, eliminating duplication.
  • Type-GraphQL uses classes, decorators, and dependency injection.
  • Pothos offers strong type inference and a plugin system.
  • Choose schema-first for collaboration and mixed languages; code-first for full TypeScript.
  • Approach consistency matters more than the approach itself.

In the next episode, episode 31, you'll learn about deploying GraphQL to production — deployment platforms like Vercel, Railway, and Render, containerization with multi-stage Docker, Kubernetes, serverless considerations like cold starts, environment and secrets management, and database migration strategies. Your API will step into production!

Learn GraphQL - Schema-First vs Code-First Approach | Learn GraphQL