Command: module
Description
The module command generates a complete module in an existing Next.js project, following the Screaming Architecture pattern. It automatically creates the entire folder structure, boilerplate files, services, types, hooks, and optionally store configuration (Zustand or Redux).
Syntax
avangcli module <module-name> [options]Prerequisites
- Be in a valid Next.js project
- Project must have
package.json - (Optional) Tailwind CSS installed if using store managers with UI
Interactive Mode
If you don't specify all options, the CLI will ask you:
avangcli module user-profileThe CLI will ask:
- Which store manager do you want to use? (zustand, redux, none)
Options
<module-name>
- Type: Positional (required)
- Format: kebab-case (e.g.,
user-profile,shopping-cart) - Description: Name of the module to create
- Example:
avangcli module user-profile
--store, --st
- Type: String
- Options:
zustand,redux,none - Description: State manager to use
- Example:
--store zustand
--set-default-global, -g
- Type: Boolean
- Description: Sets the chosen store manager as the global default
- Example:
-g
--set-default-project, -p
- Type: Boolean
- Description: Sets the store manager as default for the current project
- Example:
-p
--skip-validation, -s
- Type: Boolean
- Description: Skips Next.js project validation (use with caution)
- Example:
--skip-validation
Usage Examples
Example 1: Basic Module (Interactive Mode)
avangcli module user-profileThe CLI will ask which store manager to use.
Example 2: Module with Zustand
avangcli module shopping-cart --store zustandCreates the module with Zustand store configured.
Example 3: Module with Redux and Global Default
avangcli module authentication --store redux -gCreates module with Redux and sets it as global default for future modules.
Example 4: Module with Project Default
avangcli module products --store zustand -pUses Zustand and saves it as default for this project.
Example 5: Without Store Manager
avangcli module blog-posts --store noneCreates the module without state configuration.
Example 6: Multiple Modules with Saved Config
# First module: set Zustand as default
avangcli module user --store zustand -p
# Following modules use Zustand automatically
avangcli module products
avangcli module orders
avangcli module reviewsGenerated Module Structure
Complete Structure
app/modules/user-profile/
├── components/ # Reusable UI components
├── containers/ # Container components
│ └── user-profile-container.tsx
├── services/ # Business logic
│ └── user-profile.service.ts
├── types/ # TypeScript definitions
│ └── user-profile.types.ts
├── hooks/ # Custom React hooks
├── store/ # Module state
│ ├── user-profile.store.ts (Zustand)
│ └── user-profile.slice.ts (Redux)
├── adapters/ # Adapters for external APIs
├── helpers/ # Utility functions
├── lib/ # Specific utilities
└── index.ts # Barrel exportIf src/ directory exists
The CLI automatically detects if the project uses src/:
src/modules/user-profile/
└── ... (same structure)Generated Files
1. Container (user-profile-container.tsx)
'use client'
import React from 'react'
interface UserProfileContainerProps {
// Add your props here
}
/**
* UserProfileContainer
*
* Main container component for the user-profile module.
* Handles the main logic and state management for this feature.
*/
export const UserProfileContainer: React.FC<UserProfileContainerProps> = (props) => {
// Add your logic here
return (
<div className="user-profile-container">
<h1>UserProfile Module</h1>
<p>This is the main container for the user-profile module.</p>
</div>
)
}
UserProfileContainer.displayName = 'UserProfileContainer'2. Service (user-profile.service.ts)
/**
* UserProfileService
*
* Service class for handling user-profile module business logic.
* Implements the singleton pattern for consistent state management.
*/
export class UserProfileService {
private static instance: UserProfileService
private constructor() {
this.initialize()
}
public static getInstance(): UserProfileService {
if (!UserProfileService.instance) {
UserProfileService.instance = new UserProfileService()
}
return UserProfileService.instance
}
private initialize(): void {
// Add initialization logic here
}
public async fetchData(): Promise<any> {
try {
return { message: "UserProfile data" }
} catch (error) {
console.error("Error fetching user-profile data:", error)
throw error
}
}
public processData(data: any): any {
return data
}
}
export const userProfileService = UserProfileService.getInstance()3. Types (user-profile.types.ts)
export interface UserProfileData {
id: string
// Add your data properties here
}
export interface UserProfileState {
isLoading: boolean
error: string | null
data: UserProfileData | null
}
export interface UserProfileActions {
fetch: () => Promise<void>
reset: () => void
}
export type UserProfileStatus = "idle" | "loading" | "success" | "error"4. Zustand Store (user-profile.store.ts)
import { create } from "zustand"
import type { UserProfileData, UserProfileState } from "../types/user-profile.types"
interface UserProfileStore extends UserProfileState {
setData: (data: UserProfileData | null) => void
setLoading: (isLoading: boolean) => void
setError: (error: string | null) => void
reset: () => void
}
const initialState: UserProfileState = {
isLoading: false,
error: null,
data: null
}
export const useUserProfileStore = create<UserProfileStore>((set) => ({
...initialState,
setData: (data) => set({ data, error: null }),
setLoading: (isLoading) => set({ isLoading }),
setError: (error) => set({ error, isLoading: false }),
reset: () => set(initialState)
}))5. Redux Slice (user-profile.slice.ts)
import { createSlice, PayloadAction } from "@reduxjs/toolkit"
import type { UserProfileData, UserProfileState } from "../types/user-profile.types"
const initialState: UserProfileState = {
isLoading: false,
error: null,
data: null
}
const userProfileSlice = createSlice({
name: "user-profile",
initialState,
reducers: {
setData: (state, action: PayloadAction<UserProfileData | null>) => {
state.data = action.payload
state.error = null
},
setLoading: (state, action: PayloadAction<boolean>) => {
state.isLoading = action.payload
},
setError: (state, action: PayloadAction<string | null>) => {
state.error = action.payload
state.isLoading = false
},
reset: (state) => {
Object.assign(state, initialState)
}
}
})
export const userProfileActions = userProfileSlice.actions
export const userProfileReducer = userProfileSlice.reducer
// Selectors
export const selectUserProfileData = (state: { userProfile: UserProfileState }) => state.userProfile.data
export const selectUserProfileLoading = (state: { userProfile: UserProfileState }) => state.userProfile.isLoading
export const selectUserProfileError = (state: { userProfile: UserProfileState }) => state.userProfile.error6. Barrel Export (index.ts)
/**
* UserProfile Module
*
* Barrel export file for the user-profile module.
*/
// Containers
export { UserProfileContainer } from "./containers/user-profile-container"
// Services
export { UserProfileService, userProfileService } from "./services/user-profile.service"
// Types
export type {
UserProfileData,
UserProfileState,
UserProfileActions,
UserProfileStatus
} from "./types/user-profile.types"
// Zustand Store (if used)
export { useUserProfileStore } from "./store/user-profile.store"
// Redux Store (if used)
export { userProfileActions, userProfileReducer } from "./store/user-profile.slice"
export { selectUserProfileData, selectUserProfileLoading, selectUserProfileError } from "./store/user-profile.slice"What Does the Command Do?
1. Validates Next.js Project
# Verifies:
- ✅ package.json exists
- ✅ next.config.js exists
- ✅ app/ or pages/ exists
- ✅ Detects Next.js version
- ✅ Detects if using src/2. Checks that Module Doesn't Exist
# Prevents overwriting existing modules
❌ Error: Module "user-profile" already exists3. Creates Folder Structure
# Creates 9 folders:
✓ components/
✓ containers/
✓ adapters/
✓ types/
✓ services/
✓ hooks/
✓ store/
✓ lib/
✓ helpers/4. Generates Boilerplate Files
✓ containers/user-profile-container.tsx
✓ services/user-profile.service.ts
✓ types/user-profile.types.ts
✓ store/user-profile.store.ts (if Zustand)
✓ store/user-profile.slice.ts (if Redux)
✓ index.ts5. Installs Dependencies (if necessary)
# If using Zustand and it's not installed
📦 Installing zustand...
# If using Redux and it's not installed
📦 Installing @reduxjs/toolkit...Naming Conventions
Input (kebab-case)
avangcli module user-profile
avangcli module shopping-cart
avangcli module product-reviewsGenerated Files
user-profile-container.tsx # kebab-case
user-profile.service.ts # kebab-case
user-profile.types.ts # kebab-case
user-profile.store.ts # kebab-caseClasses and Components (PascalCase)
UserProfileContainer
UserProfileService
UserProfileDataInstances and Hooks (camelCase)
userProfileService
useUserProfileStoreUsing the Generated Module
In a Page
// app/profile/page.tsx
import { UserProfileContainer } from '@/modules/user-profile'
export default function ProfilePage() {
return <UserProfileContainer />
}Using the Service
import { userProfileService } from "@/modules/user-profile"
async function loadProfile() {
const data = await userProfileService.fetchData()
console.log(data)
}Using Zustand Store
'use client'
import { useUserProfileStore } from '@/modules/user-profile'
export function ProfileComponent() {
const { data, setData, setLoading } = useUserProfileStore()
return <div>{data?.name}</div>
}Using Redux Store
// 1. Add to store
import { userProfileReducer } from '@/modules/user-profile'
export const store = configureStore({
reducer: {
userProfile: userProfileReducer,
},
})
// 2. Use in components
import { useSelector, useDispatch } from 'react-redux'
import { userProfileActions, selectUserProfileData } from '@/modules/user-profile'
export function ProfileComponent() {
const data = useSelector(selectUserProfileData)
const dispatch = useDispatch()
const handleLoad = () => {
dispatch(userProfileActions.setLoading(true))
}
return <div>{data?.name}</div>
}Default Configuration
Global Default
# Saved in ~/.avangcli/config.json
avangcli module auth --store zustand -g
# All future modules will use Zustand
avangcli module products # Uses Zustand automaticallyProject Default
# Saved in .avangcli.json at project root
avangcli module auth --store redux -p
# Only in this project will use Redux
avangcli module products # Uses Redux automaticallyDefault Priority
- CLI argument (
--store zustand) - Project default (
.avangcli.json) - Global default (
~/.avangcli/config.json) - Interactive prompt
Tips and Best Practices
1. Use Defaults for Large Projects
# At project start
avangcli module users --store zustand -p
# All other modules will be consistent
avangcli module products
avangcli module orders
avangcli module analytics2. Organize by Domain
# E-commerce
avangcli module products
avangcli module shopping-cart
avangcli module checkout
avangcli module orders
# Dashboard
avangcli module analytics
avangcli module reports
avangcli module settings3. Descriptive Names
✅ GOOD:
avangcli module user-authentication
avangcli module product-catalog
avangcli module order-history❌ BAD:
avangcli module auth # Too short
avangcli module prods # Confusing abbreviation
avangcli module module1 # Not descriptiveTroubleshooting
Error: "Not a valid Next.js project"
Cause: You're not in a Next.js project or key files are missing.
Solution:
# Verify these exist:
ls package.json
ls next.config.js
ls app/ # or pages/
# Or use skip-validation (not recommended)
avangcli module my-module --skip-validationError: "Module already exists"
Cause: A module with that name already exists.
Solution:
# Choose another name
avangcli module user-profile-v2
# Or delete existing module
rm -rf app/modules/user-profileError: "Invalid module name"
Cause: Name with invalid characters.
Solution:
# Use kebab-case
avangcli module user-profile ✅
avangcli module UserProfile ❌
avangcli module user_profile ❌Store Manager Not Installing
Solution:
# Install manually
npm install zustand
# or
npm install @reduxjs/toolkitNext Steps
After generating a module:
-
Customize the Container
- Add necessary props
- Implement UI logic
-
Implement the Service
- Add business methods
- Connect with APIs
-
Define Types
- Add specific interfaces
- Extend base types
-
Configure the Store
- Add necessary actions
- Implement selectors
-
Add Tests
bash# Create test files touch app/modules/user-profile/__tests__/user-profile.test.tsCopied to clipboard!
Related Resources
Last updated: 9/22/2026