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

@teispace/next-maker

v3.0.6

Published

Create a new Teispace Next.js application with interactive setup.

Readme

@teispace/next-maker

A CLI that scaffolds Next.js 16+ applications (TypeScript, Tailwind v4, Biome, Pino, Zod, Redux Toolkit, next-intl, Vitest) and co-generates feature-based architecture — pages, layouts, components, hooks, Redux slices, API services, locales, providers, env vars, and tests. Ships a manifest-driven doctor and remove for ongoing maintenance.

Installation

Using npx (Recommended)

npx @teispace/next-maker <command> [args] [options]

Global Installation

npm install -g @teispace/next-maker
next-maker <command> [args] [options]

Commands at a glance

| Category | Command | Purpose | | --- | --- | --- | | Lifecycle | init [name] | Create a new Next.js application | | Lifecycle | setup [options] | Add features to an existing project (retrofit) | | Lifecycle | doctor [options] | Diagnose drift against known feature manifests | | Lifecycle | remove <feature> | Reverse a feature install (uses the manifest) | | Routing | page <name> | Generate a page/route | | Routing | layout <segment> | Generate a nested layout.tsx | | UI | component <name> | Shared component with auto-wired barrel exports | | State | feature <name> | Full feature module (DDD) | | State | slice <name> | Redux Toolkit slice (auto-registers in rootReducer) | | State | service <name> | API service (axios/fetch, optional CRUD) | | State | provider <name> | Context provider with RootProvider auto-wiring | | Config | env <NAME> | Add an env var (schema + .env.example + .env) | | Config | locale [code] | Add a new language/locale | | Code | hook <name> | Custom React hook | | Code | test <file> | Sibling test stub for a component/hook/slice | | Assets | favicon | Generate favicon.ico (and optionally PWA / OG / Apple icons) from a source image |

Run npx @teispace/next-maker <command> --help for the full option list of any command.


Lifecycle commands

init — Create a New App

npx @teispace/next-maker init [project-name] [options]

| Flag | Effect | | --- | --- | | -y, --yes | Skip every prompt and bootstrap with the recommended production defaults (see below) | | --package-manager <pm> | Override the package manager (npm | yarn | pnpm | bun). Works with or without --yes. |

# Interactive (default)
npx @teispace/next-maker init my-app

# One-shot opinionated install
npx @teispace/next-maker init my-app --yes

# One-shot with a different package manager
npx @teispace/next-maker init my-app -y --package-manager pnpm

--yes defaults — every architecture feature on, heavyweight integrations off:

| | | | --- | --- | | package manager | yarn | | HTTP client | fetch | | dark mode, redux, i18n, tests, react-compiler | ✅ on | | pre-commit hooks, commitizen, copy .env | ✅ on | | WebSocket (requires Redux), docker, GitHub Actions, bundle-analyzer, community files (CODE_OF_CONDUCT etc.) | ⏭ off |

Anything you don't want? next-maker remove <feature> after init.

The starter at teispace/nextjs-starter is cloned via degit and trimmed to match your prompt answers. The cleanup step strips opted-out features so the generated project compiles end-to-end on first install.

Interactive prompts:

| Section | Prompts | | --- | --- | | Identity | project name, description, author, version, support email, package manager, GitHub repo / issues / homepage | | Architecture | HTTP client (axios / fetch / both / none), dark mode, Redux Toolkit, WebSocket (requires Redux), i18n, testing, React Compiler, Bundle Analyzer | | Tooling | community files (CODE_OF_CONDUCT, CONTRIBUTING, SECURITY), README, Docker, CI/CD, pre-commit hooks (Husky/Commitlint/Lint-staged), Commitizen, copy .env.example.env | | Templates | keep GitHub issue/PR templates? include react-secure-storage? |

Always shipped:

  • Next.js 16+ with App Router
  • TypeScript (strict mode)
  • Tailwind CSS v4
  • Biome (single-tool lint + format)
  • Pino structured logger with redaction
  • Zod-validated env schema in src/lib/env/
  • Feature-based DDD architecture
  • Dual HTTP clients (fetchClient + axiosClient) on a shared foundation: two entry points (@/lib/utils/http universal, @/lib/utils/http/server for Server Components), automatic X-Request-Id correlation, single parseApiError pipeline, cookie-mode auth by default, typed query params via { params }. A build-time __bundle-sentinel__ rejects future regressions of the universal/server split.
  • WebSocket transport — opt-in via the ws prompt (requires Redux): typed socket.io-client wrapper, lazy singleton, useWsEvent / useWsEmit / useWsStatus hooks, Redux bridge into a dedicated (non-persisted) wsReducer. Cookie-mode auth by default; browser-only (SSR throws).
  • Hardened security headers in next.config.ts
  • scripts/sync-env.ts and scripts/check-deprecated.ts (used by the validate chain)

setup — Retrofit a feature

Add a feature to an existing project (one that wasn't generated by init, or one created before a feature existed).

npx @teispace/next-maker setup [options]

| Flag | What it does | | --- | --- | | --http-client | Adds the axios and/or fetch Result-based clients under src/lib/utils/http/ | | --dark-theme | Installs @teispace/next-themes and adds CustomThemeProvider | | --redux | Redux Toolkit + react-redux + redux-persist, StoreProvider, src/store | | --ws | WebSocket transport — socket.io-client@^4.8.3, src/lib/utils/ws/ subtree, non-persisted wsReducer, attachWsBridge mount in StoreProvider. Requires --redux to be installed first. | | --i18n | next-intl + [locale] routing + proxy.ts + RootProvider wiring | | --tests | Vitest + React Testing Library + jsdom + test/test-utils.tsx | | --react-compiler | reactCompiler: true in next.config.ts + babel-plugin-react-compiler | | --bundle-analyzer | Wraps the default export with withBundleAnalyzer and adds the analyze script | | --security-headers | Injects the hardened headers block into next.config.ts (DNS prefetch, HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, X-XSS-Protection) | | --validate-scripts | Drops in scripts/sync-env.ts + scripts/check-deprecated.ts and wires env:sync, check:deprecated, type-check, and the validate chain (PM-aware) | | --commitizen | Writes .czrc, adds commit script, installs commitizen + cz-conventional-changelog |

Run setup without flags for an interactive picker.

# Interactive
npx @teispace/next-maker setup

# Specific feature
npx @teispace/next-maker setup --redux
npx @teispace/next-maker setup --ws            # adds WebSocket layer (run after --redux)
npx @teispace/next-maker setup --security-headers
npx @teispace/next-maker setup --validate-scripts

Every setup operation is idempotent — re-running is a no-op on already-installed parts and a fix-up on missing parts.


doctor — Drift detection

doctor walks every feature manifest, asks "is this installed?" and (if yes) "are all of its parts present?". Drift is reported per feature.

npx @teispace/next-maker doctor [options]

| Flag | Behaviour | | --- | --- | | --fix | Re-runs apply() for every drifted feature (idempotent — safe to retry) | | --feature <id> | Only check one manifest (e.g. redux, security-headers) | | --json | Machine-readable output for CI |

Exit code is 0 on a clean report and 1 when drift is found — next-maker doctor --json makes a useful CI gate.

# Human report
npx @teispace/next-maker doctor

# Fix everything that drifted
npx @teispace/next-maker doctor --fix

# CI
npx @teispace/next-maker doctor --json > health.json

Sample output:

🩺 Project Doctor

  ✓ Security Headers
  ! Validation Scripts (2 issues)
      • missing file: scripts/sync-env.ts
      • missing script: validate
  — Redux Toolkit (not installed)
  ✓ Internationalization

1 clean, 1 drifted, 1 not installed

Run with --fix to re-apply drifted features.

Manifests live under src/manifests/; each one declares the files, packages, scripts, and code blocks the feature consists of. Adding a manifest for a new feature is a single file — doctor and remove automatically pick it up.


remove — Reverse an install

Symmetric to setup. Uses the feature manifest to compute the reversal: deletes generated files, strips code blocks (when a removePattern is recorded), removes scripts, uninstalls packages.

npx @teispace/next-maker remove <feature> [options]

| Flag | Behaviour | | --- | --- | | --dry-run | Print the planned changes without writing | | -y, --yes | Skip the confirmation prompt |

Auto-removed when possible: provider chain unwraps (<NextIntlClientProvider>, <StoreProvider>, <CustomThemeProvider>), the withNextIntl(...) and bundleAnalyzer(...) wraps in next.config.ts, and their orphan import statements. The transforms are conservative — if the file shape has drifted from the canonical pattern (e.g. a multi-line opening tag, no matching close at the same indent), the runner bails out and surfaces it as manual cleanup rather than corrupting your code.

remove will never recursively delete a directory that may hold user-authored contentsrc/app/[locale]/ (your pages), src/i18n/ (your translations), src/store/ (your slices), src/lib/utils/http/ (your service code), and test/ (your helpers) are flagged in the manifest with containsUserContent: true and surface as manual-cleanup with a hint. Move what you want to keep, then rm -rf the rest by hand.

# Preview the effect
npx @teispace/next-maker remove redux --dry-run

# Apply with confirmation
npx @teispace/next-maker remove security-headers

# Non-interactive
npx @teispace/next-maker remove validate-scripts --yes

Sample plan:

🗑  Remove Validation Scripts

Planned changes:
  - delete file: scripts/sync-env.ts
  - delete file: scripts/check-deprecated.ts
  - remove script: env:sync
  - remove script: check:deprecated
  - remove script: validate
  - uninstall: tsx

Code generators

page — Generate a page/route

npx @teispace/next-maker page <name> [options]

| Flag | Effect | | --- | --- | | --dynamic <param> | Dynamic segment (e.g. --dynamic id produces [id]/page.tsx) | | --loading | Generate loading.tsx | | --error | Generate error.tsx |

What it does:

  • Writes page.tsx under src/app/[locale]/<name>/ (i18n) or src/app/<name>/
  • When i18n is detected: generateMetadata, setRequestLocale, getTranslations
  • Registers route in src/lib/config/app-paths.ts
  • Adds translation namespace to en.json
npx @teispace/next-maker page about
npx @teispace/next-maker page dashboard --loading --error
npx @teispace/next-maker page products --dynamic id --loading --error

layout — Generate a nested layout

npx @teispace/next-maker layout <segment> [options]

| Flag | Effect | | --- | --- | | --group | Wraps the segment in parens for a route group, e.g. (marketing) | | --at <path> | Places the layout under a nested path (kebab-case, slash-separated) | | --no-locale | Skip the locale wrapper even when i18n is detected |

When i18n is detected the generated layout consumes params: Promise<{ locale: string }> and calls setRequestLocale. Otherwise it's a plain ({ children }) => <>{children}</> shell.

# /[locale]/dashboard/layout.tsx
npx @teispace/next-maker layout dashboard

# Route group: /[locale]/(marketing)/layout.tsx
npx @teispace/next-maker layout marketing --group

# Nested: /[locale]/dashboard/settings/preferences/layout.tsx
npx @teispace/next-maker layout preferences --at dashboard/settings

Refuses to overwrite an existing layout.tsx — explicit error rather than silent loss.


component — Shared component

npx @teispace/next-maker component <name> [options]

| Flag | Effect | | --- | --- | | --client | Adds 'use client' directive | | --i18n | Imports useTranslations | | --feature <path> | Generate inside a feature directory | | --test / --no-test | Co-generate a sibling *.test.tsx (default: on when Vitest is installed) |

Generated structure:

src/components/common/MyButton/
├── MyButton.tsx
└── index.ts

Auto-updates src/components/common/index.ts and src/components/index.ts.

npx @teispace/next-maker component data-table --client
npx @teispace/next-maker component nav-bar --client --i18n
npx @teispace/next-maker component user-card --client --feature src/features/auth

feature — Full feature module

npx @teispace/next-maker feature <name> [options]

| Flag | Effect | | --- | --- | | --store <type> | Generate Redux store: persist or no-persist | | --skip-store | Skip Redux store | | --service <client> | API service: axios or fetch | | --skip-service | Skip API service | | --path <path> | Custom path (default src/features) |

Generated structure:

src/features/user-dashboard/
├── components/UserDashboard.tsx
├── hooks/useUserDashboard.ts
├── types/user-dashboard.types.ts
├── store/                  (optional)
├── services/               (optional)
└── index.ts
npx @teispace/next-maker feature user-profile --store persist --service axios
npx @teispace/next-maker feature shopping-cart --store no-persist --skip-service
npx @teispace/next-maker feature auth --store persist --service fetch --path src/modules

slice — Redux slice

npx @teispace/next-maker slice <name> [options]

| Flag | Effect | | --- | --- | | --persist / --no-persist | Toggle redux-persist for this slice | | --path <path> | Custom path (default: new feature) | | --test / --no-test | Co-generate *.slice.test.ts (default: on when Vitest is installed) |

Auto-registers in rootReducer with correct imports and persist config.

npx @teispace/next-maker slice auth --persist
npx @teispace/next-maker slice user-settings --path features/auth/store

service — API service

npx @teispace/next-maker service <name> [options]

| Flag | Effect | | --- | --- | | --axios / --fetch | Pick the HTTP client | | --crud | Generate full CRUD (getAll, getById, create, update, delete) | | --path <path> | Custom path |

CRUD mode also generates <Name>Summary (list view) and <Name>Detail (detail view) types, Create<Name>Dto, Update<Name>Dto, and registers the endpoints in app-apis.ts.

Endpoints are emitted as bare paths (e.g. '/users', `/users/${id}`) — the /api/v{n} prefix is owned by getApiBaseUrl() in src/lib/config/api-url.ts and applied at request time. Don't add ${API_PREFIX} interpolation in app-apis.ts; the base URL composer handles it.

npx @teispace/next-maker service payment --axios
npx @teispace/next-maker service users --fetch --crud
npx @teispace/next-maker service orders --axios --crud --path features/products/services

provider — Context provider

npx @teispace/next-maker provider <name>

Generates src/providers/<Name>Provider.tsx with:

  • 'use client' directive
  • createContext + typed context value
  • useX() hook with non-null guard
  • <XProvider> component memoising the value with useMemo

Then two-tier auto-wiring:

  1. Locates RootProvider.tsx — canonical path first (src/providers/RootProvider.tsx), heuristic scan as fallback (looks for the deepest {children} chain in src/providers/*.tsx).
  2. Wraps {children} with <XProvider> inside that chain, preserving indentation.
  3. Updates src/providers/index.ts barrel (re-exports kept sorted).

If no candidate is found, the generator prints the snippet to wire manually rather than failing silently.

npx @teispace/next-maker provider auth        # → AuthProvider, useAuth
npx @teispace/next-maker provider session     # → SessionProvider, useSession
npx @teispace/next-maker provider analytics-provider   # already-suffixed names work

The wrap is idempotent — running twice is a no-op.


env — Declare an env var

Adds a new variable across the four files the starter keeps in sync, atomically and idempotently:

  1. src/lib/env/schema.ts — Zod entry with the right wrapper (preprocess(emptyStringToUndefined, …) for non-enum types)
  2. .env.exampleKEY= placeholder with optional description comment and # -public marker
  3. .envKEY=<default> line when the file exists
npx @teispace/next-maker env <NAME> [options]

| Flag | Effect | | --- | --- | | --type <type> | string (default), url, number, boolean, enum | | --required | Skips .optional() and .default() | | --default <value> | Adds .default(value) (mutually exclusive with --required) | | --public | Auto-prefixes NEXT_PUBLIC_ if missing and tags .env.example with # -public | | --describe <text> | Adds .describe() and a comment line in .env.example | | --enum <list> | Comma-separated values, required when --type=enum |

# Optional URL
npx @teispace/next-maker env SENTRY_DSN --type url --describe "Sentry endpoint"

# Public default
npx @teispace/next-maker env API_URL --type url --public --default "http://localhost:3000"

# Required string (no default, no .optional)
npx @teispace/next-maker env DATABASE_URL --type url --required

# Enum
npx @teispace/next-maker env LOG_LEVEL --type enum --enum debug,info,warn,error --default info

# Coerced number
npx @teispace/next-maker env PORT --type number --default 3000

The generator quote-escapes defaults and descriptions, mirrors the starter's house style, and is fully covered by tests against the schema.ts/.env.example/.env shapes.


locale — Add a locale

npx @teispace/next-maker locale [code] [options]

| Flag | Effect | | --- | --- | | --copy-translations | Copy English translations as the starting point |

Creates src/i18n/translations/<code>.json, updates SupportedLocale, and adds the entry to src/lib/config/app-locales.ts (name, flag, country).

npx @teispace/next-maker locale es
npx @teispace/next-maker locale fr --copy-translations

hook — Custom React hook

npx @teispace/next-maker hook <name> [options]

| Flag | Effect | | --- | --- | | --client | Add 'use client' directive (default true) | | --feature <path> | Generate inside a feature directory | | --test / --no-test | Co-generate *.test.ts |

npx @teispace/next-maker hook auth-session
npx @teispace/next-maker hook user-profile --feature src/features/auth

test — Retrofit a sibling test

Adds a *.test.{ts,tsx} next to existing code that pre-dates the --test flag.

npx @teispace/next-maker test <file> [options]

| Flag | Effect | | --- | --- | | --kind <kind> | Override inferred kind: component / hook / slice | | --force | Overwrite an existing test file |

Inference rules:

  • *.slice.ts → reducer test
  • use*.ts (or content starting with export function useX) → hook test (renderHook)
  • *.tsx → component test (renderWithProviders)
npx @teispace/next-maker test src/features/auth/components/LoginForm.tsx
npx @teispace/next-maker test src/features/auth/store/auth.slice.ts
npx @teispace/next-maker test src/hooks/use-debounce.ts --kind hook --force

Requires setup --tests first.


favicon — Generate icons from a source image

Generates favicon.ico (multi-size) into the App Router root, with optional icon.png, apple-icon.png, opengraph-image.png, twitter-image.png, and PWA manifest icons. Source can be PNG, JPG, JPEG, WebP, SVG, or AVIF.

npx @teispace/next-maker favicon [options]

| Flag | Effect | | --- | --- | | --path <file> | Source image. If omitted, you'll be prompted. | | --out <dir> | Output directory (default: auto-detected src/app or app) | | --icon | Also emit icon.png (512×512) | | --apple | Also emit apple-icon.png (180×180) | | --og | Also emit opengraph-image.png (1200×630) | | --og-source <file> | Use a separate image for the OG/Twitter card | | --twitter | Also emit twitter-image.png (1200×600) | | --all | Shorthand for --icon --apple --og | | --pwa | Detect PWA setup and emit manifest icons (192/512); errors if not detected | | --pwa-init | Bootstrap public/manifest.webmanifest with icons | | --shape <shape> | square | rounded | circle | squircle (default: square) | | --radius <percent> | Corner radius % when --shape=rounded (0–50, default: 20) | | --bg <color> | Background: transparent, hex (#0f172a), CSS name, or rgb()/rgba()/hsl()/hsla() (default: transparent) | | --padding <percent> | Padding around source content (0–30, default: 0) | | --fit <fit> | contain | cover | clip (default: contain) | | --sizes <list> | Comma-separated ICO sizes (default: 16,32,48) | | --quality <n> | PNG compression 1–100 (higher = smaller; PNG is lossless, default: 90) | | --force | Overwrite existing files without prompt | | --dry-run | Show what would be written without writing |

# Minimal: just favicon.ico from a source PNG
npx @teispace/next-maker favicon --path ./brand/logo.png

# Full set: favicon + icon + apple-icon + OG image, rounded with brand background
npx @teispace/next-maker favicon \
  --path ./brand/logo.svg \
  --all \
  --shape rounded --radius 24 \
  --bg "#0f172a" \
  --padding 8

# PWA: emit manifest icons and bootstrap public/manifest.webmanifest
npx @teispace/next-maker favicon --path ./brand/logo.png --pwa-init

# Separate OG art
npx @teispace/next-maker favicon \
  --path ./brand/logo.png \
  --og --og-source ./brand/social-card.png

# Preview without writing
npx @teispace/next-maker favicon --path ./brand/logo.png --all --dry-run

Outputs land in your App Router root (src/app/ or app/) so Next.js auto-resolves them via the file conventions for favicon.ico, opengraph-image, and apple-icon — no <head> wiring required.


End-to-end examples

Quick start

npx @teispace/next-maker init my-project
cd my-project

# Routes & layouts
npx @teispace/next-maker page dashboard --loading --error
npx @teispace/next-maker layout dashboard
npx @teispace/next-maker page products --dynamic id --loading --error

# State + data
npx @teispace/next-maker feature users --store persist --service fetch
npx @teispace/next-maker service users --fetch --crud --path features/users/services

# Providers & env
npx @teispace/next-maker provider auth
npx @teispace/next-maker env SENTRY_DSN --type url --describe "Sentry endpoint"

# i18n
npx @teispace/next-maker locale es

# Health check before commit
npx @teispace/next-maker doctor

npm run dev

Feature-driven workflow

npx @teispace/next-maker feature products --store persist --service axios
npx @teispace/next-maker service products --axios --crud --path features/products/services
npx @teispace/next-maker page products --dynamic id --loading --error
npx @teispace/next-maker component product-card --client --feature src/features/products
npx @teispace/next-maker layout products

npx @teispace/next-maker feature cart --store persist --skip-service
npx @teispace/next-maker page checkout --loading --error

Maintenance — re-applying drifted features

# What's drifted?
npx @teispace/next-maker doctor

# Fix in place
npx @teispace/next-maker doctor --fix

# Pull a feature out cleanly
npx @teispace/next-maker remove i18n --dry-run
npx @teispace/next-maker remove i18n

Architecture

Layers

src/
├── commands/        # Commander definitions (one file per CLI command)
├── prompts/         # Enquirer flows (one per command needing interactivity)
├── generators/      # generate<X>(): writes files for a single artifact
│   └── templates/   # Pure string-template functions (testable in isolation)
├── modifiers/       # Pure functions that surgically edit existing files
├── pipelines/       # PipelineStep[] composers for multi-step generators
├── services/setup/  # Retrofit installers, one per feature
├── manifests/       # Declarative feature footprints (drives doctor + remove)
├── detection/       # "Is feature X installed?" detectors
├── core/            # File I/O + package-manager helpers (yarn/npm/pnpm/bun)
└── config/          # PROJECT_PATHS, PACKAGES, spinner, output, error handlers

The manifest pattern

Each feature has a manifest in src/manifests/<feature>.manifest.ts describing:

  • detect — high-level "is this installed?"
  • files — paths the feature owns (with generated: true/false to control deletion safety)
  • packages — runtime/dev dependencies
  • scriptspackage.json script entries (with optional exact-value match)
  • injections — code blocks in shared files (with presence and optional removePattern)
  • apply — the existing setup<X>() function (for setup and doctor --fix)
  • remove — optional custom remover (defaults to the generic reverser)

The manifest registry is consumed by:

  • setup — calls apply() directly
  • doctor — walks every manifest, reports drift via checkManifest
  • remove — runs reverseManifest (or a custom remove) and prints the plan

Adding a manifest for a new feature is a single file. The CLI commands don't need to know about it.

Modifier conventions

  • Pure transformation modules (e.g. headers.ts, package-modifier.ts, env-var.modifier.ts) take strings or JSON and return strings or JSON. No filesystem.
  • Thin async wrappers (index.ts per setup service, the modifier orchestrators) handle I/O and spinners.
  • Idempotency is required: re-running anything is a no-op when the target state is already reached. This is what makes doctor --fix safe.

Project structure (generated app)

The full shape of a scaffolded app (branches marked (opt) are stripped when the matching prompt is declined during init):

my-project/
├── src/
│   ├── app/                           # Next.js App Router
│   │   ├── [locale]/                  # (opt, i18n) locale-aware routes
│   │   │   ├── layout.tsx
│   │   │   ├── page.tsx
│   │   │   ├── error.tsx
│   │   │   └── not-found.tsx
│   │   ├── global-error.tsx
│   │   ├── not-found.tsx
│   │   ├── robots.ts
│   │   ├── sitemap.ts
│   │   ├── favicon.ico                # `favicon` command
│   │   ├── icon.png                   # (opt, `favicon --icon`/`--all`) 512×512
│   │   ├── apple-icon.png             # (opt, `favicon --apple`/`--all`) 180×180
│   │   ├── opengraph-image.png        # (opt, `favicon --og`/`--all`) 1200×630
│   │   └── twitter-image.png          # (opt, `favicon --twitter`) 1200×600
│   ├── proxy.ts                       # (opt, i18n) Next 16 middleware replacement
│   ├── features/                      # Feature modules (feature-first DDD)
│   │   └── counter/                   # (opt, redux) example feature
│   │       ├── components/
│   │       │   ├── Counter.tsx
│   │       │   └── Counter.test.tsx   # (opt, tests)
│   │       ├── hooks/useCounter.ts
│   │       ├── store/                 # slice + selectors + persist + barrel
│   │       └── types/counter.types.ts
│   ├── components/
│   │   ├── common/                    # Shared UI (auto-wired barrel exports)
│   │   └── index.ts
│   ├── providers/
│   │   ├── RootProvider.tsx           # Composes Store → Theme → Intl → custom
│   │   ├── StoreProvider.tsx          # (opt, redux) useRef + PersistGate
│   │   ├── CustomThemeProvider.tsx    # (opt, dark-mode) @teispace/next-themes
│   │   └── index.ts                   # Barrel — `next-maker provider <name>` keeps it sorted
│   ├── store/                         # (opt, redux) makeStore, rootReducer, typed hooks
│   │   └── slices/ws.slice.ts         # (opt, ws) non-persisted connection state slice
│   ├── services/
│   │   ├── api/                       # API service barrel
│   │   └── storage/                   # react-secure-storage wrapper
│   ├── lib/
│   │   ├── config/                    # seo, app-apis, app-paths, app-locales, constants, api-url (getApiBaseUrl)
│   │   ├── env/                       # Zod-validated env schema (schema.ts, validate.ts)
│   │   ├── logger/                    # Pino logger with auto-redaction
│   │   ├── errors/                    # ApiException (carries requestId), catchError
│   │   ├── enums/
│   │   └── utils/
│   │       ├── http/                  # (opt, http-client)
│   │       │   ├── shared/            # runtime guards, request-id, parseApiError, toSearchParams
│   │       │   ├── axios-client/      # interceptors, token refresh, Result-based
│   │       │   ├── fetch-client/      # same Result pattern on native fetch, typed `params`
│   │       │   ├── __bundle-sentinel__/  # build-time regression gate ('use client' check)
│   │       │   ├── client-utils.ts
│   │       │   ├── token-store.ts    # inert in cookie-mode (the default)
│   │       │   ├── index.ts          # universal entry — safe in client/server/edge
│   │       │   └── server.ts         # server-only entry — forwards next/headers cookies
│   │       ├── ws/                    # (opt, ws) socket.io-client wrapper, hooks, Redux bridge
│   │       │   ├── client/            # WsClient + lazy `wsClient` singleton (Proxy)
│   │       │   ├── hooks/             # useWsStatus, useWsEvent, useWsEmit
│   │       │   ├── redux/             # bridge (the only WS dispatcher) + selectors
│   │       │   ├── shared/            # SSR guard, auth carrier, URL composer
│   │       │   ├── types/             # ClientToServerEvents/ServerToClientEvents, payloads
│   │       │   ├── constants.ts       # namespace, heartbeat, reconnection bounds
│   │       │   └── index.ts           # public barrel
│   │       └── validations/
│   ├── i18n/                          # (opt, i18n) routing, request, navigation, translations/
│   ├── styles/globals.css             # Tailwind v4 directives
│   └── types/                         # common/, utility/ (Result, Either), i18n.ts
├── test/                              # (opt, tests)
│   ├── setup.ts                       # testing-library + jsdom setup
│   └── test-utils.tsx                 # renderWithProviders, TestProviders
├── scripts/
│   ├── sync-env.ts                    # .env.example ← .env (respects `-public` markers)
│   └── check-deprecated.ts            # fails build if @deprecated APIs are referenced
├── public/
├── biome.json                         # single-tool lint + format
├── next.config.ts                     # security headers, reactCompiler (opt), bundleAnalyzer (opt), withNextIntl (opt, i18n)
├── vitest.config.ts                   # (opt, tests)
├── postcss.config.mjs                 # @tailwindcss/postcss
├── tsconfig.json
├── .env.example
├── .czrc                              # (opt, commitizen)
├── .husky/                            # (opt, pre-commit hooks)
├── .lintstagedrc.mjs                  # (opt, pre-commit hooks) runs `biome check --write`
├── commitlint.config.mjs              # (opt, pre-commit hooks)
├── Dockerfile                         # (opt, docker) multi-stage, standalone mode
├── docker-compose.yml                 # (opt, docker)
├── AGENTS.md                          # Agent coding rules (referenced from CLAUDE.md)
├── CLAUDE.md
└── package.json

Features that have first-class opt-in/opt-out prompts during init: httpClient, darkMode, redux, ws (opt-in, requires redux), i18n, tests, reactCompiler, bundleAnalyzer, docker, ci, preCommitHooks, commitizen, communityFiles, readme, copyEnv. Each opt-out has a matching setup --<feature> to re-add later. doctor and remove cover the whole installed footprint via manifests.


Tech Stack

CLI: TypeScript, esbuild, Commander.js, Enquirer, Vitest, degit.

Generated apps: Next.js 16+, TypeScript, Tailwind CSS v4, Biome, Pino, Zod, Redux Toolkit, @teispace/next-themes, next-intl, Fetch / Axios HTTP clients (shared foundation), socket.io-client (opt-in via ws prompt), Vitest + RTL, React Compiler.


Recent changes

Behaviour added in v2.1.0 beyond the headline features. None of these change the user-facing CLI surface — they harden parts of the generated app that previously needed manual cleanup.

  • HTTP sentinel + server entry auto-align. The template ships src/lib/utils/http/__bundle-sentinel__/client-bundle-sentinel.tsx and src/lib/utils/http/server.ts with imports of both axios and fetch client modules. When you pick a single client (at init or via setup --http-client), the inactive variant's directory is removed — and the two files would normally still reference it, breaking yarn build. Both are now rewritten in place to mention only the active client(s). Idempotent: re-running setup --http-client against the same configuration is a no-op.
  • remove ws strips cleanly without manual intervention. The WS manifest's reducer-registration and bridge-mount injections now carry removePattern functions, so next-maker remove ws deletes the wsReducer import, the ws: wsReducer entry, the unwrapped-on-purpose JSDoc, and the attachWsBridge useEffect block — without any "manual cleanup" messages. The init-time cleanupWs and the remove ws flow share the same pure helpers, so the byte-level output is identical.
  • useEffect import auto-pruned. When the WS bridge effect is stripped (init opt-out or remove ws), the useEffect import is dropped from StoreProvider.tsx's React import line if no other useEffect( calls remain — avoiding the unused-import lint warning.
  • Wording-tolerant strip helpers. The stripBundleSentinel, stripBridgeMount, and stripWsReducerRegistration helpers now anchor on stable code tokens (import paths, function names, the ws + persistReducer keywords inside JSDoc) rather than literal comment text. Upstream template comment rewording can't silently break cleanup.
  • doctor reports sentinel mount drift. The HTTP manifest tracks the <HttpClientBundleSentinel /> mount as a code injection in either [locale]/layout.tsx or src/app/layout.tsx. If you delete the mount manually, doctor reports it; remove http-client strips it.

Known issues

  • setup --redux post-init when ws was opted out. The template's StoreProvider.tsx ships with the WS bridge mount inline. next-maker setup --redux copies the template's StoreProvider.tsx wholesale into the project — so running it on a project where ws is not wanted leaves import { attachWsBridge, wsClient } from '@/lib/utils/ws' in place, and yarn build fails because that module doesn't exist. Workaround until a fix lands: also run next-maker setup --ws to install the WS layer, then next-maker remove ws if you don't actually want it (clean removal handles both layers). Tracked separately; out of scope for v2.1.0.
  • doctor --fix is interactive. Some setup services (notably setup --http-client) prompt for an action when the feature is partially installed. doctor --fix invokes apply() directly, so the prompt fires during what's meant to be a non-interactive repair. Workaround: run the specific setup --<feature> manually and pick the appropriate action. A non-interactive repair path is on the roadmap.

Development

Setup

git clone <repository-url>
cd npm-packages/packages/next-maker
yarn install

Build

yarn build      # esbuild bundle + tsc --emitDeclarationOnly

Test

yarn test           # one-shot
yarn test:watch

The test suite covers every modifier, generator template, and manifest runner with deterministic string/JSON inputs. Generators that touch the filesystem are tested against os.tmpdir() directories.

Smoke-test the built CLI

node dist/index.js init test-project
cd test-project

# Generators
node ../dist/index.js page dashboard --loading --error
node ../dist/index.js layout dashboard
node ../dist/index.js component sidebar --client
node ../dist/index.js hook debounce
node ../dist/index.js provider auth
node ../dist/index.js slice filters --persist
node ../dist/index.js feature users --store persist --service axios
node ../dist/index.js service users --fetch --crud
node ../dist/index.js env SENTRY_DSN --type url --describe "Sentry"
node ../dist/index.js locale es
node ../dist/index.js test src/hooks/useDebounce.ts --force

# Maintenance
node ../dist/index.js doctor
node ../dist/index.js setup --ws            # add WebSocket layer (project must already have --redux)
node ../dist/index.js remove redux --dry-run

Adding a new feature manifest

  1. Drop a file under src/manifests/<feature>.manifest.ts exporting a FeatureManifest.
  2. Append it to the MANIFESTS array in src/manifests/index.ts.
  3. (Optional) Add a setup --<feature> flag if you want a flag-based retrofit.

doctor and remove will pick it up automatically.


License

MIT


Contributing

Contributions are welcome. Please open a PR.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'feat: add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Support

For issues and questions, please visit our GitHub Issues.