Intermediate15 min1 prerequisite

Use Windsurf Flows to automate repetitive coding tasks, create custom workflows, and boost productivity.

Flows and Automation

Flows are Windsurf's automation system for repetitive coding tasks. Define a workflow once, then execute it with a single command.

What are Flows?

Flows automate multi-step coding tasks:

Terminal
Without Flows:
1. Create component file
2. Add boilerplate code
3. Create test file
4. Add test boilerplate
5. Create styles file
6. Update exports

With Flow "Create React Component":
1. Run flow
2. Enter component name
3. All files created instantly

Built-in Flows

Accessing Flows

Open the Flows panel:

Terminal
Cmd/Ctrl+Shift+P  "Flows: Open Panel"

Or click the Flows icon in the activity bar.

Available Built-in Flows

FlowDescription
Create ComponentReact/Vue/Angular component with tests
Create API RouteNext.js/Express API endpoint
Create HookCustom React hook
Create ServiceService class with methods
Create TestTest file for selected code
Scaffold FeatureFull feature with all parts

Running a Flow

Terminal
1. Open Flows panel
2. Select flow (e.g., "Create React Component")
3. Enter parameters:
   - Component name: UserProfile
   - Include tests: Yes
   - Include styles: CSS Modules
4. Click "Run"
5. Files are created

Flow Examples

Create React Component

Flow Definition:

Terminal
name: Create React Component
inputs:
  - name: componentName
    type: string
    prompt: "Component name"
  - name: includeTests
    type: boolean
    default: true
  - name: styling
    type: select
    options: ["none", "css", "css-modules", "styled-components"]

outputs:
  - path: components/{{componentName}}/{{componentName}}.tsx
  - path: components/{{componentName}}/{{componentName}}.test.tsx
    condition: includeTests
  - path: components/{{componentName}}/{{componentName}}.module.css
    condition: styling == "css-modules"

Result:

Terminal
components/
└── UserProfile/
    ├── UserProfile.tsx
    ├── UserProfile.test.tsx
    └── UserProfile.module.css

Create API Route

Input:

Terminal
Route name: users
Methods: GET, POST
Validation: Yes (Zod)

Output:

Terminal
// app/api/users/route.ts
import { NextResponse } from 'next/server'
import { z } from 'zod'

const userSchema = z.object({
  name: z.string().min(1),
  email: z.string().email(),
})

export async function GET() {
  const users = await prisma.user.findMany()
  return NextResponse.json(users)
}

export async function POST(request: Request) {
  const body = await request.json()
  const validated = userSchema.parse(body)
  const user = await prisma.user.create({ data: validated })
  return NextResponse.json(user, { status: 201 })
}

Scaffold Feature

Input:

Terminal
Feature name: subscription
Include: model, service, api, ui, tests

Output:

Terminal
src/
├── prisma/
   └── migrations/add_subscription/
├── services/
   └── subscription.service.ts
├── app/api/subscriptions/
   ├── route.ts
   └── [id]/route.ts
├── components/
   └── Subscription/
       ├── SubscriptionCard.tsx
       └── SubscriptionForm.tsx
├── types/
   └── subscription.ts
└── tests/
    └── subscription/
        ├── subscription.service.test.ts
        └── subscription.api.test.ts

Creating Custom Flows

Flow File Location

Create flows in .windsurf/flows/:

Terminal
.windsurf/
└── flows/
    ├── create-feature.yaml
    ├── add-endpoint.yaml
    └── generate-types.yaml

Flow Structure

Terminal
# .windsurf/flows/create-feature.yaml
name: Create Feature
description: Scaffold a complete feature with all components
version: 1.0.0

inputs:
  - name: featureName
    type: string
    prompt: "Feature name (e.g., 'subscription')"
    validate: "^[a-z][a-z0-9-]*$"

  - name: includeAPI
    type: boolean
    prompt: "Include API routes?"
    default: true

  - name: includeUI
    type: boolean
    prompt: "Include UI components?"
    default: true

steps:
  - action: create_file
    path: "services/{{featureName}}.service.ts"
    template: service.template.ts

  - action: create_file
    path: "types/{{featureName}}.ts"
    template: types.template.ts

  - action: create_file
    path: "app/api/{{featureName}}/route.ts"
    template: api-route.template.ts
    condition: "{{includeAPI}}"

  - action: create_directory
    path: "components/{{featureName | pascalCase}}"
    condition: "{{includeUI}}"

  - action: create_file
    path: "components/{{featureName | pascalCase}}/{{featureName | pascalCase}}.tsx"
    template: component.template.tsx
    condition: "{{includeUI}}"

  - action: run_command
    command: "npm run lint:fix"

Templates

Create templates in .windsurf/templates/:

Terminal
// .windsurf/templates/service.template.ts
import { prisma } from '@/lib/prisma'
import type { {{featureName | pascalCase}} } from '@/types/{{featureName}}'

export class {{featureName | pascalCase}}Service {
  async findAll(): Promise<{{featureName | pascalCase}}[]> {
    return prisma.{{featureName}}.findMany()
  }

  async findById(id: string): Promise<{{featureName | pascalCase}} | null> {
    return prisma.{{featureName}}.findUnique({ where: { id } })
  }

  async create(data: Omit<{{featureName | pascalCase}}, 'id'>): Promise<{{featureName | pascalCase}}> {
    return prisma.{{featureName}}.create({ data })
  }

  async update(id: string, data: Partial<{{featureName | pascalCase}}>): Promise<{{featureName | pascalCase}}> {
    return prisma.{{featureName}}.update({ where: { id }, data })
  }

  async delete(id: string): Promise<void> {
    await prisma.{{featureName}}.delete({ where: { id } })
  }
}

Template Helpers

Available template helpers:

HelperExample InputOutput
pascalCaseuser-profileUserProfile
camelCaseuser-profileuserProfile
snakeCaseuserProfileuser_profile
kebabCaseUserProfileuser-profile
pluraluserusers
singularusersuser

Flow Actions

create_file

Terminal
- action: create_file
  path: "path/to/file.ts"
  template: template-file.ts
  overwrite: false  # Don't overwrite if exists

create_directory

Terminal
- action: create_directory
  path: "path/to/directory"

run_command

Terminal
- action: run_command
  command: "npm install some-package"
  cwd: "{{workspaceRoot}}"

modify_file

Terminal
- action: modify_file
  path: "package.json"
  operation: json_merge
  data:
    scripts:
      "{{featureName}}:dev": "..."

cascade_prompt

Invoke Cascade AI:

Terminal
- action: cascade_prompt
  prompt: |
    Create a README for the {{featureName}} feature.
    Include usage examples and API documentation.
  output: "docs/{{featureName}}.md"

Conditional Logic

Simple Conditions

Terminal
- action: create_file
  path: "tests/{{name}}.test.ts"
  condition: "{{includeTests}}"

Complex Conditions

Terminal
- action: create_file
  path: "{{name}}.styles.ts"
  condition: "{{styling == 'styled-components'}}"

- action: create_file
  path: "{{name}}.module.css"
  condition: "{{styling == 'css-modules'}}"

Sharing Flows

Team Flows

Share flows via the repository:

Terminal
.windsurf/
└── flows/
    └── team-flows/
        ├── create-feature.yaml
        ├── add-migration.yaml
        └── README.md

Commit to version control for team access.

Publishing Flows

Export flows for others:

Terminal
Flows Panel  Your Flow  Export

Share the exported .flow file.

Importing Flows

Terminal
Flows Panel  Import  Select .flow file

Best Practices

1. Start Simple

Begin with basic flows, then add complexity:

Terminal
# v1: Simple
steps:
  - action: create_file
    path: "components/{{name}}.tsx"
    template: component.tsx

# v2: Add options
inputs:
  - name: includeTests
    type: boolean
    default: true

# v3: Add conditional steps
# v4: Add post-processing

2. Use Descriptive Names

Terminal
# 
name: cf

# 
name: Create React Feature Component
description: Creates a feature component with tests, styles, and stories

3. Validate Inputs

Terminal
inputs:
  - name: componentName
    validate: "^[A-Z][a-zA-Z0-9]*$"
    errorMessage: "Component name must be PascalCase"

4. Document Flows

Terminal
name: Create API Endpoint
description: |
  Creates a complete API endpoint with:
  - Route handler
  - Input validation
  - Error handling
  - TypeScript types

  Usage: Run this flow and provide the endpoint name.

Troubleshooting

Flow Not Appearing

Terminal
1. Check file location (.windsurf/flows/)
2. Verify YAML syntax
3. Reload Windsurf

Template Errors

Terminal
1. Check template path
2. Verify variable names match inputs
3. Test helpers (pascalCase, etc.)

Conditional Not Working

Terminal
1. Check boolean vs string comparison
2. Use correct syntax: {{variable == 'value'}}
3. Ensure input names match

Summary

  • Flows automate repetitive coding tasks
  • Built-in flows for common operations
  • Custom flows in .windsurf/flows/
  • Templates with variable substitution
  • Actions: create_file, run_command, modify_file
  • Conditions for flexible workflows
  • Share flows with team via repository

What's Next

You've completed the Windsurf module. You can now:

  • Use Cascade for AI development
  • Create Flows for automation
  • Combine both for maximum productivity

Consider exploring:

  • Cursor for another agentic editor experience
  • Claude Code for terminal-based AI development
  • GitHub Copilot for multi-editor support
Mark this lesson as complete to track your progress