Next.js Cross-Platform Development
Build Next.js applications with React Native conversion in mind. These rules guide you to write portable, maintainable code that can be adapted to mobile platforms with minimal refactoring.
Tech Stack
**Next.js with App Router**: Core framework for routing, server components, and API routes**TypeScript**: Type-safe code across the entire stack**Prisma with SQLite**: ORM and database for data persistence**TailwindCSS**: Utility-first styling**React Hooks**: `useState`, `useEffect`, `useContext` for all client-side state managementProject Structure
Organize code in a `/src` directory with clear separation of concerns:
```
/src
/components
/ui # Reusable UI primitives
/features # Feature-specific components
/hooks # Custom React hooks
/services # API and data services
/utils # Pure utility functions
/constants # Type-safe constants
/context # React context providers
/types # Shared TypeScript types
/styles # Global styles and theme
```
**Rules:**
Keep component files, styles, types, and README together in the same folderInclude README.md files documenting props, usage, and implementation detailsMaintain consistent naming conventions across all filesComponent Architecture
Build components that are highly reusable and mobile-ready:
**Create "dumb" UI components** that are highly configurable through props**Use container/presentational pattern** to separate data fetching from UI rendering**Keep components small** (under 200 lines of code)**Favor composition over inheritance** when building complex components**Include props for error and loading states** in all data-dependent components**Design with accessibility in mind** (proper ARIA attributes from the start)**Document component APIs** thoroughly in README filesTypeScript Implementation
Enforce strict type safety to catch errors early:
Enable **strict mode** in `tsconfig.json`Create **shared types** in `/types` for domain entitiesUse **discriminated unions** for different event types (e.g., feeding vs. diaper events)Implement **type guards** for safe type narrowingDefine **constants with `as const`** assertions for type safetyCreate **specific error types** that extend the base Error classUse **TypeScript generics** for reusable components and functionsDefine **readonly properties** for immutable dataState Management
Manage state predictably with hooks and context:
Implement **custom hooks** for complex state logicCreate **context providers** for global state accessed by multiple componentsUse **React Query** for data fetching with proper type definitionsFollow **immutable update patterns** in all state modificationsImplement **memoization** with `useMemo` for expensive computationsInclude **error and loading states** in all async operations**Design with offline-first principles** for future mobile supportStyling Approach
Create a portable, consistent design system:
Define a **shared design system** with consistent variables for colors, spacing, typographyUse **CSS Modules or Styled Components** for component stylingKeep styles **modular and component-specific**Implement **responsive design** using media queriesExport **theme as TypeScript constants**Support **light and dark modes** through a theme contextCreate **helper functions** for complex style logicNavigation
Plan navigation patterns that translate to mobile:
Use **Next.js file-system based routing**Define **strongly typed route parameters** with TypeScript interfacesCreate **navigation utilities** that consolidate route definitionsImplement **type-safe navigation helpers**Create **guards for protected routes** in middlewareDesign **consistent route structure** that mirrors future mobile routesMake routes **accessible and SEO-friendly**API and Data Fetching
Build a robust, type-safe API layer:
Create a **type-safe fetch wrapper** with proper error handlingImplement **domain-specific API services** that use the core API layerUse **React Query** for data fetching with consistent query key patternsImplement **error handling** that provides clear user feedbackDefine **optimistic updates** for better UXStructure **API responses with consistent types****Design with offline capabilities** in mind for future mobile supportForm Handling
Manage forms with validation and accessibility:
Use **React Hook Form** for form state management and validationCreate **reusable validation rules**Implement **consistent error message styling**Create **type-safe form components**Consider a **form builder pattern** for complex formsHandle **form submission with loading and error states**Make forms **accessible** with proper labels and ARIA attributesTesting
Ensure reliability across platforms:
Write tests for **all components, custom hooks, and services**Test **error and loading states**Verify **accessibility features**Test **responsive layouts**Implement **integration tests** for complex featuresMobile Considerations
Write code that translates to React Native:
**Avoid web-specific APIs** that don't exist in React NativeDesign UI with **touch interaction in mind** (larger touch targets)**Consider offline capabilities** from the start**Plan for cross-platform navigation patterns****Document any web-specific behavior** that will need adaptation for mobileCode Modification Guidelines
Write lean, intentional code:
**Challenge yourself to write as few lines of code as possible****Preserve all formatting and styling** when changing existing code unless explicitly asked to modify**Make only the changes** that have been discussed and approved**Maintain all existing functionality** when making modifications**Ask questions about any ambiguous requirements** before implementing changes**Perform due diligence** to ensure accuracy and minimize rewritesExamples
Type-Safe API Service
```typescript
// services/babyEvents.ts
import { BabyEvent, BabyEventType } from '@/types/babyEvent';
export class BabyEventService {
static async getEvents(babyId: string): Promise<BabyEvent[]> {
const response = await fetch(`/api/babies/${babyId}/events`);
if (!response.ok) throw new Error('Failed to fetch events');
return response.json();
}
static async createEvent(event: Omit<BabyEvent, 'id'>): Promise<BabyEvent> {
const response = await fetch('/api/events', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(event),
});
if (!response.ok) throw new Error('Failed to create event');
return response.json();
}
}
```
Container/Presentational Pattern
```typescript
// components/features/BabyEventList/BabyEventListContainer.tsx
'use client';
import { useQuery } from '@tanstack/react-query';
import { BabyEventService } from '@/services/babyEvents';
import { BabyEventList } from './BabyEventList';
export function BabyEventListContainer({ babyId }: { babyId: string }) {
const { data, isLoading, error } = useQuery({
queryKey: ['babyEvents', babyId],
queryFn: () => BabyEventService.getEvents(babyId),
});
return <BabyEventList events={data} isLoading={isLoading} error={error} />;
}
// components/features/BabyEventList/BabyEventList.tsx
import { BabyEvent } from '@/types/babyEvent';
interface BabyEventListProps {
events?: BabyEvent[];
isLoading: boolean;
error: Error | null;
}
export function BabyEventList({ events, isLoading, error }: BabyEventListProps) {
if (isLoading) return <LoadingSpinner />;
if (error) return <ErrorMessage error={error} />;
if (!events?.length) return <EmptyState />;
return (
<ul>
{events.map(event => (
<BabyEventCard key={event.id} event={event} />
))}
</ul>
);
}
```
Custom Hook with Immutable Updates
```typescript
// hooks/useBabyEvents.ts
import { useState, useCallback } from 'react';
import { BabyEvent } from '@/types/babyEvent';
export function useBabyEvents(initialEvents: BabyEvent[] = []) {
const [events, setEvents] = useState<BabyEvent[]>(initialEvents);
const addEvent = useCallback((event: BabyEvent) => {
setEvents(prev => [...prev, event]);
}, []);
const removeEvent = useCallback((id: string) => {
setEvents(prev => prev.filter(e => e.id !== id));
}, []);
const updateEvent = useCallback((id: string, updates: Partial<BabyEvent>) => {
setEvents(prev => prev.map(e => (e.id === id ? { ...e, ...updates } : e)));
}, []);
return { events, addEvent, removeEvent, updateEvent };
}
```
Key Takeaways
1. **Write portable code**: Avoid web-specific APIs; design for touch and offline
2. **Separate concerns**: Use container/presentational pattern and custom hooks
3. **Embrace TypeScript**: Strict types, discriminated unions, type guards
4. **Plan for mobile**: Large touch targets, offline-first, consistent navigation
5. **Write less code**: Challenge yourself to minimize lines while maintaining clarity