NextRush
Community

Contributing

How to contribute to NextRush — from setup to pull request.

This guide covers setup, workflow, and conventions for contributing to NextRush.


Prerequisites

RequirementVersion
Node.js>=22.0.0
pnpm10.29.3 (managed via corepack)
GitAny recent version

The project uses corepack to manage pnpm. Node.js >=22 ships with corepack built-in.


Quick Start

Fork and Clone

# Fork on GitHub, then:
git clone https://github.com/YOUR_USERNAME/nextrush.git
cd nextrush

Install Dependencies

# Enable corepack (ships with Node.js >=22)
corepack enable

# Install project dependencies (uses pnpm@10.29.3 from packageManager field)
pnpm install

Build Packages

pnpm build

Run Tests

pnpm test

Create Branch

git checkout -b feat/your-feature

Branch prefix should match the commit type: feat/, fix/, docs/, refactor/, test/, perf/, chore/.


Repository Structure

NextRush is a monorepo using Turborepo and pnpm workspaces:

nextrush/
├── packages/
│   ├── core/           # @nextrush/core
│   ├── router/         # @nextrush/router
│   ├── di/             # @nextrush/di
│   ├── decorators/     # @nextrush/decorators
│   ├── errors/         # @nextrush/errors
│   ├── types/          # @nextrush/types
│   ├── runtime/        # @nextrush/runtime
│   ├── dev/            # @nextrush/dev
│   ├── nextrush/       # nextrush (meta package)
│   ├── adapters/       # Platform adapters
│   │   ├── node/       # @nextrush/adapter-node
│   │   ├── bun/        # @nextrush/adapter-bun
│   │   ├── deno/       # @nextrush/adapter-deno
│   │   └── edge/       # @nextrush/adapter-edge
│   ├── middleware/     # Middleware packages
│   │   ├── cors/
│   │   ├── body-parser/
│   │   └── ...
│   └── plugins/        # Plugin packages
│       ├── controllers/
│       ├── logger/
│       └── ...
├── apps/
│   ├── docs/           # Documentation site
│   └── playground/     # Testing playground
├── draft/              # Architecture documents
└── turbo.json          # Turborepo config

Development Workflow

Running Commands

View all available commands
# Build all packages
pnpm build

# Run all tests
pnpm test

# Run tests for specific package
pnpm --filter @nextrush/core test

# Type check
pnpm typecheck

# Lint
pnpm lint

# Lint and auto-fix
pnpm lint:fix

# Format
pnpm format

# Check formatting (CI)
pnpm format:check

# Run tests with coverage
pnpm test:coverage

# Clean build artifacts
pnpm clean

Package Development

When working on a specific package:

cd packages/core

# Run tests in watch mode
pnpm test:watch

# Build package
pnpm build

# Type check
pnpm typecheck

Documentation

cd apps/docs

# Start dev server
pnpm dev

# Build docs
pnpm build

Code Style

TypeScript

  • Strict mode: Always use strict TypeScript
  • No any: Avoid any type; use unknown if needed
  • Explicit types: Export interfaces and types explicitly
  • ESM: Use ES modules (import/export)

File Structure

// 1. Type imports
import type { Context, Middleware } from '@nextrush/types';

// 2. Value imports
import { compose } from './middleware';

// 3. Types/interfaces (export first)
export interface MyOptions {
  enabled: boolean;
}

// 4. Implementation
export function myFunction(options: MyOptions): void {
  // ...
}

Naming Conventions

TypeConventionExample
Fileskebab-casebody-parser.ts
Types/InterfacesPascalCaseRouterOptions
FunctionscamelCasecreateRouter
ConstantsUPPER_SNAKEDEFAULT_TIMEOUT
Private fieldsunderscore prefix_internal

Comments

// Good: Explain WHY, not WHAT
// Rate limit is per-IP to prevent abuse from single sources
const rateLimit = createRateLimiter({ keyGenerator: (ctx) => ctx.ip });

// Bad: Obvious comment
// Create router
const router = createRouter();

Testing

Test Structure

import { describe, it, expect, beforeEach } from 'vitest';

describe('MyFeature', () => {
  describe('basic functionality', () => {
    it('should do something', () => {
      expect(result).toBe(expected);
    });
  });

  describe('edge cases', () => {
    it('should handle empty input', () => {
      // ...
    });
  });

  describe('error cases', () => {
    it('should throw on invalid input', () => {
      expect(() => fn(null)).toThrow();
    });
  });
});

Test Guidelines

  • One assertion per test when possible
  • Descriptive names: should return 404 when user not found
  • Test behavior, not implementation
  • No mocking unless necessary

Coverage Requirements

MetricThreshold
Lines90%
Functions90%
Statements90%
Branches85%
  • All exports: Every public function tested
  • Error paths: All error scenarios covered

Run pnpm test:coverage to verify thresholds before submitting.


Pull Request Process

Before Submitting

  • Tests pass: pnpm test
  • Coverage meets thresholds: pnpm test:coverage
  • Types check: pnpm typecheck
  • Lint passes: pnpm lint
  • Formatting correct: pnpm format:check
  • Documentation updated (if needed)
  • Changeset added (if needed)

PR Title Format

type(scope): description

Examples:
feat(router): add wildcard route support
fix(core): handle async middleware errors
docs(guides): add authentication guide
chore(deps): update typescript to 5.x

Types

  • feat: New feature
  • fix: Bug fix
  • docs: Documentation
  • chore: Maintenance
  • refactor: Code change without feature/fix
  • test: Adding tests
  • perf: Performance improvement

Review Process

  1. Automated checks — CI must pass
  2. Code review — At least one approval
  3. Documentation — Updated if needed
  4. Merge — Squash and merge

Adding a New Package

Create Package Structure

mkdir -p packages/middleware/my-middleware/src
cd packages/middleware/my-middleware

Create package.json

{
  "name": "@nextrush/my-middleware",
  "version": "3.0.4",
  "description": "Description here",
  "type": "module",
  "main": "./dist/index.js",
  "types": "./dist/index.d.ts",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/index.js"
    }
  },
  "scripts": {
    "build": "tsup",
    "test": "vitest run",
    "test:watch": "vitest",
    "typecheck": "tsc --noEmit"
  },
  "dependencies": {
    "@nextrush/types": "workspace:*"
  },
  "devDependencies": {
    "typescript": "^5.9.3",
    "vitest": "^4.0.18"
  }
}

Create tsconfig.json

{
  "extends": "../../../tsconfig.base.json",
  "compilerOptions": {
    "outDir": "dist",
    "rootDir": "src"
  },
  "include": ["src"]
}

Create tsup.config.ts

import { defineConfig } from 'tsup';

export default defineConfig({
  entry: ['src/index.ts'],
  format: ['esm'],
  dts: true,
  clean: true,
  sourcemap: true,
});

Implement and Test

// src/index.ts
import type { Middleware } from '@nextrush/types';

export interface MyMiddlewareOptions {
  // ...
}

export function myMiddleware(options?: MyMiddlewareOptions): Middleware {
  return async (ctx, next) => {
    // Implementation
    await next();
  };
}

Documentation Contributions

Writing Guidelines

  • Human-first: Explain concepts before code
  • Show examples: Include runnable code
  • Be accurate: Test all code examples
  • Keep current: Update when APIs change

Structure

Every doc page should have:

  1. Title and description
  2. Problem explanation
  3. Solution overview
  4. Code examples
  5. Common issues
  6. Next steps

See the Documentation Instructions for detailed guidelines.


Getting Help

  • Questions: Open a Discussion
  • Bugs: Open an Issue
  • Code review: Request review on your PR
First-time contributors: Look for issues labeled good first issue.

Questions?

If anything in this guide is unclear, open a Discussion. Contributions of all sizes are welcome.

On this page