npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

nestjs-gql-namespaces

v1.1.1

Published

Clean, type-safe nested namespace support for NestJS GraphQL with decorator-based API

Readme

nestjs-gql-namespaces

Clean, type-safe nested namespace support for NestJS GraphQL with decorator-based API.

Features

  • 🎯 Clean API: Export only 3 decorators (@NamespaceResolver, @NestedMutation, @NestedQuery)
  • 📦 Modular Design: Well-structured, maintainable codebase split into focused modules
  • 🔒 Type Safety: Full TypeScript support with comprehensive type definitions
  • 🚀 Zero Config: Works out of the box with sensible defaults
  • 🔧 Flexible: Support for both mutations and queries in the same resolver
  • 📖 Documentation: Comprehensive examples and migration guides

Installation

npm install nestjs-gql-namespaces
# or
yarn add nestjs-gql-namespaces

Quick Start

1. Basic Usage

import { NamespaceResolver, NestedMutation, NestedQuery } from 'nestjs-gql-namespaces';

@NamespaceResolver({ fieldName: 'user' })
export class UserResolver {
  @NestedMutation()
  async createUser(@Args('input') input: CreateUserInput): Promise<User> {
    // Creates: mutation { user { createUser(input: ...) { ... } } }
    return this.userService.create(input);
  }

  @NestedQuery()
  async profile(@Args('id') id: string): Promise<UserProfile> {
    // Creates: query { user { profile(id: ...) { ... } } }
    return this.userService.getProfile(id);
  }
}

2. Module Setup

import { Module } from '@nestjs/common';
import { NamespaceModule } from 'nestjs-gql-namespaces';
import { UserResolver } from './user.resolver';

@Module({
  imports: [
    NamespaceModule.forRoot(), // Add this to enable namespace resolvers
  ],
  providers: [UserResolver],
})
export class AppModule {}

Advanced Usage

Nested Namespaces

@NamespaceResolver({ 
  fieldName: 'profile',
  parentFieldName: 'user' // Creates user.profile namespace
})
export class UserProfileResolver {
  @NestedMutation()
  async updateBio(@Args('bio') bio: string): Promise<string> {
    // Creates: mutation { user { profile { updateBio(bio: ...) } } }
    return this.profileService.updateBio(bio);
  }
}

Custom Return Types

@NamespaceResolver({ fieldName: 'admin' })
export class AdminResolver {
  @NestedMutation(() => AdminResult) // Explicit return type
  async deleteUser(@Args('id') id: string): Promise<AdminResult> {
    return this.adminService.deleteUser(id);
  }

  @NestedQuery(() => [User]) // Array return type
  async getAllUsers(): Promise<User[]> {
    return this.userService.findAll();
  }
}

Mixed Mutation and Query Resolvers

@NamespaceResolver({ fieldName: 'auth' })
export class AuthResolver {
  @NestedMutation()
  async login(@Args('credentials') credentials: LoginInput): Promise<AuthResult> {
    return this.authService.login(credentials);
  }

  @NestedMutation()
  async logout(): Promise<boolean> {
    return this.authService.logout();
  }

  @NestedQuery()
  async me(): Promise<User> {
    return this.authService.getCurrentUser();
  }
}

Migration from Original Implementation

If you're migrating from the original nested.ts implementation:

Before (Original)

import { NestedMutation, NamespaceResolver } from '../common/graphql/nested';

@NamespaceResolver({
  fieldName: 'user',
  objectTypeName: 'UserMutations', // Manual type naming
  rootKind: 'Mutation'
})
export class UserResolver {
  @NestedMutation()
  async createUser(): Promise<User> { /* ... */ }
}

After (New Package)

import { NestedMutation, NamespaceResolver } from 'nestjs-gql-namespaces';

@NamespaceResolver({ 
  fieldName: 'user' // Simplified - type names auto-generated
})
export class UserResolver {
  @NestedMutation()
  async createUser(): Promise<User> { /* ... */ }
}

Key Changes

  • ✅ Cleaner import: nestjs-gql-namespaces instead of relative paths
  • ✅ Simplified configuration: No need for objectTypeName or rootKind
  • ✅ Better naming: Auto-generated type names follow conventions
  • ✅ Improved TypeScript support
  • ✅ Better error messages and warnings

Important: Entity Resolvers vs Namespace Resolvers

Namespace resolvers are only responsible for queries and mutations. Entity resolve fields (@ResolveField, @ResolveReference) should remain in a separate entity resolver outside the namespace resolver.

Correct Pattern: Separate Resolvers

import { Resolver, ResolveField, ResolveReference, Parent } from '@nestjs/graphql';
import { NamespaceResolver, NestedMutation, NestedQuery } from 'nestjs-gql-namespaces';

// Entity resolver - handles resolve fields, references, and federation concerns
@Resolver(() => User)
export class UserResolver {
  constructor(private readonly userService: UserService) {}

  @ResolveField(() => String)
  email(@Parent() user: User): string {
    // Resolve computed or related fields
    return user.email;
  }

  @ResolveField(() => Profile, { nullable: true })
  async profile(@Parent() user: User): Promise<Profile | null> {
    // Resolve related entities
    return this.userService.getProfile(user.id);
  }

  @ResolveReference()
  async resolveReference(reference: { __typename: string; id: string }): Promise<User> {
    // Apollo Federation entity resolution
    return this.userService.findById(reference.id);
  }
}

// Namespace resolver - handles only queries and mutations
@NamespaceResolver({ fieldName: 'user' })
export class UserNamespaceResolver {
  constructor(private readonly userService: UserService) {}

  @NestedMutation(() => User)
  async createUser(@Args('input') input: CreateUserInput): Promise<User> {
    return this.userService.create(input);
  }

  @NestedQuery(() => [User])
  async getAllUsers(): Promise<User[]> {
    return this.userService.findAll();
  }

  @NestedQuery(() => User)
  async getUserById(@Args('id') id: string): Promise<User> {
    return this.userService.findById(id);
  }
}

Why Separate Resolvers?

  • Entity Resolver: Handles GraphQL entity relationships, field resolution, and Apollo Federation concerns (@ResolveReference, @ResolveField)
  • Namespace Resolver: Provides organized API endpoints through nested mutations and queries (@NestedMutation, @NestedQuery)
  • Separation of Concerns: Each resolver has a distinct responsibility and purpose
  • Federation Support: Entity resolvers are essential for Apollo Federation to work properly

API Reference

@NamespaceResolver(options)

Class decorator that creates namespace resolvers.

Options:

  • fieldName: string - The GraphQL field name for this namespace
  • typeName?: string - Custom type name (auto-generated if not provided)
  • parentFieldName?: string - Parent namespace for nested resolvers
  • graphqlKind?: 'Mutation' | 'Query' - Override default behavior

@NestedMutation(returnType?, options?)

Method decorator for GraphQL mutations within a namespace.

Parameters:

  • returnType?: () => any - Return type function (inferred if not provided)
  • options?: { name?: string } - Decorator options

@NestedQuery(returnType?, options?)

Method decorator for GraphQL queries within a namespace.

Parameters:

  • returnType?: () => any - Return type function (inferred if not provided)
  • options?: { name?: string } - Decorator options

Generated GraphQL Schema

With the examples above, your GraphQL schema will look like:

type Mutation {
  user: UserMutations!
  auth: AuthMutations!
}

type Query {
  user: UserQueries!
  auth: AuthQueries!
}

type UserMutations {
  createUser(input: CreateUserInput!): User!
}

type UserQueries {
  profile(id: String!): UserProfile!
}

type AuthMutations {
  login(credentials: LoginInput!): AuthResult!
  logout: Boolean!
}

type AuthQueries {
  me: User!
}

Requirements

  • NestJS ^10.0.0
  • @nestjs/graphql ^12.0.0
  • TypeScript ^5.0.0
  • Node.js ^18.0.0

License

MIT

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.