nexstruct
v1.0.27
Published
Next.js 15 CLI scaffold with shadcn/ui, MUI, Ant Design, Zustand, Redux, tRPC, NextAuth, Clerk — interactive project generator with 24+ custom field types.
Maintainers
Readme
Getting Started
npx nexstructNo install needed. Answer the prompts, and your project is ready in seconds.
Features at a Glance
| Category | Options | |----------|---------| | UI Library | shadcn/ui (Tailwind), Material UI (MUI), Ant Design | | State Management | Redux Toolkit, Zustand, React Context | | API Layer | Fetch API, Axios, tRPC | | Authentication | None, NextAuth.js, Clerk, JWT Auth (Custom) — 4 token strategies | | Form Handling | None, React Hook Form + Zod, Formik + Yup | | Component Organization | Feature Components or Co-located Components | | Theme | Dark/Light mode toggle with next-themes | | Examples | Optional example dashboard with live demos | | Git Hooks | Optional Husky — pre-commit (lint-staged), pre-push (tsc/lint/build), commitlint |
Prompts Walkthrough
1. UI Library
? Select UI libraries:
◉ shadcn/ui (with Tailwind CSS)
◯ Material UI (MUI)
◯ Ant DesignYou can select multiple UI libraries. The first one becomes the primary UI (components, pages, examples). Additional libraries only contribute their provider/theme files and auth pages.
2. State Management
? Select state management:
◯ Redux Toolkit (with RTK Query)
◉ Zustand
◯ React Context + useReducerMultiple selections allowed. The chosen stores, providers, and typed hooks are wired into the project automatically.
| State Manager | Files Generated |
|---|---|
| Redux Toolkit | src/store/redux/ — store.ts, hooks.ts, slices |
| Zustand | src/store/zustand/ — typed stores with devtools |
| Context | src/store/context/ — providers and consumer hooks |
3. API Layer
? Select API layer:
◉ Fetch API (built-in)
◯ Axios
◯ tRPCMultiple selections allowed. Each generates its client setup and typed request/response patterns.
| API Layer | Files Generated |
|---|---|
| Fetch | src/api/fetch/client.ts — wrapper with error handling |
| Axios | src/api/axios/ — instance with interceptors |
| tRPC | src/api/trpc/ — procedures, React Query integration |
API Hook Layers (optional)
? Select API hook layers (under src/hooks):
◉ Client API hooks (@/hooks/client-api) — React Query hooks for the browser
◉ Server API hooks (@/hooks/server-api) — Node/Server-side fetch layerMultiple selections allowed (both are selected by default). This controls which data-fetching hook layers are scaffolded under src/hooks/:
| Layer | Path | What it gives you |
|---|---|---|
| Client API | src/hooks/client-api/ | React Query hooks (useFetchData, useApiMutation, useInfiniteFetchData) — run in the browser, inject the access token |
| Server API | src/hooks/server-api/ | Node fetch layer (serverApi.fetchData, mutateData, fetchInfiniteData) — call third-party/upstream APIs directly from Server Components / Actions, no CORS |
Each layer is exported from a single barrel:
// Browser
import { queryHooks } from '@/hooks/client-api';
const { data } = queryHooks.useFetchData({ path: 'courses', queryKey: 'list' });
// Server
import { serverApi } from '@/hooks/server-api';
const data = await serverApi.fetchData({ path: 'https://api.example.com/courses' });Pick Client API only for a pure SPA, Server API only for server-side fetching, or both when you mix Server Components with client interactivity.
4. Authentication
? Select authentication:
◯ None
◯ NextAuth.js
◯ Clerk
◉ JWT Auth (Custom)JWT Auth — Token Strategy Sub-prompt
? Select token strategy:
◉ Cookie-Based (Recommended)
◯ Memory + Cookie
◯ LocalStorage
◯ SessionStorage| Strategy | Access Token | Refresh Token | XSS Safe | Persistence | |---|---|---|---|---| | Cookie-Based ⭐ | HttpOnly cookie | HttpOnly cookie | ✅ Full | Server-managed | | Memory + Cookie | React state (memory) | HttpOnly cookie | ✅ Refresh safe | Lost on refresh | | LocalStorage | localStorage | localStorage | ❌ Vulnerable | Permanent | | SessionStorage | sessionStorage | sessionStorage | ❌ Vulnerable | Tab-only |
All strategies use Zustand for auth state management. Auth state is initialized on mount via the AuthProvider, and the useAuth() hook reads from the Zustand store.
Auth Files Generated
src/
├── api/auth/
│ ├── auth.ts # API calls (login, register, logout, refresh, me, etc.)
│ └── auth.types.ts # Request/Response types
├── hooks/
│ └── use-auth.ts # Auth state + actions from the auth store
├── lib/
│ ├── api-client.ts # Client with auto-refresh interceptor
│ ├── token-storage.ts # Strategy-specific token storage
│ └── validators.ts # Zod schemas for auth forms
├── store/
│ └── auth.ts # Zustand store (all strategies)
├── components/features/auth/ # Auth shell + forms (features org)
│ ├── auth-card.tsx # Shared page shell (icon header + form card)
│ ├── auth-message.tsx # Full-page status (success / invalid link)
│ ├── error-alert.tsx # Inline form error banner
│ ├── loading-spinner.tsx # Small inline spinner for submit buttons
│ ├── login-form.tsx # Pure form UI — MUI/AntD templates override these
│ ├── register-form.tsx
│ ├── forgot-password-form.tsx
│ └── reset-password-form.tsx
└── app/(auth)/ # Page → container → service pattern
├── login/
│ ├── page.tsx # Ultra-thin entry, just renders container
│ ├── login-container.tsx # All state: auth store, react-hook-form, redirect
│ └── service.ts # API calls for login (loginService.submit)
├── register/
│ ├── page.tsx
│ ├── register-container.tsx
│ └── service.ts # API calls for register (registerService.submit)
├── forgot-password/
│ ├── page.tsx
│ ├── forgot-password-container.tsx
│ └── service.ts # API calls for forgot password
└── reset-password/
├── page.tsx # Wraps container in Suspense (useSearchParams)
├── reset-password-container.tsx
└── service.ts # API calls for reset passwordWith colocated organization, the same components are copied per route into src/app/(auth)/{route}/_assets/components/ and components/features/auth/ is removed — auth follows the exact same single format as every other page.
Backend endpoints required (backend-agnostic — works with Node.js, Python, Go, etc.):
| Method | Endpoint | Description |
|--------|----------|-------------|
| POST | /auth/register | Create account |
| POST | /auth/login | Sign in |
| POST | /auth/logout | Sign out |
| POST | /auth/refresh | Refresh token |
| GET | /auth/me | Current user |
| POST | /auth/forgot-password | Send reset email |
| POST | /auth/reset-password | Reset with token |
| POST | /auth/change-password | Change password |
5. Form Handling
? Select form handling:
◉ None
◯ React Hook Form + Zod
◯ Formik + Yup| Selection | Generated |
|---|---|
| React Hook Form | src/forms/react-hook-form/ — schemas, hooks, CustomField integration |
| Formik | src/forms/formik/ — schemas, hooks, validation |
6. Component Organization
? How do you want to organize your page components?
◉ Feature Components — shared across pages
◯ Co-located Components — page-specific only| Organization | Pattern |
|---|---|
| Feature Components | page.tsx → {feature}-container.tsx + service.ts → src/components/features/{feature}/ |
| Colocated Components | page.tsx → {feature}-container.tsx + service.ts → src/app/{route}/_assets/components/ |
One organization format is applied to every page (demo, examples, auth) — never a mix. Auth pages follow the same rule: feature mode puts the auth shell + forms in src/components/features/auth/, colocated mode puts them in each src/app/(auth)/{route}/_assets/components/.
Each feature page (auth, demo, examples) now includes a colocated service.ts file next to its container that contains the API calls for that feature. This keeps the container clean (state + UI composition) and separates API logic into a dedicated file.
7. Theme Toggle
? Enable dark/light mode toggle? (Y/n)When enabled, next-themes provides dark/light mode with a ThemeToggle component in the navbar and a unified palette at src/lib/theme/palette.json. You pick one of 8 color presets (Blue, Emerald, Violet, Rose, Amber, Cyan, Slate, Mono) at scaffold time, or switch later with npm run theme:preset -- <name>.
8. Example Components
? Include example components and pages? (Y/n)When enabled, a full examples dashboard is generated at /examples with live demos of the component system.
9. Git Hooks (optional)
? Add Husky git hooks? (pre-commit lint-staged, pre-push typecheck/lint/build, commitlint) (y/N)Default is No — opt in only if you want automated git checks. When enabled, an e-crystal-style setup is generated:
| Hook | Runs |
|------|------|
| pre-commit | lint-staged — formats only staged files with Prettier |
| pre-push | tsc --noEmit + ESLint (relative-path formatter) + next build |
| commit-msg | Commitlint — enforces Conventional Commits |
Generated files: .husky/{pre-commit,pre-push,commit-msg,prepare-commit-msg}, lint-staged.config.js, commitlint.config.js, .prettierrc (Tailwind class sorting), and scripts/eslint-formatter-relative.cjs. Hooks activate automatically on the first npm install via the prepare: husky script.
10. Project Name
? Project name: my-appAuto-derived from your selections (e.g., shadcn-zustand-app), but customizable.
Component System (shadcn/ui)
When you select shadcn/ui, you get a full reusable component system.
UI Primitives — src/components/ui/
button, badge, card, dialog, input, label, select, form, switch, checkbox, radio-group, textarea, table, tooltip, popover, scroll-area, avatar, sheet, dropdown-menu, tabs, progress, separator, input-otp.
CustomField System — src/components/common/fields/
26+ field types with dual-mode operation:
| Field Type | Modes | Features |
|---|---|---|
| CustomField.Text | form / standalone | Left/right icons, array splitting |
| CustomField.TextArea | form / standalone | Configurable rows |
| CustomField.Number | form / standalone | Integer/float, scroll prevention, key filtering, min=0 |
| CustomField.StringNumber | form / standalone | Numeric string input |
| CustomField.Password | form / standalone | Show/hide toggle, strength validation rules |
| CustomField.PhoneNumber | form / standalone | Country dropdown, flag, search, maskable view |
| CustomField.OTP | form / standalone | One-time password input |
| CustomField.SingleSelectField | form / standalone | shadcn Select with loading/empty states |
| CustomField.SelectField | form only | Multi-select, search, avatars, tags, "show more" |
| CustomField.SwitchField | form / standalone | With description, border mode |
| CustomField.RadioField | form only | Radio group |
| CustomField.CheckField | form only | Single checkbox with label |
| CustomField.MultiCheckField | form only | Multi-checkbox group |
| CustomField.SingleCheckField | form only | Standalone checkbox |
| CustomField.SearchField | form / standalone | Search with callback |
| CustomField.DatePickerField | form / standalone | Date picker |
| CustomField.RangeDatePicker | form only | Date range picker |
| CustomField.LimitField | standalone | Pagination limit selector with URL sync |
| CustomField.TextAreaWithFile | form only | Textarea + file attachments |
| CustomField.UploadProfilePicture | form / standalone | Avatar upload with preview, FileReader data URL |
| CustomField.UploadVideoFile | form / standalone | Video upload with preview |
| CustomField.DynamicFileUploadField | form only | Drag-and-drop file upload, optional onUpload callback |
| CustomField.RichTextEditor | form only | Rich text editing |
| CustomField.TinyEditor | form only | Lightweight editor |
Dual-mode pattern:
// With react-hook-form — validation, errors, form state
<CustomField.Text form={form} name="username" label="Username" />
// Standalone — controlled input, no form library needed
<CustomField.Text value={value} onChange={setValue} label="Username" viewOnly={true} />Each field also supports a view-only mode via viewOnly prop, rendering a styled read-only display.
Common Components — src/components/common/
| Component | Description |
|---|---|
| ActionButton | Button with icon positions, loading spinner (isPending), optional Tooltip |
| DialogWrapper | Scrollable dialog with sticky header, close button, optional trigger, footer slot |
| DynamicTable | Config-driven table with loading/empty states, checkbox selection, expandable rows |
| Pagination | Page navigation with ellipsis for large page counts |
Toast Notification System — src/components/common/toast/
| Function | Description |
|---|---|
| ToastMessageShow(type, message, options) | Unified toast API |
| toastSuccessMessage(msg) | Success toast |
| toastErrorMessage(msg) | Error toast with API error extraction |
| toastLoadingMessage(msg) | Loading toast |
| toastCustomMessage(msg) | Custom toast |
| ToastMessageChange(msg) | Transform error messages into human-friendly text |
The ToastProvider is auto-injected into the generated Providers composition.
Project Structure
my-app/
├── public/
├── scripts/
│ ├── cleanup.mjs # Remove example/demo files (npm run cleanup)
│ ├── theme.mjs # Regenerate CSS theme from config (npm run theme)
│ └── theme-preset.mjs # Apply a named preset (npm run theme:preset -- <name>)
├── src/
│ ├── app/ # App Router pages & layouts
│ │ ├── favicon.ico
│ │ ├── globals.css
│ │ ├── layout.tsx # Root layout with Providers + AppLayout
│ │ ├── page.tsx # Home page
│ │ ├── (auth)/ # Auth pages (login, register, forgot/reset password)
│ │ │ ├── login/
│ │ │ │ ├── page.tsx
│ │ │ │ ├── login-container.tsx
│ │ │ │ └── service.ts # API calls for login
│ │ │ ├── register/
│ │ │ │ ├── page.tsx
│ │ │ │ ├── register-container.tsx
│ │ │ │ └── service.ts # API calls for register
│ │ │ ├── forgot-password/
│ │ │ │ ├── page.tsx
│ │ │ │ ├── forgot-password-container.tsx
│ │ │ │ └── service.ts # API calls for forgot password
│ │ │ └── reset-password/
│ │ │ ├── page.tsx
│ │ │ ├── reset-password-container.tsx
│ │ │ └── service.ts # API calls for reset password
│ │ ├── demo/ # Demo page (page → container → service.ts → WelcomeCard)
│ │ │ ├── page.tsx
│ │ │ ├── demo-container.tsx
│ │ │ └── service.ts # API calls for demo
│ │ │ └── _assets/components/ # Colocated component (if colocated org)
│ │ └── examples/ # Example dashboard (optional)
│ │ ├── page.tsx
│ │ ├── examples-container.tsx
│ │ ├── service.ts # API calls for examples
│ │ └── _assets/components/ # Colocated component (if colocated org)
│ ├── components/
│ │ ├── ui/ # Design system primitives (button, card, dialog, etc.)
│ │ ├── common/ # Shared components
│ │ │ ├── badge/
│ │ │ ├── button/ # ActionButton system
│ │ │ ├── card/
│ │ │ ├── dialog/ # DialogWrapper
│ │ │ ├── dynamic-table/
│ │ │ ├── error-page/
│ │ │ ├── fields/ # CustomField system (26+ field types)
│ │ │ ├── global-loader/
│ │ │ ├── header-search/
│ │ │ ├── pagination/
│ │ │ ├── toast/ # Toast notification system
│ │ │ └── typography/
│ │ ├── layouts/ # App chrome (sidebar, navbar)
│ │ │ ├── app-layout.tsx
│ │ │ ├── left-sidebar.tsx
│ │ │ ├── right-sidebar.tsx
│ │ │ └── top-navbar.tsx
│ │ └── features/ # Feature-specific components
│ │ ├── auth/ # Auth shell + forms (if JWT auth)
│ │ └── demo/ # Demo component (if features organization)
│ ├── hooks/ # Data fetching hooks
│ │ ├── client-api/ # Browser hooks (React Query) — optional
│ │ │ ├── fetcher.ts # Core fetch function
│ │ │ ├── index.ts # Barrel export (queryHooks)
│ │ │ ├── useApiMutation.tsx
│ │ │ ├── useFetchData.tsx
│ │ │ └── useInfiniteFetchData.tsx
│ │ ├── server-api/ # Server/Node fetch layer — optional
│ │ │ ├── fetcher.ts # Server twin of client-api/fetcher.ts
│ │ │ ├── index.ts # Barrel export (serverApi)
│ │ │ ├── api-mutation.ts
│ │ │ ├── infinite-fetch-data.ts
│ │ │ └── logger.tsx # DevTools console logger
│ │ ├── auth/ # useAccessToken, useAuth
│ │ ├── socket/ # useSocket (real-time)
│ │ └── ui/ # useSafeUpdate, useThemeMode
│ ├── lib/
│ │ ├── date-utils/ # Date/time formatters
│ │ ├── schema-validation/ # Zod validation helpers
│ │ ├── theme/ # Theme configuration
│ │ ├── error-handler.ts
│ │ ├── remove-empty-fields.ts
│ │ └── utils.ts # cn(), maskString(), passwordRules, etc.
│ ├── providers/ # Auto-composed provider stack
│ │ ├── index.tsx # Generated Providers composition
│ │ ├── auth-provider.tsx
│ │ ├── layout-provider.tsx
│ │ ├── theme-provider.tsx
│ │ ├── toast-provider.tsx
│ │ └── ...
│ ├── store/ # State management
│ │ ├── zustand/ # (if Zustand selected)
│ │ ├── redux/ # (if Redux selected)
│ │ └── context/ # (if Context selected)
│ ├── api/ # API layer
│ │ ├── fetch/ # (if Fetch selected)
│ │ ├── axios/ # (if Axios selected)
│ │ ├── trpc/ # (if tRPC selected)
│ │ └── auth/ # Auth API calls & types (if JWT Auth)
│ ├── forms/ # Form handling
│ │ ├── react-hook-form/ # (if RHF selected)
│ │ └── formik/ # (if Formik selected)
│ └── types/ # Shared TypeScript types
│ ├── common.type.ts
│ ├── global.d.ts
│ ├── layout.type.ts
│ └── react-simple-maps.d.ts
├── next.config.ts
├── tailwind.config.ts
├── postcss.config.mjs
├── tsconfig.json
├── eslint.config.mjs # Flat config with template-friendly rules
├── lint-staged.config.js # (if git hooks enabled) — prettier on staged files
├── commitlint.config.js # (if git hooks enabled) — conventional commits
├── .prettierrc # (if git hooks enabled) — Tailwind class sorting
├── .husky/ # (if git hooks enabled) — pre-commit, pre-push, commit-msg
├── .gitignore
├── guide.md # Generated per-selection usage guide
└── package.jsonGenerated Files & Scripts
npm run dev — Next.js dev server
npm run build — Production build
npm run typecheck — tsc --noEmit for full type checking
npm run cleanup — Interactive cleanup
Removes example/demo files step-by-step with confirmation:
$ npm run cleanup
🧹 Nexstruct Cleanup
─────────────────────
Remove src/app/examples/ (all demo pages)? (y/N)
Remove /examples link from the navbar? (y/N)
Remove COMPONENT_GUIDE.md file(s)? (y/N)
Remove unused dependencies? (y/N)
Remove the cleanup script itself? (y/N)npm run theme — Regenerate CSS theme
If you modify src/lib/theme/palette.json, run this to regenerate globals.css with updated CSS variables.
npm run theme:preset -- <name> — Switch color preset
The project ships with 8 presets in src/lib/theme/presets/ (blue, emerald, violet, rose, amber, cyan, slate, mono). Apply one at any time:
npm run theme:preset -- emeraldThis copies the preset over palette.json and regenerates globals.css. MUI and Ant Design pick it up automatically (they read palette.json at build time). Add your own by dropping a new src/lib/theme/presets/<name>.json file.
Git Hooks (Husky) — optional
If you opted into Husky during scaffolding, the project ships with:
| Hook | Runs |
|------|------|
| pre-commit | lint-staged — formats staged files with Prettier (Tailwind class sorting included) |
| pre-push | tsc --noEmit + ESLint (relative-path formatter) + next build |
| commit-msg | Commitlint — enforces Conventional Commits |
Hooks activate automatically on the first npm install (the prepare lifecycle script wires Husky up via core.hooksPath). Skip them with git commit --no-verify / git push --no-verify if you ever need to bypass.
guide.md — Per-selection guide
Generated alongside your project, this file contains only the sections relevant to your selections — no noise about libraries you didn't choose.
Shared Utilities
src/lib/utils.ts
| Function | Description |
|---|---|
| cn() | Merge Tailwind classes with clsx + tailwind-merge |
| LabelAndPlaceholderTextFormat() | Auto-format labels to title case (preposition-aware) |
| truncate() | String truncation with ellipsis |
| slugify() | URL-safe slug generation |
| maskString() | "Helld" — show first N / last N chars |
| maskEmail() | "j@example.com" |
| passwordRules | 5 rules array (length, uppercase, number, special, no sequential) |
| isPasswordStrong() | Check all rules pass |
src/lib/date-utils/index.ts
| Function | Description |
|---|---|
| formatDate() | "June 17, 2026" |
| formatRelativeTime() | "just now", "3m ago", "2h ago", "5d ago" |
| toMonthYear() | "Jun 2025" |
| time12h() | "2:30 PM" (with relative mode for today/yesterday) |
| time24h() | "14:30" |
| customFormatDate() | "YYYY-MM-DD" / "DD-MM-YYYY" / "YYYY" |
| fullDateTime() | "24 August 2025, 03:30 PM" |
| duration() | "2y 3m" between two dates |
| localDateTime() | "20-10-2025 at 10:07 am" |
| localDateToISO() | UTC midnight ISO string |
src/lib/error-handler.ts
| Function | Description |
|---|---|
| handleApiAuthError() | Handle 401/403 errors with toast + redirect |
| extractErrorMessage() | Extract human-readable message from API error |
src/lib/remove-empty-fields.ts
| Function | Description |
|---|---|
| removeEmptyFields() | Strip null/undefined/empty values from payloads |
src/lib/schema-validation/index.ts
| Function | Description |
|---|---|
| validateSchema() | Validate data against a Zod schema |
Shared Hooks — src/hooks/
Data-fetching hooks are split into two optional layers (see API Hook Layers above). Both are selected by default.
src/hooks/client-api/ (browser)
| Hook | Description |
|---|---|
| useFetchData | React Query data fetching hook (GET/POST) |
| useApiMutation | React Query mutation hook (POST/PATCH/DELETE/PUT) |
| useInfiniteFetchData | Infinite scroll / pagination hook |
| fetchData | Core fetch function with auth token injection |
All client hooks are exported from the queryHooks barrel:
import { queryHooks } from '@/hooks/client-api';
const { data } = queryHooks.useFetchData({ path: 'courses', queryKey: 'list' });src/hooks/server-api/ (Node / Server Components)
| Function | Description |
|---|---|
| serverApi.fetchData | Server-side fetch (same options as the client fetchData) |
| serverApi.mutateData | Server-side mutation (POST/PUT/PATCH/DELETE) |
| serverApi.fetchInfiniteData | One page of an infinite list (pass cursor) |
| ApiLogger | DevTools console logger for server responses |
import { serverApi } from '@/hooks/server-api';
const data = await serverApi.fetchData({ path: 'https://api.example.com/courses' });Always-included hooks
| Hook | Path | Description |
|---|---|---|
| useAccessToken | src/hooks/auth/ | Cross-tab token management with localStorage + cookie |
| useSafeUpdate | src/hooks/ui/ | Prevent state updates on unmounted components |
| useSocket | src/hooks/socket/ | WebSocket / real-time subscription |
Provider Composition
The src/providers/index.tsx is code-generated based on your selections. The provider nesting order is:
LayoutProvider
ToastProvider
ThemeProvider (if dark mode enabled)
MuiProvider / AntdProvider (if selected)
ReduxProvider (if Redux)
TrpcProvider (if tRPC)
NextAuthProvider / ClerkAuthProvider / AuthProvider (if auth)
ChildrenLayoutProvider, ToastProvider and (when dark mode is enabled) ThemeProvider are always included; every other provider is only added when its corresponding library/feature is selected. ThemeProvider sits outside the MUI/AntD providers so they can read the resolved theme and switch to dark mode.
File Naming Convention
| Extension | Type | Example |
|---|---|---|
| .tsx | UI components / hooks | useApiMutation.tsx |
| .ts | React hooks (no JSX) | useAccessToken.ts |
| .store.ts | State management | counter.store.ts |
| .api.ts | API layer | users.api.ts |
| .service.ts | Auth/services | auth.service.ts |
| .type.ts | TypeScript types | common.type.ts |
Updating Existing Projects
npx nexstruct updateThe update command detects changes between your project and the latest templates, shows a preview, and applies only untouched-file updates.
License
MIT
