Windsurf is the world's first AI-native IDE that uses a unique "Flows" system to maintain persistent context throughout your development session. Unlike traditional rules files, Windsurf's approach is more dynamic and conversational, but you still need clear guidelines to get the best results.
This guide provides ready-to-use rules and patterns that make Windsurf's Cascade AI work optimally for your projects.
Windsurf is fundamentally different from other AI coding tools:
The key is feeding Windsurf the right context at the start and updating it as you work.
When starting a new session, initialize your Flow with this template:
I'm working on [PROJECT_NAME], a [PROJECT_DESCRIPTION].
Tech Stack:
- [Language/Framework]
- [Database]
- [Key libraries]
Architecture:
- [Brief architecture description]
Current Focus:
- [What you're working on right now]
Please follow the coding standards and patterns I'll describe below.
While Windsurf doesn't have a traditional .rules file, you can create a .windsurf/context.md file in your repository:
# Windsurf Project Context
[Your rules go here - Windsurf can reference this file]
## Flow Management
- Maintain context throughout the entire coding session
- Update Flow when switching between features or modules
- Reference previous decisions made in this session
- Ask for clarification before making architectural changes
- Keep track of TODO items and next steps within the Flow
## Code Style Standards
Follow these conventions in all generated code:
### Naming
- Variables and functions: camelCase
- Classes and components: PascalCase
- Constants: UPPER_SNAKE_CASE
- Private methods: prefix with underscore
- Boolean variables: start with is/has/should/can
### Function Guidelines
- Maximum 50 lines per function
- Single responsibility principle
- Maximum 3 parameters (use options object for more)
- Maximum 3 levels of nesting
- Use early returns to reduce complexity
### Code Organization
- Group related functionality together
- Import order: external → internal → relative → types → styles
- One component per file (except small related components)
- Colocate tests with implementation
## TypeScript/JavaScript Standards
### Type Safety
- Strict mode enabled always
- No `any` types - use `unknown` if type is truly uncertain
- Define interfaces for all object shapes
- Use `type` for unions, aliases, and intersections
- Optional chaining (`?.`) and nullish coalescing (`??`) preferred
### Modern JavaScript
- Use `const` by default, `let` only when reassignment needed
- Arrow functions for callbacks and short functions
- Template literals over string concatenation
- Async/await over raw promises
- Destructuring for object and array access
- Spread operator for object/array copying
### Example Pattern
```typescript
// ✅ Preferred
interface UserData {
id: string;
name: string;
email: string;
}
const fetchUser = async (id: string): Promise<UserData> => {
const response = await api.get(`/users/${id}`);
return response.data;
};
// ❌ Avoid
function fetchUser(id: any) {
return new Promise((resolve, reject) => {
api.get('/users/' + id).then(function(response) {
resolve(response.data);
});
});
}
### React Flow Rules
```markdown
## React Development Patterns
### Component Structure
- Functional components only (no classes)
- TypeScript interfaces for all props
- Named exports preferred
- Props interface defined separately
### Component Template
```typescript
interface ComponentNameProps {
prop1: string;
prop2: number;
onAction?: () => void;
}
export const ComponentName = ({ prop1, prop2, onAction }: ComponentNameProps) => {
// 1. Hooks (always at top level)
const [state, setState] = useState<Type>(initialValue);
const queryResult = useQuery(...);
// 2. Derived state and computations
const derivedValue = useMemo(() => compute(state), [state]);
// 3. Event handlers
const handleClick = useCallback(() => {
// handler logic
onAction?.();
}, [onAction]);
// 4. Effects (if needed)
useEffect(() => {
// effect logic
return () => cleanup();
}, [dependencies]);
// 5. Early returns for loading/error states
if (queryResult.isLoading) return <LoadingSpinner />;
if (queryResult.error) return <ErrorMessage />;
// 6. Main render
return (
<div>
{/* Component content */}
</div>
);
};
### Python Flow Rules
```markdown
## Python Development Standards
### Style Guide
- Follow PEP 8 strictly
- Maximum line length: 88 characters (Black formatter)
- Use type hints for all function signatures
- Docstrings in Google style for all public functions
### Modern Python Patterns
```python
from typing import List, Dict, Optional
from dataclasses import dataclass
@dataclass
class User:
"""User data model."""
id: str
email: str
name: str
is_active: bool = True
def process_users(
users: List[User],
filter_active: bool = True
) -> List[Dict[str, str]]:
"""
Process user list and return formatted data.
Args:
users: List of User objects to process
filter_active: Whether to filter for active users only
Returns:
List of dictionaries with formatted user data
Raises:
ValueError: If users list is empty
"""
if not users:
raise ValueError("Users list cannot be empty")
filtered = [u for u in users if not filter_active or u.is_active]
return [{"id": u.id, "display": f"{u.name} ({u.email})"} for u in filtered]
except:
### Testing Flow Rules
```markdown
## Testing Standards
### Test Coverage
- Minimum 80% code coverage
- Test happy path, edge cases, and error conditions
- Integration tests for critical user flows
- E2E tests for business-critical features
### Test Structure (AAA Pattern)
```typescript
describe('UserService', () => {
describe('createUser', () => {
it('should create user with valid data', async () => {
// Arrange
const userData = { name: 'John', email: 'john@example.com' };
const mockDb = createMockDb();
const service = new UserService(mockDb);
// Act
const result = await service.createUser(userData);
// Assert
expect(result.success).toBe(true);
expect(result.data.email).toBe(userData.email);
expect(mockDb.insert).toHaveBeenCalledWith(userData);
});
it('should reject invalid email format', async () => {
// Arrange
const userData = { name: 'John', email: 'invalid-email' };
const service = new UserService(createMockDb());
// Act
const result = await service.createUser(userData);
// Assert
expect(result.success).toBe(false);
expect(result.error).toContain('Invalid email');
});
});
});
### API Design Flow Rules
```markdown
## API Development Standards
### RESTful Conventions
- Use resource-based URLs with plural nouns
- HTTP methods: GET (read), POST (create), PUT (update), DELETE (remove)
- Version APIs in URL: `/api/v1/`
- Consistent response format across all endpoints
### Response Format
```typescript
// Success response
{
success: true,
data: {
// Response payload
},
meta?: {
pagination?: {
page: number,
pageSize: number,
totalPages: number,
totalItems: number
}
}
}
// Error response
{
success: false,
error: {
message: "Human-readable error message",
code: "ERROR_CODE",
details?: any
}
}
GET /api/v1/users - List users (with pagination)
GET /api/v1/users/:id - Get specific user
POST /api/v1/users - Create new user
PUT /api/v1/users/:id - Update entire user
PATCH /api/v1/users/:id - Partial update user
DELETE /api/v1/users/:id - Delete user
GET /api/v1/users/:id/posts - Get user's posts (nested resource)
### Database Flow Rules
```markdown
## Database Standards
### Schema Design
- Use UUIDs for primary keys (or BigInt for huge scale)
- Add `created_at` and `updated_at` to all tables
- Implement soft deletes with `deleted_at` nullable timestamp
- Use foreign keys with proper constraints
- Create indexes for frequently queried columns
### Query Patterns
```typescript
// ✅ Use ORM/Query Builder
const users = await db
.select('*')
.from('users')
.where('deleted_at', null)
.where('is_active', true)
.orderBy('created_at', 'desc')
.limit(50);
// ❌ Avoid raw SQL strings (SQL injection risk)
const users = await db.raw(`SELECT * FROM users WHERE email = '${email}'`);
// ✅ If raw SQL needed, use parameterized queries
const users = await db.raw('SELECT * FROM users WHERE email = ?', [email]);
### Security Flow Rules
```markdown
## Security Standards
### Environment & Secrets
- Never commit secrets, API keys, or passwords to git
- Use environment variables for all sensitive config
- Different .env files for dev/staging/prod
- Add .env to .gitignore immediately
### Input Validation
```typescript
// ✅ Validate all user input
import { z } from 'zod';
const UserSchema = z.object({
email: z.string().email(),
age: z.number().min(18).max(120),
name: z.string().min(2).max(100)
});
// This throws if validation fails
const validatedData = UserSchema.parse(untrustedInput);
### Error Handling Flow Rules
```markdown
## Error Handling Patterns
### Async Error Handling
```typescript
// ✅ Always use try-catch with async/await
async function fetchUserData(id: string): Promise<Result<User>> {
try {
const response = await api.get(`/users/${id}`);
return { success: true, data: response.data };
} catch (error) {
console.error('Failed to fetch user:', error);
if (error.response?.status === 404) {
return { success: false, error: 'User not found' };
}
return {
success: false,
error: 'Failed to fetch user data. Please try again.'
};
}
}
class ValidationError extends Error {
constructor(
message: string,
public field: string,
public value: any
) {
super(message);
this.name = 'ValidationError';
}
}
class NotFoundError extends Error {
constructor(resource: string, id: string) {
super(`${resource} with id ${id} not found`);
this.name = 'NotFoundError';
}
}
### Performance Flow Rules
```markdown
## Performance Optimization
### Frontend Performance
- Lazy load routes and components
- Code splitting for large bundles
- Optimize images (WebP format, next/image)
- Implement virtual scrolling for long lists
- Use CDN for static assets
- Cache API responses appropriately
- Minimize main thread blocking
### Database Performance
- Add indexes for WHERE, JOIN, ORDER BY columns
- Use connection pooling
- Implement query result caching
- Paginate large datasets
- Avoid N+1 queries (use eager loading)
- Monitor slow queries
### API Performance
- Implement response caching (Redis)
- Use compression (gzip/brotli)
- Rate limiting to prevent abuse
- Batch similar requests when possible
- Implement proper pagination
## Documentation Standards
### Code Documentation
```typescript
/**
* Calculates the discounted price with tax applied.
*
* This function first applies the discount percentage to the base price,
* then adds the appropriate tax based on the tax rate.
*
* @param basePrice - The original price before any modifications
* @param discountPercent - Discount as a percentage (0-100)
* @param taxRate - Tax rate as a decimal (e.g., 0.08 for 8%)
* @returns The final price after discount and tax
*
* @throws {Error} If basePrice is negative
* @throws {Error} If discountPercent is not between 0 and 100
*
* @example
* ```typescript
* const finalPrice = calculatePrice(100, 10, 0.08);
* // Result: 97.2 (100 - 10% discount, then + 8% tax)
* ```
*/
function calculatePrice(
basePrice: number,
discountPercent: number,
taxRate: number
): number {
if (basePrice < 0) throw new Error('Base price cannot be negative');
if (discountPercent < 0 || discountPercent > 100) {
throw new Error('Discount must be between 0 and 100');
}
const discounted = basePrice * (1 - discountPercent / 100);
return discounted * (1 + taxRate);
}
## How to Use These Rules in Windsurf
### Method 1: Initial Flow Context
Start each session by providing context:
Hi Windsurf! I'm working on an e-commerce platform.
Tech Stack: React, TypeScript, Next.js 14, PostgreSQL, Prisma
Follow these standards:
Currently working on: User authentication flow
Let's begin!
### Method 2: Create Context File
Create `.windsurf/context.md`:
```markdown
# Project Context for Windsurf
[Paste relevant rules from this guide]
## Current Sprint Goals
- [ ] Implement user authentication
- [ ] Add payment processing
- [ ] Create admin dashboard
Reference it: "Follow the guidelines in .windsurf/context.md"
When changing focus:
Update Flow: We've completed the auth system.
Now focusing on payment integration with Stripe.
Continue following our coding standards.
Give Windsurf autonomy:
Command Mode: Create a complete user profile editing feature following our React and TypeScript standards. Include:
- Profile form component
- Image upload with preview
- Form validation with Zod
- API integration
- Loading and error states
- Unit tests
Windsurf's Cascade AI can handle multi-step reasoning:
"Create a blog post feature. Think through:
1. Database schema design
2. API endpoints needed
3. React components structure
4. State management approach
5. Testing strategy
Then implement following our project standards."
Supercomplete learns from your patterns:
Use Command Mode when:
Use Chat Mode when:
## Next.js Standards
- Use App Router (not Pages Router)
- Server Components by default
- Add 'use client' only when needed (hooks, browser APIs)
- Use Server Actions for mutations
- Implement loading.tsx and error.tsx
- Proper metadata for SEO
app/
├── (auth)/
│ ├── login/
│ │ └── page.tsx
│ └── register/
│ └── page.tsx
├── dashboard/
│ ├── layout.tsx
│ ├── page.tsx
│ ├── loading.tsx
│ └── error.tsx
└── api/
└── v1/
└── users/
└── route.ts
## Django Standards
- Follow MVT pattern strictly
- Use class-based views for CRUD
- Django REST framework for APIs
- Serializers for all API responses
- Use Django ORM (avoid raw SQL)
- Proper migrations for all model changes
project/
├── apps/
│ ├── users/
│ │ ├── models.py
│ │ ├── views.py
│ │ ├── serializers.py
│ │ └── tests/
│ └── posts/
├── config/
│ ├── settings/
│ └── urls.py
└── manage.py
Solution: Be more explicit in initial Flow setup. Provide examples of your preferred patterns.
Solution: Periodically update your Flow with "Still following our TypeScript standards..." to reinforce context.
Solution: Switch from Command Mode to Chat Mode for more control. Break tasks into smaller pieces.
Solution: Reference specific files: "Following the pattern in UserService.ts, create OrderService"
Here's a complete Flow initialization for a new e-commerce project:
Hi Windsurf! Starting a new e-commerce platform project.
## Tech Stack
- Frontend: React 18, TypeScript, Next.js 14, Tailwind CSS
- Backend: Node.js, Express, PostgreSQL
- ORM: Prisma
- Testing: Vitest, React Testing Library
- State: React Query for server state, Zustand for global client state
## Architecture
Clean architecture with layers:
- /app - Next.js pages and routes
- /components - Reusable React components
- /lib - Business logic and services
- /db - Database schemas and migrations
## Coding Standards
- TypeScript strict mode
- Functional components only
- Max 50 lines per function
- 80% test coverage
- RESTful API with /api/v1/ prefix
## Current Focus
Building the core product catalog feature with:
- Product listing with pagination
- Product detail pages
- Search and filtering
- Shopping cart
Follow these standards in all generated code. Let's start with the product database schema.