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 🙏

© 2025 – Pkg Stats / Ryan Hefner

gqlopera

v1.0.2

Published

A CLI tool to generate individual GraphQL operation files from GraphQL APIs

Readme

GQLOpera

A fast, focused CLI tool that extracts individual GraphQL operation files from any GraphQL API. Perfect for feeding into GraphQL Codegen or other GraphQL tooling.

✨ What it does

  • Introspects your GraphQL API
  • Extracts all queries, mutations, and subscriptions
  • Generates individual .graphql files with complete selection sets
  • Organizes them in query/, mutation/, and subscription/ folders
  • Ready for Codegen: Generated files work seamlessly with GraphQL Code Generator

⚠️ Important Note: Recommended Workflow

Using generated hooks is no longer the recommended workflow.

  • Recommended approach is to use Fragment Colocation to declare each component’s data requirements near the component itself.
  • This approach keeps the number of data-fetching hooks low—ideally one per page—while avoiding network waterfalls and preventing overfetching..
  • The current recommendation is to only generate TypedDocumentNodes and use them with Apollo Client’s useQuery, useSuspenseQuery, useFragment, and useSuspenseFragment hooks.

However, GQLOpera still can be used to :

  • Quick project bootstrapping - rapidly generate a starting point for your GraphQL operations
  • API exploration - understand your schema structure and available operations
  • Migration projects - extract operations from existing APIs
  • Documentation - create a reference of all available operations

🚀 Quick Start

# Extract operations from your GraphQL API
npx gqlopera generate --endpoint http://localhost:4000/graphql --output ./graphql

# Or install globally
npm install -g gqlopera
gqlopera generate --endpoint https://api.example.com/graphql --output ./my-graphql

🔧 Configuration Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | endpoint | string | required | GraphQL API endpoint URL | | output | string | "graphql" | Output directory path | | headers | object | {} | HTTP headers for authentication | | excludeTypes | string[] | [] | Type names to exclude from generation | | watch | boolean | false | Watch for schema changes | | maxDepth | number | 5 | Maximum nesting depth for selection sets (1-10) | | maxFields | number | 50 | Maximum fields per type (5-100) | | circularRefs | string | "skip" | Circular reference handling: "skip", "silent", or "allow" | | shallowMode | boolean | false | Enable shallow mode (maxDepth=1) | | includeFields | string[] | [] | Only include specific fields | | excludeFields | string[] | [] | Exclude specific fields | | fieldDepthMap | object | {} | Custom depth per type | | circularRefDepth | number | 1 | Depth limit for circular references | | circularRefTypes | object | {} | Custom depth per circular type |

🎯 Shallow Data Options

For users who want minimal, focused data extraction (1-2 levels deep), GQLOpera provides several options:

Quick Shallow Mode

# Generate only 1 level deep
gqlopera generate --endpoint http://localhost:4000/graphql --shallow

# Or via config
{
  "shallowMode": true
}

Custom Depth Control

# Generate 2 levels deep
gqlopera generate --endpoint http://localhost:4000/graphql --max-depth 2

# Or via config
{
  "maxDepth": 2
}

Field Selection

# Only include specific fields
gqlopera generate --endpoint http://localhost:4000/graphql --include-fields "id,name,title,email"

# Or via config
{
  "includeFields": ["id", "name", "title", "email"]
}

Type-Specific Depth

{
  "fieldDepthMap": {
    "User": 2,      // User type: 2 levels deep
    "Post": 1,      // Post type: 1 level deep  
    "Comment": 0    // Comment type: no nesting
  }
}

Example Output (Shallow Mode)

# With maxDepth: 1
query GetUser($id: ID!) {
  getUser(id: $id) {
    id              # Level 1 - scalar
    name            # Level 1 - scalar
    email           # Level 1 - scalar
    profile         # Level 1 - object (no nesting)
    posts           # Level 1 - array (no nesting)
  }
}

# With includeFields: ["id", "name"]
query GetUser($id: ID!) {
  getUser(id: $id) {
    id
    name
  }
}

🎯 Circular Reference Depth Control

For schemas with circular references (like User ↔ Post), GQLOpera provides options to extract limited data instead of completely skipping:

Basic Circular Reference Control

# Allow circular refs with 2 levels of depth
gqlopera generate --endpoint http://localhost:4000/graphql --circular-refs allow --circular-ref-depth 2

# Or via config
{
  "circularRefs": "allow",
  "circularRefDepth": 2
}

Type-Specific Circular Reference Depth

{
  "circularRefs": "allow",
  "circularRefTypes": {
    "User": 2,      // User circular refs: 2 levels deep
    "Post": 1,      // Post circular refs: 1 level deep
    "Comment": 0    // Comment circular refs: no nesting
  }
}

Example Output with Circular Reference Depth

# Before: Circular ref completely skipped
query GetUser($id: ID!) {
  getUser(id: $id) {
    id
    name
    posts {
      id
      title
      author # Circular reference to User skipped
    }
  }
}

# After: Circular ref with limited depth
query GetUser($id: ID!) {
  getUser(id: $id) {
    id
    name
    posts {
      id
      title
      content
      author {
        id        # Circular ref allowed with depth limit
        name      # Only scalar fields included
        email     # No further nesting
      }
    }
  }
}

When to Use Circular Reference Depth

  • User ↔ Post relationships: Get basic user info in posts
  • Organization ↔ Department: Show department hierarchy
  • Category ↔ Product: Display category info in products
  • Any bidirectional relationships: Extract useful data without infinite loops

🎯 Output Structure

graphql/
├── query/
│   ├── getUsers.graphql
│   ├── getProfile.graphql
│   └── searchPosts.graphql
├── mutation/
│   ├── createUser.graphql
│   ├── updateProfile.graphql
│   └── deletePost.graphql
└── subscription/
    └── messageUpdates.graphql

📄 Generated Files

Each file contains a complete, executable GraphQL operation:

# query/getUsers.graphql
query GetUsers($offset: Int!, $limit: Int!) {
  getUsers(offset: $offset, limit: $limit) {
    items {
      id
      username
      email
      profile {
        firstName
        lastName
        avatar
      }
    }
    totalCount
  }
}

⚙️ Configuration

Create a gqlopera.config.json file:

{
  "endpoint": "http://localhost:4000/graphql",
  "output": "graphql",
  "headers": {
    "Authorization": "Bearer YOUR_TOKEN"
  },
  "excludeTypes": ["InternalType"],
  "watch": false,
  "maxDepth": 5,
  "maxFields": 50,
  "circularRefs": "skip"
}

Or generate one interactively:

gqlopera init

🔄 Handling Complex Schemas

GQLOpera intelligently handles complex GraphQL schemas with circular reference detection and depth management:

🌀 Circular Reference Detection

GraphQL schemas often contain circular references where types reference each other, creating potential infinite loops. GQL Operations uses tracking to detect and handle these safely:

Detection Strategy:

# Before: Infinite loop potential
type User {
  id: ID!
  posts: [Post!]!
}

type Post {
  id: ID!
  author: User!  # Circular reference back to User
}

# After: Smart handling with comments
query GetUser($id: ID!) {
  getUser(id: $id) {
    id
    name
    email
    posts {
      id
      title
      content
      author # Circular reference to User skipped
    }
  }
}

📊 Multi-Level Depth Control

Depth Tracking Algorithm:

  • Level 0: Root operation field
  • Level 1: Direct properties of root
  • Level 2: Nested objects within properties
  • Level 3+: Deep nesting controlled by maxDepth

Example with maxDepth: 5:

query GetOrganization($id: ID!) {
  getOrganization(id: $id) {           # Level 0
    id                                 # Level 1 - scalar
    name                               # Level 1 - scalar
    departments {                      # Level 1 - object
      id                               # Level 2 - scalar
      name                             # Level 2 - scalar
      manager {                        # Level 2 - object  
        id                             # Level 3 - scalar
        profile {                      # Level 3 - object
          settings {                   # Level 4 - object
            theme                      # Level 5 - scalar
            preferences # Max depth (5) reached
          }
        }
      }
    }
  }
}

🎛️ Advanced Configuration Options

Granular Control:

{
  "maxDepth": 7,           // Allow deeper nesting for complex schemas
  "maxFields": 25,         // Balance between completeness and readability
  "circularRefs": "skip"   // Have control here
}

🚦 Field Limiting

The maxFields setting prevents operations from becoming too large by limiting how many fields are included per GraphQL type.

⚠️ Important: No Smart Prioritization

  • Takes the first N fields in schema definition order
  • No prioritization of "important" fields like id or name
  • No filtering of "less important" fields like timestamps
  • Field order depends entirely on how the GraphQL server defines its schema

Example with maxFields: 5:

# Original User type has 12 fields
query GetUser($id: ID!) {
  user(id: $id) {
    id              # Field 1 ✅ Included
    email           # Field 2 ✅ Included  
    firstName       # Field 3 ✅ Included
    lastName        # Field 4 ✅ Included
    avatar          # Field 5 ✅ Included
    # ... 7 more fields (limited by maxFields: 5)
    
    # ❌ These fields were dropped:
    # createdAt, updatedAt, profile, preferences, 
    # organization, permissions, lastLoginAt
  }
}

When Field Limiting Activates:

  • User type has 50+ fields → Only first 50 included
  • Product type has 100+ fields → Only first 100 included
  • Automatically adds comment showing how many fields were omitted

Better Alternatives:

  • Use excludeTypes to skip problematic types entirely
  • Increase maxFields if you need more fields
  • Use maxDepth to control nesting instead of field count

Example Output:

query GetProduct($id: ID!) {
  getProduct(id: $id) {
    id                    # Always included - primary key
    name                  # Essential scalar fields
    price
    description
    category {
      id                  # Simple reference
      name
      parent # Circular reference to Category skipped
    }
    reviews {
      # ... 15 more fields (limited by maxFields: 20)
    }
  }
}

## 🛠️ CLI Commands

### Generate Operations
```bash
gqlopera generate [options]

Options:
  -e, --endpoint <url>     GraphQL endpoint URL
  -o, --output <path>      Output directory (default: "graphql") 
  -c, --config <path>      Config file path (default: "gqlopera.config.json")
  -h, --headers <json>     HTTP headers as JSON string
  --watch                  Watch for schema changes and regenerate
  --verbose                Enable verbose logging
  --max-depth <number>     Maximum depth for field expansion (default: 5)
  --max-fields <number>    Maximum fields per type (default: 50)
  --shallow                Enable shallow mode (maxDepth=1)
  --include-fields <fields> Comma-separated list of fields to include
  --exclude-fields <fields> Comma-separated list of fields to exclude
  --circular-ref-depth <number> Depth limit for circular references (default: 1)
  --circular-refs <mode>   Circular reference handling: skip, silent, or allow (default: skip)

Initialize Config

gqlopera init

Validate Endpoint

gqlopera validate

🔗 Perfect for GraphQL Codegen

Use with GraphQL Code Generator to generate types and hooks:

# codegen.yml
overwrite: true
schema: "http://localhost:4000/graphql"
documents: "./graphql/**/*.graphql"
generates:
  src/generated/graphql.tsx:
    plugins:
      - "typescript"
      - "typescript-operations"
      - "typescript-react-apollo"

🚀 Use Cases

  • Ready for Codegen: Generated document files work directly with GraphQL Code Generator
  • Testing: Use individual operations in your tests
  • Documentation: Clean, organized operation files
  • Migration: Extract operations from existing APIs
  • Development: Better organization of GraphQL operations

📋 Requirements

  • Node.js 16+
  • Access to a GraphQL endpoint (with introspection enabled)

📄 License

GPL-2.0


Extract → Organize → Generate 🚀