FolderStructure.dev

NestJS GraphQL Project Structure

GraphQL API using code-first approach with Apollo Server. Schema generated from TypeScript decorators.

#nestjs #typescript #nodejs #graphql #apollo #code-first
PNGPDF

Project Directory

myproject/
src/
Application source
main.ts
Bootstrap app
app.module.ts
Root module, GraphQL setup
schema.gql
Auto-generated schema
config/
Configuration
configuration.ts
graphql.config.ts
Apollo options
common/
Shared utilities
scalars/
date.scalar.ts
Custom Date type
decorators/
current-user.decorator.ts
guards/
gql-auth.guard.ts
GraphQL context guard
modules/
Feature modules
users/
users.module.ts
users.resolver.ts
Query/Mutation handlers
users.service.ts
dto/
create-user.input.ts
@InputType()
update-user.input.ts
entities/
user.entity.ts
@ObjectType() + @Entity()
auth/
auth.module.ts
auth.resolver.ts
auth.service.ts
database/
database.module.ts
migrations/
.gitkeep
test/
app.e2e-spec.ts
jest-e2e.json
nest-cli.json
tsconfig.json
tsconfig.build.json
package.json
.env.example
.eslintrc.js
.prettierrc
.gitignore
README.md

Why This Structure?

Code-first GraphQL generates the schema from TypeScript decorators—no separate .graphql files to maintain. Entities double as @ObjectType() and @Entity(), reducing duplication. Apollo Playground provides interactive documentation.

Key Directories

  • src/modules/*/-Feature modules with resolvers instead of controllers
  • *.resolver.ts-GraphQL query/mutation handlers (replaces controllers)
  • dto/*.input.ts-@InputType() classes for mutations
  • entities/*.entity.ts-Dual-decorated: @ObjectType() + @Entity()
  • schema.gql-Auto-generated, commit for reference only

Getting Started

  1. npm install
  2. cp .env.example .env (set DATABASE_URL)
  3. npm run migration:run
  4. npm run start:dev
  5. Visit http://localhost:3000/graphql for Apollo Playground

Key Decorators

  • @Resolver()-Marks class as resolver for a type
  • @Query()-Defines a GraphQL query
  • @Mutation()-Defines a GraphQL mutation
  • @ObjectType()-Defines GraphQL output type
  • @InputType()-Defines GraphQL input for mutations
  • @Field()-Exposes property in schema

When To Use This

  • Complex data relationships with nested queries
  • Clients needing flexible data fetching
  • Mobile apps with bandwidth constraints
  • Aggregating multiple data sources
  • Teams preferring type-first API design

Trade-offs

  • Caching complexity-HTTP caching harder than REST—use Apollo cache
  • N+1 queries-Use DataLoader for batching related data
  • Learning curve-GraphQL concepts on top of NestJS patterns