Adding Features
This guide walks you through the process of adding new features to Nitro GraphQL, from initial development to submitting a pull request.
Before You Start
- Check existing issues - Search for related issues or discussions
- Open an issue - Discuss your feature idea before implementing
- Get feedback - Wait for maintainer feedback on larger features
- Fork the repo - Create your own fork to work in
Development Process
1. Set Up Your Environment
Follow the Development Setup guide to get started.
# Clone your fork
git clone https://github.com/YOUR_USERNAME/nitro-graphql.git
cd nitro-graphql
# Install dependencies
pnpm install
# Start development mode
pnpm dev2. Create a Feature Branch
Use descriptive branch names:
# For new features
git checkout -b feat/your-feature-name
# For bug fixes
git checkout -b fix/bug-description
# For documentation
git checkout -b docs/update-description
# For maintenance
git checkout -b chore/task-descriptionExamples:
feat/custom-scalarsfeat/graphql-shield-integrationfix/type-generation-windowsdocs/federation-guide
3. Implement Your Feature
File Organization
Place your code in the appropriate location:
src/
├── index.ts # Add module setup code here
├── types/
│ └── index.ts # Add new type definitions
├── utils/
│ └── your-util.ts # Add utility functions
├── routes/
│ └── your-route.ts # Add new route handlers
└── ecosystem/
└── your-integration.ts # Add framework integrationsCode Style
Follow these guidelines:
TypeScript:
// ✅ Use explicit types for public APIs
// ✅ Use type imports when possible
import type { NitroConfig } from 'nitropack'
export function generateTypes(options: GenerateOptions): Promise<void>
// ✅ Prefer named exports
export function myFunction() {}
// ❌ Avoid default exports (except for route handlers)
export default myFunction // Don't do thisNaming Conventions:
- Functions:
camelCase-generateTypes,scanSchemas - Types/Interfaces:
PascalCase-GraphQLConfig,ResolverOptions - Constants:
UPPER_SNAKE_CASE-DEFAULT_ENDPOINT,MAX_RETRIES - Files:
kebab-case-type-generation.ts,path-resolver.ts
Code Organization:
// Order your code logically:
import type { NitroConfig } from 'nitropack'
// 1. Imports
import { defineNitroModule } from 'nitropack/kit'
// 2. Types and interfaces
export interface FeatureOptions {
enabled: boolean
}
// 3. Constants
const DEFAULT_OPTIONS: FeatureOptions = {
enabled: true
}
// 4. Helper functions
function validateOptions(options: FeatureOptions) {
// ...
}
// 5. Main exported functions
export function setupFeature(options: FeatureOptions) {
// ...
}Testing Your Changes
Test your feature in multiple environments:
Nitro Playground:
# Terminal 1
pnpm dev
# Terminal 2
pnpm playground:nitroNuxt Playground:
# Terminal 1
pnpm dev
# Terminal 2
pnpm playground:nuxtAdd test cases to the playground:
// playgrounds/nitro/server/graphql/test.resolver.ts
export const testQueries = defineQuery({
testMyFeature: async () => {
// Test your feature
return { success: true }
}
})Type Safety
Ensure your feature is fully typed:
// Add types to src/types/index.ts
export interface MyFeatureOptions {
option1: string
option2?: number
}
// Extend module configuration
export interface GraphQLOptions {
// ... existing options
myFeature?: MyFeatureOptions
}4. Add Documentation
Every feature needs documentation:
Update Relevant Guides
Add documentation to .docs/guide/:
# Your Feature Name
Brief description of what your feature does.
## Usage
\`\`\`typescript
// Code example
export default defineNitroConfig({
modules: ['nitro-graphql'],
graphql: {
myFeature: {
option1: 'value'
}
}
})
\`\`\`
## Options
### `option1`
- Type: `string`
- Required: Yes
- Description: Description of option1
### `option2`
- Type: `number`
- Default: `10`
- Description: Description of option2
## Examples
### Example 1: Basic Usage
\`\`\`typescript
// Example code
\`\`\`
### Example 2: Advanced Usage
\`\`\`typescript
// Example code
\`\`\`
## Best Practices
- Best practice 1
- Best practice 2Add to API Reference
If your feature adds new APIs, document them in .docs/api/:
# Your API
## `yourFunction()`
Description of the function.
### Parameters
- `param1` - Type and description
- `param2` - Type and description
### Returns
Description of return value.
### Example
\`\`\`typescript
import { yourFunction } from 'nitro-graphql/utils'
yourFunction(param1, param2)
\`\`\`Add Examples
Create practical examples in .docs/examples/:
# Example: Using Your Feature
This example shows how to use [Your Feature] in a real-world scenario.
## Setup
\`\`\`bash
pnpm add nitro-graphql
\`\`\`
## Implementation
\`\`\`typescript
// Full working example
\`\`\`
## Explanation
Explain the key parts of the example.5. Update CLAUDE.md
If your feature changes development workflows or architecture, update /Users/code/Work/pb/nitro-graphql/CLAUDE.md:
## Your Feature Section
Description of your feature and how it fits into the architecture.
### Usage
\`\`\`typescript
// Example
\`\`\`
### Key Files
- `src/your-file.ts` - DescriptionPull Request Process
1. Prepare Your Changes
Before submitting:
# Run linter
pnpm lint:fix
# Build the project
pnpm build
# Test in playgrounds
pnpm playground:nitro
pnpm playground:nuxt2. Commit Your Changes
Use Conventional Commits:
Format:
type(scope): description
[optional body]
[optional footer]Types:
feat:- New featurefix:- Bug fixdocs:- Documentation onlystyle:- Code style (formatting, semicolons, etc.)refactor:- Code refactoringperf:- Performance improvementstest:- Adding testschore:- Maintenance tasks
Examples:
git commit -m "feat: add custom scalar support"
git commit -m "feat(codegen): add external service type generation"
git commit -m "fix: resolve Windows path issues in type generation"
git commit -m "docs: add Apollo Federation guide"
git commit -m "refactor(scanner): improve file discovery performance"Good commit messages:
feat: add GraphQL shield integration
- Add shield directive support
- Update type generation for shield
- Add examples and documentation
Closes #123Bad commit messages:
update stuff
fix bug
wip
changes3. Push to Your Fork
git push origin feat/your-feature-name4. Create Pull Request
PR Title
Use the same format as commit messages:
feat: add custom scalar support
fix: resolve type generation issues on Windows
docs: improve federation guidePR Description
Fill out the template completely:
## Description
Clear description of what this PR does and why.
## Related Issues
Closes #123
Relates to #456
## Changes
- Added X feature
- Fixed Y bug
- Updated Z documentation
## Testing
- [x] Tested in Nitro playground
- [x] Tested in Nuxt playground
- [x] Tested in Federation playground (if applicable)
- [x] Added/updated tests
- [x] Documentation updated
## Screenshots (if applicable)
Add screenshots for UI changes
## Breaking Changes
List any breaking changes and migration guide
## Checklist
- [x] Code follows project style guidelines
- [x] Self-review completed
- [x] Comments added for complex logic
- [x] Documentation updated
- [x] No new warnings generatedReview Process
- Automated Checks - CI must pass
- Maintainer Review - Wait for feedback
- Address Comments - Make requested changes
- Approval - Get approval from maintainers
- Merge - Maintainer will merge your PR
5. Respond to Feedback
When you receive review comments:
# Make changes based on feedback
# ... edit files ...
# Commit changes
git add .
git commit -m "refactor: address review feedback"
# Push updates
git push origin feat/your-feature-nameFeature Examples
Example 1: Adding a New Utility Function
// src/utils/my-utility.ts
import type { GraphQLSchema } from 'graphql'
/**
* Utility to validate GraphQL schema
*/
export function validateSchema(schema: GraphQLSchema): boolean {
// Implementation
return true
}
// Export from main utils
// src/utils/index.ts
export { validateSchema } from './my-utility'Add to package.json exports:
{
"exports": {
"./utils": {
"types": "./dist/utils/index.d.ts",
"import": "./dist/utils/index.js"
}
}
}Example 2: Adding Configuration Option
// src/types/index.ts
export interface GraphQLOptions {
// ... existing options
/**
* Enable schema validation
* @default true
*/
validateSchema?: boolean
}
// src/index.ts
export default defineNitroModule({
setup(nitro, options) {
const validateSchema = options.validateSchema ?? true
if (validateSchema) {
// Implement validation
}
}
})Example 3: Adding a New Route Handler
// src/routes/my-endpoint.ts
import { defineEventHandler } from 'h3'
export default defineEventHandler((event) => {
return {
message: 'My endpoint'
}
})
// Register in src/index.ts
nitro.options.handlers.push({
route: '/api/my-endpoint',
handler: resolver.resolve('./routes/my-endpoint')
})Common Pitfalls
Avoid These Mistakes
Not testing in playgrounds
- Always test your changes in both Nitro and Nuxt playgrounds
Breaking existing features
- Ensure backward compatibility
- Add deprecation warnings for breaking changes
Missing documentation
- Every feature needs docs
- Add examples and use cases
Poor type safety
- Add proper TypeScript types
- Don't use
anyunless absolutely necessary
Not following code style
- Run
pnpm lint:fixbefore committing - Follow existing patterns
- Run
Huge pull requests
- Keep PRs focused and small
- Split large features into multiple PRs
Not responding to reviews
- Address feedback promptly
- Ask questions if something is unclear
Feature Checklist
Before submitting your PR, ensure:
- [ ] Code is properly typed
- [ ] Tests added/updated (when applicable)
- [ ] Documentation written
- [ ] Examples added
- [ ] Tested in Nitro playground
- [ ] Tested in Nuxt playground
- [ ] Linter passes (
pnpm lint) - [ ] Build succeeds (
pnpm build) - [ ] Commit messages follow conventions
- [ ] PR description is complete
- [ ] No breaking changes (or documented)
- [ ] CLAUDE.md updated (if needed)
Getting Help
If you need help while developing:
- Questions: Ask in GitHub Discussions
- Bugs: Report in GitHub Issues
- Architecture: Review Architecture Guide
- Setup Issues: Check Development Setup
Next Steps
- Review the Architecture guide
- Learn about Documentation standards
- Check out existing PRs for examples