ShipKit Next.js Development
Expert guidance for TypeScript, Node.js, Next.js App Router, React, Shadcn UI, Radix UI and Tailwind development following production-ready best practices.
Project Stack
This skill optimizes development for Next.js projects using:
Next.js App RouterShadcn/UI & Radix UITailwind CSSTypeScriptPNPM package managerOptional: Resend, Builder.io, Payload CMS 3, NextAuth/AuthJS@v5Instructions
1. Check for Existing AI Documentation
Look for `ai.mdx` file at project rootIf exists, read it to understand completed workMark completed steps with checkboxesUpdate file as you progress so another AI can continue2. Follow Key Principles
**Code Style:**
Write concise, technical TypeScript code with accurate examplesUse functional and declarative programming patterns; avoid classesPrefer iteration and modularization over code duplicationUse descriptive variable names with auxiliary verbs (e.g., `isLoading`, `hasError`)Structure files: exported component, subcomponents, helpers, static content, types**Naming Conventions:**
Use lowercase with dashes for directories (e.g., `components/auth-wizard`)Favor named exports for componentsPrefer `hyphen-case.ext` over `CamelCase.ext` for filenames3. TypeScript Standards
Use TypeScript for all codePrefer interfaces over typesAvoid enums; use maps insteadUse functional components with TypeScript interfacesPre-emptively add types to all functions and variablesFix all TypeScript errors and warnings4. React Component Patterns
**Preferred Syntax:**
```typescript
// ✅ Correct - Arrow function
export const Component = () => { ... }
// ❌ Avoid
export function Component() { ... }
export default function Component() { ... }
```
**General Rules:**
Use functional components and hooks for state managementEnsure components are reusable and maintainableUse the "function" keyword for pure functionsAvoid unnecessary curly braces in conditionalsUse declarative JSX5. Next.js App Router Best Practices
**Server vs Client Components:**
Minimize `use client`, `useEffect`, and `setState`Favor React Server Components (RSC)Only use `use client` for Web API access in small componentsAvoid `use client` for data fetching or state managementWrap client components in Suspense with fallbackDon't nest server components in client components unless passed through props**Data Fetching:**
❌ DO NOT fetch data with server actions✅ Use Server Components for data fetchingServer code belongs in `@/server/services`Server action code belongs in `@/server/actions`Server actions should call services when needing server-side code**File Structure:**
Use `@/server/actions` for all server actionsUse `@/server/services` for all internal services6. UI and Styling
Use Shadcn UI, Radix, and Tailwind for components and stylingImplement responsive design with Tailwind CSSUse mobile-first approachFollow Tailwind CSS conventionsEnsure responsive design for all componentsPrioritize accessibility in UI design7. Performance Optimization
**Images:**
Use WebP formatInclude size dataImplement lazy loading**Loading:**
Use dynamic loading for non-critical componentsOptimize Web Vitals (LCP, CLS, FID)**Dependencies:**
Minimize heavy libraries and dependenciesRegularly audit performance metrics8. Database Interactions
When working with databases:
1. Ensure all required fields are provided
2. Check for potential undefined values and handle appropriately
3. Use TypeScript's type system to enforce correct data structures
4. Implement error handling for database operations
5. Validate input data to prevent runtime errors
6. Use `db.transaction` for atomicity when performing multiple operations
7. Use dates instead of boolean values (e.g., `activeAt: Date` not `isActive: boolean`)
9. API Integration
Use environment variables for sensitive data like API keysNever delete environment variablesHandle API errors gracefully and provide user feedbackUse async/await for asynchronous operationsDocument API interactions and expected responsesPrefer server actions for internal API requests10. Code Quality Standards
**Comments:**
Pre-emptively add comments to explain "why" behind the codeDon't modify comments or functionality unrelated to the promptPreserve all existing comments unless specifically askedUse comments with callouts and examples:```typescript
/*
* Logging configuration
* @see https://nextjs.org/docs/app/api-reference/next-config-js/logging
*/
```
When showing code changes, use `// ...` to indicate unchanged sections**Coding Conventions:**
Pre-emptively ask questions if unsure about requirementsPre-emptively optimize code for productionPre-emptively add types to all functions and variablesPre-emptively fix any TypeScript errors or warningsUse open-source libraries when they enhance UX/DXWrite production-ready codeFix bugs and improve performanceComment complex or hard-to-read code11. URL State Management
Use 'nuqs' for URL search parameter state management12. Critical Don'ts
❌ Don't delete environment variables❌ Don't nest server components in client components (unless passed through props)❌ Don't forget to add `use client` when using client-side code like hooks❌ Don't use `use client` in server components❌ Don't fetch data with server actions (use Server Components)Examples
Server Component with Service
```typescript
// app/dashboard/page.tsx
import { getUsers } from '@/server/services/user-service'
export const DashboardPage = async () => {
const users = await getUsers()
return (
<div className="grid gap-4">
{users.map((user) => (
<UserCard key={user.id} user={user} />
))}
</div>
)
}
```
Client Component with Server Action
```typescript
// components/user-form.tsx
'use client'
import { updateUser } from '@/server/actions/user-actions'
import { useState } from 'react'
export const UserForm = ({ userId }: { userId: string }) => {
const [isLoading, setIsLoading] = useState(false)
const handleSubmit = async (formData: FormData) => {
setIsLoading(true)
await updateUser(userId, formData)
setIsLoading(false)
}
return <form action={handleSubmit}>...</form>
}
```
Service Calling Database
```typescript
// server/services/user-service.ts
import { db } from '@/lib/db'
export const getUsers = async () => {
return await db.user.findMany({
where: { deletedAt: null }, // Use dates not booleans
select: {
id: true,
name: true,
email: true,
},
})
}
```
Constraints
Always use TypeScript, never plain JavaScriptPNPM is the package manager - don't use npm or yarn commandsFollow Next.js App Router conventions, not Pages RouterMaintain separation of concerns: services for data, actions for mutations, components for UIReference Next.js documentation for Data Fetching, Rendering, and Routing patterns