Design.dev design.dev

Windsurf Rules Guide

Learn how to configure and use Windsurf Rules to customize Cascade AI behavior in the Windsurf IDE (by Codeium). Rules let you define coding standards, project conventions, and workflow preferences that Cascade follows automatically.

What Are Windsurf Rules?

Windsurf Rules are configuration files that instruct Cascade AI to follow specific coding standards, conventions, and workflows. They act as persistent instructions that shape how Cascade generates and modifies code in your projects.

Quick Start: Want to skip the manual setup? Use the Windsurf Rules Generator to create rule files instantly with templates and a visual editor.

Why Use Rules?

Without rules, Cascade relies on its general training to make decisions about code style, architecture, and patterns. Rules let you override those defaults with your team's specific preferences:

Without Rules:
- Cascade guesses your coding style
- Inconsistent patterns across sessions
- You repeat the same instructions every conversation

With Rules:
- Cascade follows your exact coding standards
- Consistent output every time
- Preferences persist across all Cascade sessions

Windsurf Rules vs. Other IDE Rules

Windsurf Rules serve a similar purpose to Cursor Rules and Claude Skills, but are specific to the Windsurf IDE and its Cascade AI assistant. Each system has its own format and features:

Windsurf Rules (.windsurf/rules/)
- Configures Cascade AI in Windsurf IDE
- Supports activation modes (always on, manual, glob, model decision)
- Has global and workspace scopes

Cursor Rules (.cursor/rules/)
- Configures AI agents in Cursor IDE
- Uses always, auto-attached, agent-requested, and manual modes
- Has user-level and project-level scopes

Claude Skills (SKILL.md)
- Specialized task instructions for Claude agents
- Triggered by matching user requests
- Stored in .cursor/skills/ or global config

Rules vs Memories

Windsurf uses two complementary systems to customize Cascade: Rules and Memories. Understanding the difference is key to using them effectively.

Rules: Explicit Instructions

Rules are instructions you write to tell Cascade how to behave. They are deliberate, structured, and version-controlled:

Rules are:
- Written by you (developer-authored)
- Stored as files in .windsurf/rules/ or .windsurfrules
- Version-controlled with your project
- Applied based on activation mode (always, manual, glob, etc.)
- Focused on coding standards and conventions
- Shared across your team via the repository

Memories: Learned Context

Memories are contextual information that Cascade captures automatically during your conversations. They help Cascade remember important details across sessions:

Memories are:
- Auto-captured by Cascade during conversations
- Stored in Windsurf's internal data (not in project files)
- Not version-controlled
- Always available to Cascade across sessions
- Focused on project context and user preferences
- Personal to each developer

When to Use Each

Use Rules for:
- Coding standards (naming, formatting, patterns)
- Architecture decisions (file structure, imports)
- Framework-specific conventions (React, Vue, etc.)
- Team-wide standards that should be shared

Use Memories for:
- Project-specific context Cascade learns over time
- Personal preferences unique to your workflow
- Dynamic context that evolves as the project grows
- Details you don't need to explicitly document

Tip: Rules and Memories work together. Use rules for the explicit standards you want to enforce, and let Cascade build memories for the contextual knowledge it picks up over time. You can view and manage memories at docs.windsurf.com.

Rule Types

Windsurf supports two scopes for rules: Global Rules that apply to every workspace, and Workspace Rules that apply only to the current project.

Global Rules

Global rules apply across all your Windsurf workspaces. They're ideal for personal coding preferences that should follow you everywhere:

Good candidates for global rules:
- Preferred language (e.g., "Always respond in English")
- General coding style (tabs vs. spaces, semicolons)
- Communication preferences (concise vs. detailed)
- Universal patterns (error handling, logging)
- Personal conventions (naming, documentation style)

Global rules are created and managed through the Windsurf Settings UI:

To create a global rule:
1. Open Windsurf Settings (Cmd/Ctrl + ,)
2. Navigate to the "Cascade" or "Rules" section
3. Click "Add Rule" under Global Rules
4. Set the trigger mode and write your rule content
5. Save — the rule now applies to all workspaces

Workspace Rules

Workspace rules live inside your project repository and apply only to that project. They're stored in the .windsurf/rules/ directory:

your-project/
├── .windsurf/
│   └── rules/
│       ├── coding-standards.md
│       ├── react-patterns.md
│       ├── api-conventions.md
│       └── testing-guidelines.md
├── src/
├── package.json
└── README.md

Because workspace rules are stored as files in your repository, they can be version-controlled and shared with your entire team.

Team sharing: Commit your .windsurf/rules/ directory to Git so every team member gets the same Cascade behavior. This is one of the biggest advantages of workspace rules over global rules.

The .windsurf/rules Directory

Starting with Wave 8, Windsurf uses a modern rule format where each rule is a separate .md file in the .windsurf/rules/ directory. Each file has YAML frontmatter that configures how and when the rule activates.

Directory Structure

.windsurf/
└── rules/
    ├── coding-standards.md      # Always-on rule
    ├── react-components.md      # Glob-triggered for .tsx files
    ├── api-design.md            # Model decision rule
    ├── database-migrations.md   # Manual rule
    └── testing.md               # Always-on rule

Rule File Format

Each rule file consists of YAML frontmatter followed by markdown content. The frontmatter configures the rule's behavior:

---
trigger: always_on
description: "Project-wide coding standards and conventions"
---

The body of the file (after the frontmatter) contains your rule instructions in markdown:

# TypeScript Coding Standards

## General
- Use TypeScript strict mode for all files
- Prefer `const` over `let`; never use `var`
- Use explicit return types on all exported functions
- Use template literals instead of string concatenation

## Naming Conventions
- PascalCase for components, interfaces, and type aliases
- camelCase for variables, functions, and methods
- UPPER_SNAKE_CASE for constants and environment variables
- Prefix interfaces with descriptive nouns (UserProfile, not IUser)

## Imports
- Use absolute imports with the `@/` path alias
- Group imports: external libs, then internal modules, then types
- No default exports except for pages and layouts

Frontmatter Fields

# Required fields
trigger: always_on          # Activation mode (see Activation Modes section)
description: "..."          # Human-readable description of what this rule does

# Optional fields (for glob trigger mode)
globs:                      # File patterns that activate this rule
  - "src/components/**/*.tsx"
  - "src/components/**/*.ts"

Available Trigger Values

# Always included in Cascade's context
trigger: always_on

# User activates manually with @rule-name
trigger: manual

# Cascade decides based on description
trigger: model_decision

# Activated when matching files are in context
trigger: glob

GUI support: You can also create and edit rules through Windsurf's built-in Rules UI, which provides a form-based interface for setting the trigger mode, description, and globs. The UI reads from and writes to the same .windsurf/rules/ directory.

Legacy .windsurfrules Format

Before Wave 8, Windsurf used a single .windsurfrules file at the project root. This format is still supported for backward compatibility but is less flexible than the modern directory-based approach.

File Location

your-project/
├── .windsurfrules          # Legacy single-file format
├── src/
├── package.json
└── README.md

File Format

The .windsurfrules file is a plain-text file with numbered rules. All rules are always active — there are no activation modes:

1. Use TypeScript strict mode for all files.
2. Follow the project's ESLint and Prettier configuration.
3. Use functional React components with hooks, never class components.
4. All components must have TypeScript prop interfaces.
5. Use CSS Modules for styling. Do not use inline styles.
6. Write unit tests for all utility functions using Vitest.
7. Use absolute imports with the @/ prefix.
8. Handle all async operations with try/catch and proper error messages.
9. Add JSDoc comments to all exported functions and components.
10. Never commit console.log statements to production code.

Migrating to the Modern Format

To migrate from .windsurfrules to .windsurf/rules/, split your rules into logical groups and create separate files:

# Before (single file)
.windsurfrules

# After (organized directory)
.windsurf/rules/
├── coding-standards.md     # Rules 1, 2, 7, 10
├── react-conventions.md    # Rules 3, 4, 5
├── testing.md              # Rule 6
└── documentation.md        # Rules 8, 9

Recommendation: Migrate to the modern .windsurf/rules/ format to take advantage of activation modes, better organization, and the GUI editor. The Windsurf Rules Generator can help you create rules in the modern format.

Rule Activation Modes

The modern rule format supports four activation modes that control when a rule is included in Cascade's context. Choose the right mode based on how and when you want the rule to apply.

Always On

Rules with always_on trigger are included in every Cascade conversation, regardless of context. Use this for fundamental standards that should always be enforced:

---
trigger: always_on
description: "Core TypeScript coding standards for all project files"
---

Example rule content:

# Core Coding Standards

- Use TypeScript strict mode
- Prefer const over let; never use var
- Use explicit return types on exported functions
- Follow ESLint and Prettier configurations
- No console.log in production code

Manual (@rule-name)

Manual rules are only activated when you explicitly reference them using @rule-name in your Cascade prompt. Use this for specialized rules you only need occasionally:

---
trigger: manual
description: "Database migration creation template and guidelines"
---

To activate, type @database-migrations in your Cascade prompt (the name is derived from the filename).

Model Decision

With model_decision, Cascade reads the rule's description and decides whether the rule is relevant to the current conversation. The description is critical — it tells Cascade when to apply the rule:

---
trigger: model_decision
description: "Guidelines for writing and organizing API route handlers. Apply when creating, modifying, or reviewing API endpoints."
---

Tip: Write clear, specific descriptions for model_decision rules. The description is what Cascade uses to decide if the rule applies — vague descriptions lead to rules being applied (or skipped) incorrectly.

Glob Patterns

Glob-triggered rules activate automatically when files matching the specified patterns are part of the Cascade context:

---
trigger: glob
description: "React component conventions and patterns"
globs:
  - "src/components/**/*.tsx"
  - "src/components/**/*.ts"
---

Common glob patterns:

# All TypeScript files
globs: ["**/*.ts", "**/*.tsx"]

# Only test files
globs: ["**/*.test.ts", "**/*.spec.ts", "**/__tests__/**"]

# API routes
globs: ["src/app/api/**/*.ts"]

# Stylesheets
globs: ["**/*.css", "**/*.scss", "**/*.module.css"]

# Configuration files
globs: ["*.config.ts", "*.config.js", ".env*"]

Choosing the Right Mode

always_on      → Core standards, universal conventions
                 (TypeScript config, naming rules, import order)

manual         → Specialized workflows, infrequent tasks
                 (migrations, deployments, release notes)

model_decision → Context-dependent guidelines
                 (API design when working on routes, testing when writing tests)

glob           → File-type-specific rules
                 (React patterns for .tsx, test conventions for .test.ts)

Creating Your First Rule

Let's walk through creating a workspace rule from scratch using the modern format.

Step 1: Create the Rules Directory

# Create the .windsurf/rules directory in your project root
mkdir -p .windsurf/rules

Step 2: Create a Rule File

Create a new .md file in the rules directory. The filename becomes the rule's identifier:

# Create a coding standards rule
touch .windsurf/rules/coding-standards.md

Step 3: Add Frontmatter

Start the file with YAML frontmatter specifying the trigger mode and description:

---
trigger: always_on
description: "Core coding standards and conventions for this project"
---

Step 4: Write the Rule Content

Add your instructions in markdown below the frontmatter:

# Project Coding Standards

## Language & Framework
- Use TypeScript strict mode for all files
- Use React 19 with functional components and hooks
- Use Next.js App Router conventions

## Code Style
- Use tabs for indentation (width: 2)
- Use single quotes for strings
- Add trailing commas in multi-line structures
- Maximum line length: 100 characters

## Naming
- PascalCase for components and types
- camelCase for variables and functions
- kebab-case for file and directory names
- UPPER_SNAKE_CASE for environment variables

## File Organization
- Group imports: external, internal, types (separated by blank lines)
- One component per file
- Co-locate tests with source files
- Use barrel exports (index.ts) for public module APIs

Step 5: Verify the Rule

Open a new Cascade conversation and ask it about your coding standards. Cascade should reflect the rules you just created. You can also check the Rules panel in Windsurf Settings to confirm the rule was detected.

Faster approach: Use the Windsurf Rules Generator to create rules visually. Choose a trigger mode, write your instructions, and export a ready-to-use rule file in seconds.

Writing Effective Rules

The quality of your rules directly impacts how well Cascade follows them. Here are guidelines for writing rules that produce consistent, reliable results.

Be Specific, Not Vague

# Bad — too vague
Write clean code and follow best practices.

# Good — specific and actionable
- Use explicit return types on all exported functions
- Destructure props in function signatures
- Handle all errors with try/catch and user-friendly messages
- Use named exports (not default exports) except for pages

Use Positive Instructions

Tell Cascade what to do, not just what to avoid:

# Bad — only negative
- Don't use var
- Don't use class components
- Don't use inline styles

# Good — positive with context
- Use const for immutable values; use let only when reassignment is needed
- Use functional components with hooks for all React components
- Use CSS Modules for component styling (import as 'styles')

Organize with Headings

Structure rules with clear markdown headings so Cascade can quickly find relevant instructions:

# React Component Standards

## Structure
- One component per file
- Export component as named export
- Props interface above the component definition

## Hooks
- Custom hooks go in src/hooks/
- Prefix custom hooks with "use"
- Keep hook logic separate from rendering logic

## State Management
- Use React Context for shared state
- Keep component state minimal
- Lift state up only when necessary

Include Examples

Concrete examples are more effective than abstract descriptions. Show Cascade exactly what you want:

// Good component structure example:
interface UserCardProps {
  name: string;
  email: string;
  avatarUrl?: string;
}

export function UserCard({ name, email, avatarUrl }: UserCardProps) {
  return (
    <div className={styles.card}>
      {avatarUrl && <img src={avatarUrl} alt={name} />}
      <h3>{name}</h3>
      <p>{email}</p>
    </div>
  );
}

Keep Rules Focused

Each rule file should cover one coherent topic. Don't mix unrelated concerns in a single rule:

# Bad — one file for everything
.windsurf/rules/
└── all-rules.md              # 5,000 chars covering 10 different topics

# Good — organized by concern
.windsurf/rules/
├── coding-standards.md       # General TypeScript conventions
├── react-patterns.md         # React component patterns
├── api-design.md             # API route conventions
└── testing.md                # Testing guidelines

Common Rule Patterns

Ready-to-use rule templates for common development scenarios. Adapt these to match your project's specific needs.

TypeScript Project Standards

---
trigger: always_on
description: "TypeScript coding standards and conventions"
---
# TypeScript Standards

## Types
- Use explicit types for function parameters and return values
- Prefer interfaces for object shapes; use type for unions/intersections
- Avoid `any` — use `unknown` and narrow with type guards
- Use generics for reusable utility functions

## Patterns
- Use optional chaining (?.) and nullish coalescing (??)
- Prefer early returns to reduce nesting
- Use const assertions for literal types
- Destructure objects and arrays in function parameters

React Component Conventions

---
trigger: glob
description: "React component patterns and conventions"
globs:
  - "src/components/**/*.tsx"
  - "src/app/**/*.tsx"
---
# React Conventions

## Components
- Use functional components with arrow functions
- Define props interface directly above the component
- Use named exports for all components
- Keep components under 150 lines; extract sub-components if larger

## Hooks
- Place all hooks at the top of the component body
- Use custom hooks to extract complex logic
- Name custom hooks with the "use" prefix

## Rendering
- Use early returns for conditional rendering
- Keep JSX nesting under 4 levels
- Extract complex expressions into named variables

API Route Conventions

---
trigger: glob
description: "API route handler patterns and error handling"
globs:
  - "src/app/api/**/*.ts"
  - "src/routes/**/*.ts"
---
# API Conventions

## Structure
- Validate all inputs with Zod schemas
- Use try/catch with structured error responses
- Return consistent response shapes: { data } or { error }
- Set appropriate HTTP status codes

## Security
- Validate authentication on all non-public routes
- Sanitize user input before database queries
- Use parameterized queries, never string concatenation
- Rate-limit sensitive endpoints

Testing Guidelines

---
trigger: model_decision
description: "Testing conventions and patterns. Apply when creating, modifying, or discussing tests."
---
# Testing Guidelines

## General
- Use Vitest for unit and integration tests
- Co-locate test files with source: ComponentName.test.tsx
- Follow the Arrange-Act-Assert pattern
- Test behavior, not implementation details

## Coverage
- Every utility function must have a test
- Test happy path, edge cases, and error cases
- Mock external services and API calls
- Aim for meaningful coverage, not 100% line coverage

Git Commit Conventions

---
trigger: model_decision
description: "Git commit message format and conventions. Apply when creating commits or writing changelogs."
---
# Git Commit Conventions

Use Conventional Commits format:

  type(scope): description

Types: feat, fix, docs, style, refactor, test, chore
Scope: component or module name (optional)
Description: imperative mood, lowercase, no period

Examples:
  feat(auth): add OAuth2 login flow
  fix(api): handle null response from user endpoint
  refactor(hooks): extract form validation into useFormValidation

More templates: The Windsurf Rules Generator includes a library of templates for common frameworks and workflows that you can customize and export.

Rule Limits and Prioritization

Windsurf enforces character limits on rules to keep Cascade's context window efficient. Understanding these limits helps you write rules that fit within the budget.

Character Limits

Per-rule limit:   6,000 characters per individual rule file
Total limit:     12,000 characters across all active rules combined

These limits apply to the rule content only (the markdown body), not the YAML frontmatter.

What Happens When Limits Are Exceeded

When the total character count of all active rules exceeds 12,000 characters, Cascade uses a prioritization strategy to decide which rules to include:

Prioritization order:
1. Global rules are loaded first (highest priority)
2. Workspace rules are loaded next, fitting as many as possible
3. Rules that don't fit within the budget are silently dropped

Within each scope, "always_on" rules take priority over other
activation modes.

Staying Within Limits

Strategies for keeping your rules within the character budget:

1. Be concise — use bullet points, not paragraphs
2. Split rules by topic with appropriate activation modes
3. Use "glob" and "model_decision" triggers to avoid loading
   rules that aren't relevant to the current task
4. Avoid duplicating instructions across multiple rule files
5. Reserve "always_on" for truly universal rules
6. Move detailed code examples to project documentation and
   reference them from rules instead

Checking Your Character Count

Use the command line to check how many characters your rules consume:

# Count characters in all workspace rules
wc -m .windsurf/rules/*.md

# Count total characters (content only, excluding frontmatter)
for f in .windsurf/rules/*.md; do
  sed '1,/^---$/d' "$f" | wc -m
done

Pro tip: If you're hitting the 12,000-character limit, switch less critical rules from always_on to model_decision or glob. These modes only load rules when relevant, keeping your always-on budget lean.

Best Practices

Guidelines for getting the most out of Windsurf Rules across your projects and team.

Organize Rules by Concern

# Good organization — clear separation of concerns
.windsurf/rules/
├── coding-standards.md       # Language conventions
├── react-patterns.md         # Framework patterns
├── api-design.md             # Backend conventions
├── testing.md                # Test guidelines
├── git-workflow.md           # Commit and branch conventions
└── documentation.md          # Code documentation standards

Use Descriptive Filenames

Rule filenames become identifiers for manual activation (@rule-name). Choose clear, descriptive names:

# Bad filenames
rules1.md
misc.md
stuff.md

# Good filenames
react-component-patterns.md
api-error-handling.md
database-migrations.md
accessibility-standards.md

Version Control Your Rules

# Commit .windsurf/rules/ to your repository
git add .windsurf/rules/
git commit -m "chore: add windsurf rules for project conventions"

# The directory should NOT be in .gitignore
# (unless you want rules to be per-developer only)

Write Clear Descriptions

The description field in frontmatter is especially important for model_decision rules. Cascade uses it to decide when to apply the rule:

# Bad — too vague
description: "Some coding rules"

# Good — specific about when to apply
description: "React component patterns including props, hooks, and state management. Apply when creating, editing, or reviewing React components."

# Good — clear scope
description: "Database migration guidelines for Prisma ORM. Apply when creating migrations, modifying the schema, or discussing database changes."

Review and Update Regularly

Maintenance checklist:
- Review rules quarterly or when upgrading frameworks
- Remove rules for deprecated patterns
- Update examples when project patterns evolve
- Consolidate overlapping rules
- Check character counts after adding new rules
- Test that Cascade follows updated rules correctly

Balance Global and Workspace Rules

Global rules should be:
- Personal preferences (style, communication)
- Universal standards (language, formatting basics)
- Small in character count (save budget for workspace rules)

Workspace rules should be:
- Project-specific conventions
- Framework and library patterns
- Team-agreed standards
- Architecture decisions

Explore Community Rules

Browse community-contributed rules at windsurf.run for inspiration and ready-to-use templates. You can also share your own rules to help others.

Troubleshooting

Common issues with Windsurf Rules and how to resolve them.

Rule Not Being Applied

Problem: Cascade ignores your rule

Solutions:
1. Verify the file is in .windsurf/rules/ (not another directory)
2. Check the YAML frontmatter is valid (proper --- delimiters)
3. For glob rules, confirm the glob patterns match the files
   you're working with
4. For model_decision rules, make the description more specific
5. Check that the total rule character count is under 12,000
6. Try an always_on trigger to confirm the rule file is detected
7. Restart Windsurf if rules were recently added

Rule Only Partially Followed

Problem: Cascade follows some instructions but skips others

Solutions:
1. Break long rules into shorter, focused bullet points
2. Put the most important instructions first
3. Use headings to organize sections clearly
4. Check if the rule exceeds 6,000 characters (it may be truncated)
5. Avoid contradicting instructions between multiple rules
6. Be more explicit — don't assume Cascade will infer intent

Rules Conflicting with Each Other

Problem: Two rules give contradictory instructions

Solutions:
1. Audit all active rules for overlapping topics
2. Use different activation modes to prevent both from loading
3. Merge related rules into a single, authoritative file
4. Use glob patterns to scope rules to specific file types
5. Add explicit priority notes: "This rule takes precedence
   over general coding standards for API files"

Frontmatter Not Recognized

Problem: Rule loads as always-on despite having a different trigger

Solutions:
1. Ensure frontmatter starts on line 1 (no blank lines before ---)
2. Check for invisible characters or BOM markers in the file
3. Verify the trigger value is valid: always_on, manual,
   model_decision, or glob
4. Ensure YAML syntax is correct (proper indentation, quoting)
5. Try recreating the file through the Windsurf GUI

Character Limit Issues

Problem: Some rules are being dropped or truncated

Solutions:
1. Check total character count across all active rules
2. Move less critical rules from always_on to model_decision
3. Make instructions more concise (bullets over paragraphs)
4. Remove redundant or duplicate content across rule files
5. Split large rules and use glob triggers to only load
   what's relevant to the current file context

Legacy .windsurfrules Not Working

Problem: .windsurfrules file seems to be ignored

Solutions:
1. Confirm the file is at the project root (not in a subdirectory)
2. Check for .windsurf/rules/ — modern format takes precedence
3. Ensure the file has no syntax errors or encoding issues
4. Try migrating to the modern .windsurf/rules/ format
5. Restart Windsurf after creating or modifying the file

Related Resources