Guide

How to Build a Complete Frontend Project with Windsurf

How to Build a Complete Frontend Project with Windsurf

This tutorial builds a real React and TypeScript task dashboard with Windsurf. It covers requirements, architecture, scaffolding, state, validation, accessibility, testing, production builds, and deployment, with reusable prompts and measured project results.

One of the most misleading experiences in AI-assisted development is this:

You ask for a website, see a page a few minutes later, and assume the project is finished.

A complete frontend project still needs decisions and verification around:

- Technology choices;

- Maintainable structure;

- State and data flow;

- Form validation;

- Responsive behavior;

- Keyboard and screen-reader access;

- Type safety and linting;

- Automated tests;

- Production builds;

- Secrets and environment variables;

- Deployment and future maintenance.

Windsurf is most valuable when it operates across the editor, repository, and terminal: reading the current codebase, making a plan, editing several files, running commands, interpreting failures, and applying a targeted fix.

Naming note: After Cognition acquired Windsurf, the 2026 documentation increasingly uses the name “Devin Desktop.” This article keeps the better-known Windsurf name and focuses on the Cascade workflow. Labels may differ slightly between versions.

1. What are we building?

The example project is TaskFlow, a responsive task-management dashboard.

It includes:

- Dashboard;

- Task list;

- Validated task form;

- Task status and priority;

- Lightweight analytics;

- Dark mode;

- Local persistence;

- Desktop, tablet, and mobile layouts;

- Unit tests;

- Playwright end-to-end test scripts;

- Production build and deployment configuration.

Technology stack

AreaChoice
FrameworkReact 19
LanguageTypeScript
Build toolVite 8
RoutingReact Router
StateZustand
FormsReact Hook Form
ValidationZod
IconsLucide React
Unit testsVitest + Testing Library
E2EPlaywright
StylingCSS custom properties and responsive CSS

This is not the only valid stack. It is a compact modern setup that demonstrates a maintainable application without hiding the implementation behind a large component framework.


2. Reproducible test results

The tutorial project was actually created, checked, tested, and built.

Test environment

ItemVersion or condition
Node.js22.16.0
npm10.9.2
React19.2.7
TypeScript6.0.3
Vite8.1.0
Vitest4.1.9
Operating systemLinux container

Results

CheckMeasured result
Source files21
Vite modules transformed138
Oxlint0 warnings, 0 errors
TypeScript0 errors
Unit tests4/4 passed
Vite production-build phaseabout 0.75 seconds
Full `npm run build` commandabout 3.4 seconds
Main JavaScript337.51 KB
Main JavaScript gzip105.79 KB
CSS7.48 KB
CSS gzip2.26 KB
`dist` directoryabout 353 KB
Production dependency audit0 known vulnerabilities

These measurements describe the example project, not “how fast Windsurf codes.” Hardware, dependency versions, and project scope will change the results.

Three Playwright flows were also written:

- Create and complete a task;

- Persist dark mode after reload;

- Use mobile navigation.

The managed Chromium environment used for this article blocked local-page access, so those scripts are not misrepresented as executed passes. On a normal development machine, install the Playwright browsers and run:

```bash

npx playwright install

npm run test:e2e

```


3. Install Windsurf and prepare the machine

Windsurf currently supports macOS, Windows, and Linux and can import settings from VS Code or Cursor.

Install:

- A compatible Node.js version;

- Git;

- Windsurf;

- Chrome or Chromium;

- A GitHub account.

Vite 8 requires Node.js 20.19+ or 22.12+.

Verify the environment:

```bash

node -v

npm -v

git --version

```

Is the free plan enough?

Public plans in June 2026 include:

PlanPublic price
Free$0/month
Pro$20/month
Max$200/month
TeamStarts around $80/month, with seat structure shown at checkout

The free plan is sufficient for this tutorial, although agent quotas and model choices are more limited. Pro is more practical for sustained work and larger repositories.

Pricing and quotas change frequently. Confirm them on the current checkout page.


4. Write requirements before code

Do not start with:

Build me a task management website.

That prompt forces the agent to guess the framework, pages, data model, quality standards, and visual direction.

Create:

```text

docs/requirements.md

```

Example:

```markdown

TaskFlow requirements

Goal

Build a responsive personal task dashboard.

Pages

- Dashboard

- Tasks

- Analytics

- Settings

- 404

Core features

- Create and delete tasks

- Change task status

- Priority and due date

- Persist data locally

- Dark mode

- Mobile navigation

Quality requirements

- TypeScript strict mode

- Accessible labels and keyboard focus

- Form validation

- Unit tests

- End-to-end test scripts

- Production build must pass

Non-goals

- No backend

- No authentication

- No external database

- No large UI component library

```

Requirements in the repository are more reliable than requirements buried in a chat history.


5. Constrain Windsurf with AGENTS.md

Create this file at the repository root:

```text

AGENTS.md

```

Example:

```markdown

Project instructions

- Package manager: npm.

- Framework: React + TypeScript + Vite.

- Use functional components.

- State management: Zustand.

- Forms: React Hook Form + Zod.

- Unit tests: Vitest + Testing Library.

- E2E tests: Playwright.

- All interactive controls require accessible names.

- Do not add a dependency when a small local implementation is enough.

- Run npm run check before marking a task complete.

- Never place secrets in frontend source code.

```

Current Windsurf documentation recommends:

- `AGENTS.md` for simple directory-scoped instructions;

- Rules for cross-cutting or conditionally activated behavior;

- Skills for repeatable multi-step procedures;

- Explicit rules rather than relying on auto-generated memories for critical conventions.

Without stable instructions, an agent may:

- Switch between npm and pnpm;

- Mix several styling systems;

- Add overlapping dependencies;

- Forget tests;

- Refactor unrelated files while solving a small issue.


6. Ask Cascade for a plan before edits

Start in chat or a non-editing mode:

```text

Read docs/requirements.md and AGENTS.md.

Do not write code yet.

Create an implementation plan that includes:

1. Technology choices and reasons

2. Project directory structure

3. Data model

4. Route design

5. Component boundaries

6. State-management plan

7. Validation strategy

8. Unit and E2E test plan

9. Accessibility checklist

10. Build and deployment checklist

Identify ambiguous requirements and choose the simplest maintainable solution.

```

A useful plan should explain:

- The Task data model;

- Which state is global;

- Page and component boundaries;

- Persistence;

- Critical user flows;

- What is explicitly out of scope.

If the plan is only “create pages, add styling, finish the app,” ask for a more concrete plan before allowing edits.


7. Scaffold the Vite project

After approving the plan:

```text

Initialize the project with the latest Vite React TypeScript template.

Use npm.

Do not install application dependencies yet.

After scaffolding:

1. Run npm install

2. Start the development server

3. Report any errors

4. Stop and wait for review

```

Equivalent commands:

```bash

npm create vite@latest taskflow -- --template react-ts

cd taskflow

npm install

npm run dev

```

Vite officially provides a React TypeScript template. There is no reason for the agent to hand-write a custom Webpack setup for this project.

Terminal safety

Windsurf’s terminal provides four auto-execution levels:

- Disabled;

- Allowlist Only;

- Auto;

- Turbo.

Beginners should use Allowlist Only or Auto.

Keep destructive commands behind explicit approval:

```text

rm

sudo

chmod

chown

curl | sh

git push --force

git reset --hard

npm publish

```

An agent’s ability to execute a command is not a reason to approve it automatically.


8. Install only approved dependencies

Prompt:

```text

Install only the dependencies required by the approved architecture:

Runtime:

- react-router-dom

- zustand

- zod

- react-hook-form

- @hookform/resolvers

- lucide-react

Development:

- vitest

- jsdom

- @testing-library/react

- @testing-library/jest-dom

- @testing-library/user-event

- @playwright/test

Before installing:

1. Explain why each package is needed

2. Check whether an existing dependency already solves the problem

3. Use exact package names

4. Do not add a UI framework

```

Commands:

```bash

npm install react-router-dom zustand zod react-hook-form \

@hookform/resolvers lucide-react

npm install -D vitest jsdom \

@testing-library/react \

@testing-library/jest-dom \

@testing-library/user-event \

@playwright/test

```

Uncontrolled agents often add a full chart library for three bars, a date library for one date field, or multiple state solutions.

Every dependency adds bundle weight, security surface, upgrade work, and more code for the agent to understand.


9. Build in stages

Avoid:

Implement the whole plan.

Smaller stages are easier to review and revert.

Stage 1: data model and state

```text

Implement only the data layer.

Requirements:

- Create Task, TaskStatus, and TaskPriority TypeScript types

- Create a Zustand store

- Include addTask, updateStatus, removeTask, and resetTasks

- Persist tasks to localStorage

- Add three seed tasks

- Do not create UI components yet

After editing:

- Run TypeScript type checking

- Explain the public store API

```

Stage 2: shell and routing

```text

Implement the application shell and routing.

Routes:

- /

- /tasks

- /analytics

- /settings

- fallback 404

Requirements:

- Responsive sidebar on desktop

- Bottom navigation on mobile

- Active-route state

- Semantic navigation

- Dark-mode toggle persisted to localStorage

- Do not implement page-specific business logic yet

```

Stage 3: validated form

```text

Implement the task form using React Hook Form and Zod.

Validation:

- title: 3 to 80 characters

- description: maximum 240 characters

- priority: low, medium, or high

- due date: required

Accessibility:

- Every field has a visible label

- Validation errors are readable

- Submit is keyboard accessible

Add focused unit tests for invalid and valid submissions.

```

Stage 4: task list and analytics

```text

Implement:

1. Task list

2. Status selector

3. Delete action

4. Priority labels

5. Dashboard summary cards

6. A dependency-free CSS bar chart for task status

Do not add a chart library.

Preserve the existing store API.

Add tests for status updates and deletion.

```

Stage 5: responsive visual polish

```text

Polish the interface without changing business logic.

Requirements:

- CSS custom properties for light and dark themes

- Desktop, tablet, and 390px mobile layouts

- Visible focus states

- No horizontal overflow

- Touch targets approximately 44px where possible

- Respect semantic heading order

- Avoid low-contrast text

```


10. Review generated changes

Do not judge the result only by whether the page looks polished.

Check the scope

If the task was a form, why did routing, themes, and the store also change?

Look for duplication

Watch for:

- Multiple Task interfaces;

- More than one state system;

- Repeated CSS tokens;

- Duplicate components;

- Unnecessary helpers.

Look for hidden risk

Pay attention to:

- `any`;

- Non-null assertions;

- Empty `catch` blocks;

- Unhandled promises;

- Direct state mutation;

- Incorrect effect dependencies;

- Secrets in client code.

Check real accessibility

Icon-only buttons need accessible names.

Errors cannot be communicated only through red color.

All key interactions must work from the keyboard.

Check maintainability

A 300-line component is not automatically wrong, but the agent should be able to justify the boundary.


11. Create a verification loop

Add scripts:

```json

{

"scripts": {

"dev": "vite",

"lint": "oxlint",

"typecheck": "tsc -b --pretty false",

"test": "vitest run",

"test:e2e": "playwright test",

"build": "tsc -b && vite build",

"check": "npm run lint && npm run typecheck && npm run test && npm run build"

}

}

```

Prompt Cascade:

```text

Run npm run check.

If a command fails:

1. Read the complete error

2. Identify the root cause

3. Make the smallest safe fix

4. Re-run only the failed check first

5. Run npm run check again after it passes

Do not silence TypeScript or lint errors.

Do not remove failing tests unless the requirement is wrong.

```

Measured result:

```text

Lint: 0 warnings, 0 errors

Typecheck: 0 errors

Unit tests: 4 passed

Build: passed

Modules: 138 transformed

JS gzip: 105.79 KB

CSS gzip: 2.26 KB

```

This is the line between AI-generated files and a verified deliverable.


12. Generate useful tests

Do not ask:

Test every component.

That usually creates low-value “renders without crashing” tests.

Use behavioral cases:

```text

Add unit tests for business behavior only.

Test cases:

1. Empty title shows a validation error

2. A valid form submission adds one task

3. Changing the status updates the store

4. Deleting a task removes it

Use Testing Library queries based on roles and accessible names.

Do not test implementation details.

```

For Playwright:

```text

Add Playwright tests for three critical flows:

1. Create a task and mark it done

2. Switch to dark mode and verify persistence after reload

3. Use mobile navigation at 390x844

Use stable role- and label-based selectors.

Do not use arbitrary timeouts.

```

Playwright provides a runner, assertions, isolation, parallelization, and mobile emulation for modern browser testing.


13. Measure performance and bundle size

Prompt:

```text

Run a production build and analyze the output.

Report:

- Build time

- Number of transformed modules

- Raw and gzip sizes for JS and CSS

- Any chunk above 200 KB gzip

- Dependencies contributing most to the bundle

- Three optimization opportunities, ranked by impact

Do not optimize before measuring.

```

Measured main JavaScript:

- Raw: 337.51 KB;

- Gzip: 105.79 KB.

That is reasonable for routing, state, form validation, and icons, but there are still options:

- Lazy-load routes;

- Import only required icons;

- Avoid large chart and date packages;

- Split non-critical pages.

Do not hard-code a Lighthouse claim

Lighthouse varies with hardware, browser, network, and run mode.

Run it locally:

```bash

npm run build

npm run preview

npx lighthouse http://localhost:4173 \

--only-categories=performance,accessibility,best-practices,seo \

--view

```

Record the environment and use the median of several runs rather than publishing the single best score.


14. Environment variables and APIs

Create:

```text

.env.example

```

Example:

```bash

VITE_API_BASE_URL=https://api.example.com

```

Read it with:

```ts

const apiBaseUrl = import.meta.env.VITE_API_BASE_URL

```

Every variable prefixed with `VITE_` is exposed to the browser bundle.

Never put these in frontend code:

- OpenAI API keys;

- Database passwords;

- Private keys;

- Admin tokens;

- Payment-provider secrets;

- Service-account credentials.

Use:

```text

Browser -> your backend or serverless function -> third-party API

```

Add a rule:

```text

Never place secrets in frontend code.

If a feature requires a secret, create a server-side boundary or explain why it cannot be implemented safely in a frontend-only project.

```


15. Use Git as the real history

Commit after each stage:

```bash

git add .

git commit -m "feat: add task state and persistence"

```

A useful sequence:

```text

chore: scaffold Vite React TypeScript project

feat: add application shell and routes

feat: add task store and persistence

feat: add validated task form

feat: add task list and analytics

test: add unit and end-to-end coverage

style: add responsive themes

chore: add production checks

```

Cascade can suggest commit messages, but review the diff yourself.

Keep these commands behind manual approval:

```bash

git push --force

git reset --hard

git clean -fd

```

Named checkpoints are useful for reverting agent changes, but Git remains the official history.


16. Deploy

Windsurf App Deploys can deploy React, Vue, Svelte, and Next.js projects to Netlify and return a public preview URL.

Prompt:

```text

Before deployment:

1. Run npm run check

2. Run the production build

3. Verify that no .env files or secrets are included

4. Summarize the build output

If all checks pass, deploy this project to Netlify as a preview.

```

Official caveats:

- App Deploys is still beta;

- Netlify is the currently documented provider;

- Code is uploaded through the Windsurf/Cognition deployment workflow;

- Sensitive production deployments should be claimed in your own account;

- Unclaimed deployments may be removed.

For production:

1. Push to your own GitHub repository;

2. Connect Netlify, Vercel, or Cloudflare Pages;

3. Configure the build and environment variables;

4. Enable branch previews;

5. Keep logs and rollback options.


17. Five high-value prompt patterns

Plan before editing

```text

Do not edit files yet. Inspect the codebase and propose a plan with affected files, risks, and validation steps.

```

Limit scope

```text

Only modify the task-form feature. Do not refactor routing, theme, or the store unless required. Explain every out-of-scope change before making it.

```

Make the agent verify

```text

After implementation, run lint, typecheck, focused tests, and production build. Fix root causes instead of suppressing errors.

```

Ask for the smallest safe change

```text

Make the smallest safe change that satisfies the requirement. Preserve public APIs and existing behavior.

```

Request review instead of more code

```text

Review the current implementation as a senior frontend engineer. List correctness, accessibility, performance, security, and maintainability issues. Do not edit files until I approve the findings.

```


18. Common failure modes

Generating the whole project at once

Symptoms:

- Many files with weak structure;

- Features that appear complete but cannot be tested;

- Too many dependencies;

- Small changes breaking unrelated pages.

Fix: build in stages and verify each stage.

Asking to “make it prettier”

Replace vague design requests with measurable constraints:

```text

Use a neutral productivity-dashboard style.

Use one primary accent color.

Maintain at least 4.5:1 text contrast.

Keep content width below 1120px.

Use 16–24px spacing.

Create a mobile bottom navigation below 640px.

```

Letting the agent thrash after an error

If several configuration files are being changed without progress:

```text

Stop editing. Explain why the previous fix failed, which assumption was wrong, and what the minimal next experiment should be.

```

Letting the agent “fix” the tests

The agent may weaken assertions or skip cases.

Use:

```text

Do not weaken, skip, or delete tests unless the documented requirement changed.

```

Treating a preview as production

A preview URL does not automatically include:

- Custom domains;

- Monitoring;

- Backups;

- Security headers;

- Privacy compliance;

- Reliable service guarantees;

- A formal rollback process.


19. Is Windsurf suitable for non-programmers?

It lowers the entry barrier, but it does not remove engineering judgment.

A beginner should still understand:

- Components;

- State versus props;

- Browser versus server;

- Why secrets cannot live in frontend code;

- What npm dependencies do;

- The different jobs of types, linting, and tests;

- Basic Git and deployment.

AI is highly effective for:

- Boilerplate;

- Repetitive edits;

- Code explanation;

- Error diagnosis;

- Test drafts;

- Documentation;

- Small refactors.

Humans remain responsible for:

- Product requirements;

- Architecture;

- Security;

- Acceptance criteria;

- Critical code review;

- Release decisions.


20. Delivery checklist

Functionality

- [ ] Every route works

- [ ] Validation works

- [ ] Status changes and deletion work

- [ ] Data survives reload

- [ ] A 404 page exists

- [ ] Theme preference persists

Quality

- [ ] Lint passes

- [ ] TypeScript passes

- [ ] Unit tests pass

- [ ] Critical E2E flows pass

- [ ] Production build passes

- [ ] No high-severity production dependency issues

User experience

- [ ] No mobile horizontal overflow

- [ ] Main flows work by keyboard

- [ ] Icon buttons have accessible names

- [ ] Errors are understandable

- [ ] Loading and empty states exist

- [ ] Contrast is acceptable

Security and deployment

- [ ] `.env` is ignored

- [ ] No secrets are committed

- [ ] Secret APIs use a backend boundary

- [ ] Production deployment belongs to your account

- [ ] Environment variables are configured in the host

- [ ] Logs and rollback are available


21. Final assessment

Windsurf can turn frontend development from constant switching among an editor, terminal, browser, and documentation into a continuous agent-assisted workflow.

The effective approach is not:

Build the entire website for me.

It is:

1. Store requirements in the repository;

2. Define stable rules in `AGENTS.md`;

3. Ask for a plan before edits;

4. Implement data, routing, components, styling, and tests in stages;

5. Review every diff;

6. Verify through linting, types, tests, and production builds;

7. Deploy only after the checks pass.

The reproducible project finished with:

- Zero lint issues;

- Zero TypeScript errors;

- Four passing unit tests;

- A successful production build;

- 105.79 KB of gzipped main JavaScript;

- Zero known production dependency vulnerabilities.

That does not prove that AI replaces frontend engineers.

It demonstrates something more useful:

When requirements, rules, and verification commands are explicit, Windsurf can evolve from a code generator into an agent that participates in a real delivery process.

Sources

1. [Windsurf / Devin Desktop Getting Started](https://docs.devin.ai/desktop/getting-started)

2. [Cascade Overview](https://docs.devin.ai/desktop/cascade/cascade)

3. [Memories, Rules and AGENTS.md](https://docs.devin.ai/desktop/cascade/memories)

4. [Windsurf Terminal and Auto-Execution Levels](https://docs.devin.ai/desktop/terminal)

5. [Windsurf App Deploys](https://docs.devin.ai/desktop/cascade/app-deploys)

6. [Windsurf Plans and Usage](https://docs.devin.ai/desktop/accounts/usage)

7. [Windsurf Pricing Update, March 2026](https://devin.ai/blog/windsurf-pricing-plans)

8. [Vite Getting Started](https://vite.dev/guide/)

9. [Playwright Installation and Overview](https://playwright.dev/docs/intro)

Tip: Review AI-generated content before use. Free tiers may have usage limits.