[Windsurf Editor](https://windsurf.com/editor/) is an AI-powered code editor designed to boost productivity by automating repetitive coding tasks. When paired with Prisma, a robust and type-safe toolkit for database workflows, it becomes a powerful solution for managing and optimizing database schemas, queries, and data seeding.

This guide provides detailed instructions for effectively using Prisma with Windsurf to:

- Define project-specific best practices with `.windsurfrules`.  
- Use Windsurf's context-aware capabilities.  
- Generate schemas, queries, and seed data tailored to your database.

:::note

While this guide is focused on Windsurf, these patterns should work with any AI editor. [Let us know on X](https://pris.ly/x?utm_source=docs&utm_medium=inline_text) if you'd like us to create guides for your preferred tool!

:::

## Prisma MCP server

Prisma provides its own [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) server that lets you manage Prisma Postgres databases, model database schemas, and even chat through migrations. 

### Add Prisma MCP server via Windsurf Plugins

You can add the Prisma MCP server via [Windsurf MCP Plugin Store](https://docs.windsurf.com/windsurf/cascade/mcp#adding-a-new-mcp-plugin).

New MCP plugins can be added from the **Plugin Store**, which you can access by clicking on the **Plugins** icon in the top right menu in the **Cascade** panel, or from the **Windsurf Settings** > **Cascade** > **Plugins** section. Just search for **Prisma** in the **Plugin Store** and install the `Prisma` plugin.

:::note

You can also add the Prisma MCP server manually. Learn more about how you can add the MCP server manually to Windsurf [here](/postgres/integrations/mcp-server#windsurf).

:::

## Defining project-specific rules with `.windsurfrules`

The [`.windsurfrules` file](https://docs.windsurf.com/windsurf/memories#windsurfrules) in Windsurf allows you to enforce best practices and development standards tailored to your Prisma project. By defining clear and consistent rules, you can ensure that Windsurf generates clean, maintainable, and project-specific code with minimal manual adjustments.

To implement these rules, create a `.windsurfrules` file in the root of your project. Below is an example configuration:

<details>
<summary>Example <code>.windsurfrules</code> file</summary>

```text file=.windsurfrules showLineNumbers
You are a senior TypeScript/JavaScript programmer with expertise in Prisma, clean code principles, and modern backend development.
Generate code, corrections, and refactorings that comply with the following guidelines:
TypeScript General Guidelines
Basic Principles
- Use English for all code and documentation.
- Always declare explicit types for variables and functions.
  - Avoid using "any".
  - Create precise, descriptive types.
- Use JSDoc to document public classes and methods.
- Maintain a single export per file.
- Write self-documenting, intention-revealing code.
Nomenclature
- Use PascalCase for classes and interfaces.
- Use camelCase for variables, functions, methods.
- Use kebab-case for file and directory names.
- Use UPPERCASE for environment variables and constants.
- Start function names with a verb.
- Use verb-based names for boolean variables:
  - isLoading, hasError, canDelete
- Use complete words, avoiding unnecessary abbreviations.
  - Exceptions: standard abbreviations like API, URL
  - Accepted short forms: 
    - i, j for loop indices
    - err for errors
    - ctx for contexts
Functions
- Write concise, single-purpose functions.
  - Aim for less than 20 lines of code.
- Name functions descriptively with a verb.
- Minimize function complexity:
  - Use early returns.
  - Extract complex logic to utility functions.
- Leverage functional programming techniques:
  - Prefer map, filter, reduce.
  - Use arrow functions for simple operations.
  - Use named functions for complex logic.
- Use object parameters for multiple arguments.
- Maintain a single level of abstraction.
Data Handling
- Encapsulate data in composite types.
- Prefer immutability.
  - Use readonly for unchanging data.
  - Use as const for literal values.
- Validate data at the boundaries.
Error Handling
- Use specific, descriptive error types.
- Provide context in error messages.
- Use global error handling where appropriate.
- Log errors with sufficient context.
Prisma-Specific Guidelines
Schema Design
- Use meaningful, domain-driven model names.
- Leverage Prisma schema features:
  - Use @id for primary keys.
  - Use @unique for natural unique identifiers.
  - Utilize @relation for explicit relationship definitions.
- Keep schemas normalized and DRY.
- Use meaningful field names and types.
- Implement soft delete with deletedAt timestamp.
- Use Prisma's native type decorators.
Prisma Client Usage
- Always use type-safe Prisma client operations.
- Prefer transactions for complex, multi-step operations.
- Handle optional relations explicitly.
- Use Prisma's filtering and pagination capabilities.
Database Migrations
- Create migrations for schema changes.
- Use descriptive migration names.
- Review migrations before applying.
- Never modify existing migrations.
- Keep migrations idempotent.
Error Handling with Prisma
- Catch and handle Prisma-specific errors:
  - PrismaClientKnownRequestError
  - PrismaClientUnknownRequestError
  - PrismaClientValidationError
- Provide user-friendly error messages.
- Log detailed error information for debugging.
Testing Prisma Code
- Use in-memory database for unit tests.
- Mock Prisma client for isolated testing.
- Test different scenarios:
  - Successful operations
  - Error cases
  - Edge conditions
- Use factory methods for test data generation.
- Implement integration tests with actual database.
Performance Considerations
- Use select and include judiciously.
- Avoid N+1 query problems.
- Use findMany with take and skip for pagination.
- Leverage Prisma's distinct for unique results.
- Profile and optimize database queries.
Security Best Practices
- Never expose raw Prisma client in APIs.
- Use input validation before database operations.
- Implement row-level security.
- Sanitize and validate all user inputs.
- Use Prisma's built-in protections against SQL injection.
Coding Style
- Keep Prisma-related code in dedicated repositories/modules.
- Separate data access logic from business logic.
- Create repository patterns for complex queries.
- Use dependency injection for Prisma services.
Code Quality
- Follow SOLID principles.
- Prefer composition over inheritance.
- Write clean, readable, and maintainable code.
- Continuously refactor and improve code structure.
Development Workflow
- Use version control (Git).
- Implement comprehensive test coverage.
- Use continuous integration.
- Perform regular code reviews.
- Keep dependencies up to date.
```

</details>

This file ensures consistent and maintainable code generation, reducing manual intervention while improving project quality.

## Using Windsurf's context-aware capabilities

Windsurf's [context-awareness](https://docs.windsurf.com/context-awareness/overview) features let you leverage both your project files and external resources to enhance the AI's understanding of your project. By including your Prisma schema and relevant documentation in the context, you enable Windsurf to generate more accurate queries, tests, and seed data based on your database schema.

### Including Additional Prisma Resources

Windsurf comes with built-in knowledge of common libraries, but you can further enhance its awareness by explicitly referencing external Prisma resources. This is especially useful for staying up-to-date or providing authoritative context for code generation and best practices.

For example, you might reference:

- [Prisma Changelog](https://www.prisma.io/changelog)  
- [Prisma Blog](https://www.prisma.io/blog)  
- [Prisma Documentation](/)

#### Reference the resource in your requests:

When asking for code, explanations, or reviews, include the link to the relevant Prisma resource and specify that it should be used as a reference.

```terminal
Generate a migration script using best practices from prisma.io/docs.
```

#### Request persistent awareness:

Ask Windsurf to always consider a specific resource for all Prisma-related work in your project.  

```terminal
Always use the Prisma Changelog at prisma.io/changelog for Prisma updates in this project.
```

#### Ask for regular updates:  

If you want Windsurf to check for updates or new features, explicitly request it.  

```terminal
Before suggesting Prisma code, check the latest changes from prisma.io/changelog.
```

By referencing external resources directly in your requests or project guidelines, you ensure Windsurf leverages the most current and relevant Prisma information.

### Using schema as context

Out of the box, Windsurf automatically considers the current file, other open files, and indexed portions of your codebase as context. To ensure Cascade fully leverages your Prisma schema, keep your `schema.prisma` file open or pinned in the editor.

## Generating Prisma schema

Windsurf can generate Prisma schemas from high-level descriptions, enabling you to quickly establish a solid foundation for your database schema. By providing a clear and detailed prompt, Windsurf creates Prisma schemas tailored to your requirements. Whether you need a general foundational schema or a highly specific one for detailed use cases, Windsurf can deliver with precision. Here's an example prompt and its corresponding result:

:::note
LLMs may produce different results each time, even with the same prompt.
:::

<TabbedContent code>

<TabItem value="Prompt to generate Prisma schema">

```text copy
"Create a Prisma schema for a SaaS app using PostgreSQL as a provider with `User`, `Organization`, and `Subscription` models, ensuring all models include `createdAt` and `updatedAt` DateTime fields with defaults, a soft-delete `deletedAt` field, and proper relationships between entities."
```

</TabItem>

<TabItem value="Result">
```prisma file=schema.prisma showLineNumbers
generator client {
  provider = "prisma-client"
  output   = "./generated"
}

datasource db {
  provider = "postgresql"
}

model User {
  id             Int           @id @default(autoincrement())
  email          String        @unique
  name           String
  password       String
  createdAt      DateTime      @default(now())
  updatedAt      DateTime      @updatedAt
  deletedAt      DateTime?
  organization   Organization  @relation(fields: [organizationId], references: [id])
  organizationId Int
  role           UserRole      @default(MEMBER)
}

model Organization {
  id           Int           @id @default(autoincrement())
  name         String
  slug         String        @unique
  subscription Subscription?
  users        User[]
  createdAt    DateTime      @default(now())
  updatedAt    DateTime      @updatedAt
  deletedAt    DateTime?
}

model Subscription {
  id             Int              @id @default(autoincrement())
  organization   Organization     @relation(fields: [organizationId], references: [id])
  organizationId Int              @unique
  plan           SubscriptionPlan
  status         SubscriptionStatus @default(ACTIVE)
  startDate      DateTime
  endDate        DateTime?
  createdAt      DateTime         @default(now())
  updatedAt      DateTime         @updatedAt
  deletedAt      DateTime?
}

enum UserRole {
  ADMIN
  MEMBER
}

enum SubscriptionPlan {
  FREE
  BASIC
  PREMIUM
  ENTERPRISE
}

enum SubscriptionStatus {
  ACTIVE
  CANCELED
  EXPIRED
  PAST_DUE
}
```
</TabItem>
</TabbedContent>

## Generating Prisma queries

Windsurf can help you create queries tailored to your Prisma schema, whether for basic data retrieval or complex, optimized operations. To get the best results, focus on writing clear, specific prompts that define your requirements, such as the fields to include, conditions to apply, and relationships to traverse. This ensures Windsurf generates accurate, performant, and type-safe queries. Here's an example prompt and its resulting query:

<TabbedContent code>

<TabItem value="Prompt to generate a database query">

```text copy
"Generate a query to retrieve all User records associated with an Organization that has an `active` Subscription, while excluding any records where the `deletedAt` field is set."
```

</TabItem>

<TabItem value="Result">

```ts showLineNumbers
const activeUsers = await prisma.user.findMany({
  where: {
    deletedAt: null,
    organization: {
      deletedAt: null,
      subscription: {
        deletedAt: null,
        status: 'ACTIVE'
      }
    }
  },
  include: {
    organization: {
      include: {
        subscription: true
      }
    }
  },
  orderBy: {
    createdAt: 'desc'
  },
  skip: 0,
  take: 10
});
```
</TabItem>
</TabbedContent>

## Creating seed files with Windsurf

Writing seed scripts can be a tedious process, but Windsurf simplifies it by quickly generating structured and organized seed code. By providing clear instructions, you can guide Windsurf to create scripts that populate your database with realistic data, including handling relationships and complex structures defined in your schema. Here's an example prompt and its resulting seed script:

<TabbedContent code>
<TabItem value="Prompt to seed the database">

```text copy
"Generate code to populate the Prisma schema with realistic data for the User, Organization, and Subscription models, ensuring all necessary fields are included."
```

</TabItem>
<TabItem value="Result">

```ts file=seed.ts
import {
  PrismaClient,
  UserRole,
  SubscriptionPlan,
  SubscriptionStatus,
} from "../prisma/generated/client";

const prisma = new PrismaClient();

async function main() {
  // Clear existing data
  await prisma.user.deleteMany();
  await prisma.subscription.deleteMany();
  await prisma.organization.deleteMany();

  const organizations = [
    {
      name: "Tech Innovators",
      slug: "tech-innovators",
      subscription: {
        plan: SubscriptionPlan.ENTERPRISE,
        status: SubscriptionStatus.ACTIVE,
        startDate: new Date("2024-01-01"),
      },
      users: [
        {
          name: "Emma Thompson",
          email: "emma@techinnovators.com",
          role: UserRole.ADMIN,
          password: "password123",
        },
        {
          name: "Michael Chen",
          email: "michael@techinnovators.com",
          role: UserRole.MEMBER,
          password: "password123",
        },
      ],
    },
    {
      name: "Digital Solutions",
      slug: "digital-solutions",
      subscription: {
        plan: SubscriptionPlan.PREMIUM,
        status: SubscriptionStatus.ACTIVE,
        startDate: new Date("2024-01-15"),
      },
      users: [
        {
          name: "Sarah Wilson",
          email: "sarah@digitalsolutions.com",
          role: UserRole.ADMIN,
          password: "password123",
        },
        {
          name: "James Miller",
          email: "james@digitalsolutions.com",
          role: UserRole.MEMBER,
          password: "password123",
        },
      ],
    },
    {
      name: "Cloud Systems",
      slug: "cloud-systems",
      subscription: {
        plan: SubscriptionPlan.BASIC,
        status: SubscriptionStatus.ACTIVE,
        startDate: new Date("2024-02-01"),
      },
      users: [
        {
          name: "David Garcia",
          email: "david@cloudsystems.com",
          role: UserRole.ADMIN,
          password: "password123",
        },
        {
          name: "Lisa Wang",
          email: "lisa@cloudsystems.com",
          role: UserRole.MEMBER,
          password: "password123",
        },
      ],
    },
    {
      name: "Data Analytics Co",
      slug: "data-analytics",
      subscription: {
        plan: SubscriptionPlan.PREMIUM,
        status: SubscriptionStatus.ACTIVE,
        startDate: new Date("2024-01-10"),
      },
      users: [
        {
          name: "Alex Johnson",
          email: "alex@dataanalytics.com",
          role: UserRole.ADMIN,
          password: "password123",
        },
        {
          name: "Rachel Kim",
          email: "rachel@dataanalytics.com",
          role: UserRole.MEMBER,
          password: "password123",
        },
      ],
    },
    {
      name: "Smart Solutions",
      slug: "smart-solutions",
      subscription: {
        plan: SubscriptionPlan.FREE,
        status: SubscriptionStatus.ACTIVE,
        startDate: new Date("2024-02-15"),
      },
      users: [
        {
          name: "Daniel Brown",
          email: "daniel@smartsolutions.com",
          role: UserRole.ADMIN,
          password: "password123",
        },
        {
          name: "Maria Rodriguez",
          email: "maria@smartsolutions.com",
          role: UserRole.MEMBER,
          password: "password123",
        },
      ],
    },
  ];

  for (const org of organizations) {
    const createdOrg = await prisma.organization.create({
      data: {
        name: org.name,
        slug: org.slug,
        subscription: {
          create: {
            plan: org.subscription.plan,
            status: org.subscription.status,
            startDate: org.subscription.startDate,
          },
        },
      },
    });

    for (const user of org.users) {
      await prisma.user.create({
        data: {
          name: user.name,
          email: user.email,
          password: user.password,
          role: user.role,
          organizationId: createdOrg.id,
        },
      });
    }
  }

  console.log("Seed data created successfully");
}

main()
  .catch((e) => {
    console.error(e);
    process.exit(1);
  })
  .finally(async () => {
    await prisma.$disconnect();
  });
```
</TabItem>
</TabbedContent>

## Using the Prisma VS Code extension to manage your database

The [Prisma VS Code extension](https://marketplace.visualstudio.com/items?itemName=Prisma.prisma) is a powerful tool for building applications with [Prisma Postgres](/postgres). You can also use it in Windsurf by installing the extension. It provides a dedicated UI for managing Prisma Postgres instances, both local and remote, making it easy to view, create, and delete instances, push local databases to the cloud, and visualize your schema.

### Database management UI

With its built-in database management interface, [the Prisma VS Code extension](/postgres/integrations/vscode) lets you easily work with local and remote Prisma Postgres instances from inside your editor.

#### Workflows

The UI enables the following workflows:

- Authenticate with the [Prisma Console](https://console.prisma.io)
- View, create and delete Prisma Postgres instances (local & remote)
- "Push to cloud": Easily deploy a local Prisma Postgres instance
- View and edit data via an embedded Prisma Studio
- Visualize your database schema

#### Usage

To manage Prisma Postgres instances via the UI in the Prisma VS Code extension:

1. Ensure you have the latest version of the [Prisma VS Code extension](https://marketplace.visualstudio.com/items?itemName=Prisma.prisma) installed
1. Find the Prisma logo in the **Activity Bar**
1. Click the **Sign in to get started** button
1. Authenticate with the [Prisma Console](https://console.prisma.io) using the sign-in prompt, then select a target [workspace](/platform/about#workspace)

### Prisma Studio built-in

Beyond managing your database instances, the Prisma VS Code extension embeds Prisma Studio directly in your editor, making it easy to perform create, update, and delete operations on your database right inside Windsurf. Follow these [easy steps](/postgres/database/prisma-studio/studio-in-vs-code) to get started.

## Additional resources

Using Windsurf with Prisma can speed up development while ensuring clean and maintainable database code. To keep learning:

- [Windsurf Documentation](https://docs.windsurf.com/windsurf/getting-started)  
- [Prisma Documentation](/)  


---

# GitHub Copilot