Expert guidance for building full-stack TypeScript applications with Next.js, React, TailwindCSS, Clerk authentication, Supabase backend, Zod validation, Zustand state management, and TanStack Query.
Expert development guidelines for building modern full-stack applications with TypeScript, Next.js, React, TailwindCSS, Clerk.dev authentication, Supabase backend, Zod validation, Zustand state management, and TanStack React Query.
Use Clerk.dev for all authentication and user management needs in this project.
1. **Write concise, technical TypeScript code** with accurate examples that demonstrate best practices.
2. **Use functional and declarative programming patterns**:
- Avoid classes in favor of functional components and pure functions
- Prefer iteration and modularization over code duplication
- Break down complex logic into smaller, reusable functions
3. **Use descriptive variable names** with auxiliary verbs:
- `isLoading`, `hasError`, `canSubmit`, `shouldRender`
- Make intent clear through naming
4. **Structure files systematically**:
- Exported components at the top
- Subcomponents below
- Helper functions
- Static content and constants
- Types and interfaces at the bottom
5. **Favor named exports** for components and functions to improve refactoring and tree-shaking.
1. **Use TypeScript for all code**:
- Prefer interfaces over types for object shapes
- Use type aliases for unions, intersections, and utility types
- Enable strict mode in tsconfig.json
2. **Utilize Zod for schema validation**:
- Define schemas for all external data (API responses, form inputs, environment variables)
- Use `.parse()` for validation with errors, `.safeParse()` for safe validation
- Infer TypeScript types from Zod schemas using `z.infer<typeof schema>`
3. **Implement functional components** with TypeScript interfaces:
```typescript
interface ButtonProps {
label: string;
onClick: () => void;
isDisabled?: boolean;
}
export function Button({ label, onClick, isDisabled = false }: ButtonProps) {
// implementation
}
```
1. **Use the `function` keyword** for pure functions to improve hoisting and readability.
2. **Write declarative JSX**:
- Keep JSX clear and readable
- Extract complex conditional logic into variables or helper functions
- Use fragments (`<>`) to avoid unnecessary wrapper divs
1. **Implement responsive design with mobile-first approach**:
- Start with mobile styles, then add breakpoints for larger screens
- Use TailwindCSS utility classes consistently
- Leverage Tailwind's responsive modifiers (`sm:`, `md:`, `lg:`, `xl:`)
2. **Ensure styling consistency** between web and native applications when applicable.
1. **Use Zustand for state management**:
- Create focused stores for specific domains
- Use shallow comparison for selector optimization
- Implement middleware for persistence when needed
2. **Use TanStack React Query** for data fetching:
- Define query keys consistently
- Implement proper cache invalidation strategies
- Use mutations for data modifications with optimistic updates
- Configure stale times and cache times appropriately
1. **Prioritize error handling and edge cases**:
- Handle errors at the beginning of functions using guard clauses
- Validate inputs early and return/throw early
2. **Implement guard clauses**:
```typescript
function processUser(user: User | null) {
if (!user) return null;
if (!user.isActive) return null;
// Main logic here
}
```
3. **Implement proper error logging**:
- Log errors with context for debugging
- Show user-friendly error messages in the UI
- Never expose sensitive information in error messages
4. **Use custom error types** for consistent error handling across the application.
1. **Optimize for both web and mobile performance**:
- Lazy load components and routes with `next/dynamic`
- Optimize images with Next.js Image component
- Minimize bundle size by code splitting
- Use React.memo() and useMemo() judiciously
- Implement virtualization for long lists
1. **Use Supabase for backend services**:
- Leverage Supabase for authentication, database, and real-time subscriptions
- Follow Supabase Row Level Security (RLS) policies for data protection
- Use Supabase client for server and client-side operations
2. **Follow security best practices**:
- Never expose API keys or secrets in client-side code
- Validate all data with Zod schemas before sending to backend
- Implement proper authorization checks
3. **Use Uploadthing for image storage** and media management.
1. **Ensure code is clean and well-documented**:
- Add JSDoc comments for complex functions
- Write self-documenting code through clear naming
- Follow the project's established coding standards
2. **Implement consistent error handling and logging** across the entire application.
3. **Follow official documentation**:
- Adhere to Next.js App Router conventions
- Use recommended data fetching patterns (Server Components, streaming)
- Stay updated with latest best practices
When implementing features or fixing issues:
1. **Provide code snippets** that align with these guidelines
2. **Include brief explanations** for complex implementations
3. **Ensure clarity and correctness** - all code should be production-ready
4. **Demonstrate best practices** in performance, security, and maintainability
5. **Use TypeScript strictly** with proper type annotations
6. **Validate all external data** with Zod schemas
7. **Structure files consistently** following the project conventions
```typescript
// schemas/user.schema.ts
import { z } from 'zod';
export const userSchema = z.object({
id: z.string().uuid(),
email: z.string().email(),
name: z.string().min(1),
isActive: z.boolean(),
});
export type User = z.infer<typeof userSchema>;
// stores/user.store.ts
import { create } from 'zustand';
import type { User } from '@/schemas/user.schema';
interface UserStore {
user: User | null;
setUser: (user: User | null) => void;
}
export const useUserStore = create<UserStore>((set) => ({
user: null,
setUser: (user) => set({ user }),
}));
// components/UserProfile.tsx
import { useQuery } from '@tanstack/react-query';
import { useUserStore } from '@/stores/user.store';
import { userSchema } from '@/schemas/user.schema';
interface UserProfileProps {
userId: string;
}
export function UserProfile({ userId }: UserProfileProps) {
const { data: user, isLoading, error } = useQuery({
queryKey: ['user', userId],
queryFn: async () => {
const response = await fetch(`/api/users/${userId}`);
if (!response.ok) throw new Error('Failed to fetch user');
const data = await response.json();
return userSchema.parse(data);
},
});
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error loading user profile</div>;
if (!user) return null;
return (
<div className="rounded-lg border p-4 shadow-sm">
<h2 className="text-xl font-semibold">{user.name}</h2>
<p className="text-sm text-gray-600">{user.email}</p>
</div>
);
}
```
Follow these guidelines consistently to build robust, maintainable, and performant applications.
Leave a review
No reviews yet. Be the first to review this skill!
# Download SKILL.md from killerskills.ai/api/skills/typescript-nextjs-clerk-supabase-stack/raw