# How to Prevent Breaking API Contracts with Cursor

- Tool: Cursor
- Difficulty: Beginner
- Time required: 10-15 min
- Compatibility: Cursor Free+, GraphQL projects
- Last updated: March 2026

## TL;DR

Cursor can generate GraphQL schema changes that break existing clients by removing fields, changing types, or renaming operations without deprecation. By adding .cursor/rules/ with backward compatibility requirements, referencing your existing schema with @file, and prompting with explicit versioning constraints, you can ensure Cursor generates additive-only schema changes that maintain API contracts with existing consumers.

## Preventing breaking API contracts with Cursor

GraphQL APIs promise stability to clients through their schema contract. When Cursor modifies a schema, it can remove fields, change return types, or rename operations without understanding that existing clients depend on the current shape. This tutorial configures Cursor to treat your GraphQL schema as a contract and generate only additive, non-breaking changes.

## Before you start

- Cursor installed with a GraphQL project
- An existing GraphQL schema file
- Basic understanding of GraphQL schema design
- Familiarity with Cursor Chat (Cmd+L) and project rules

## Step-by-step guide

### 1. Create a GraphQL backward compatibility rule

Add a project rule that enforces additive-only schema changes. This rule prevents Cursor from removing fields, changing types, or making required arguments optional. It also mandates @deprecated directives instead of removals.

```
---
description: Enforce backward-compatible GraphQL schema changes
globs: "*.graphql,*.gql,*.resolver.ts,*.schema.ts"
alwaysApply: true
---

# GraphQL API Contract Rules
- NEVER remove existing fields from a type
- NEVER change the return type of an existing field
- NEVER rename existing queries, mutations, or subscriptions
- NEVER make a previously optional argument required
- ALWAYS add new fields instead of modifying existing ones
- ALWAYS use @deprecated(reason: "...") before removing fields
- New required arguments must have default values
- New enum values are safe to add
- Breaking changes require a new API version (v2)

## Safe Changes (ALLOWED):
- Adding new fields to existing types
- Adding new queries, mutations, subscriptions
- Adding new types, enums, unions
- Adding optional arguments to existing fields
- Deprecating fields with @deprecated

## Breaking Changes (NEVER without versioning):
- Removing any field, type, or operation
- Changing a field's return type
- Making optional arguments required
- Removing enum values
```

**Expected result:** Cursor generates additive-only GraphQL schema changes and uses @deprecated for field removals.

### 2. Reference the existing schema when making changes

Always reference your current schema file with @file when asking Cursor to modify the API. This gives Cursor the full picture of existing fields, types, and operations that must not be broken.

```
@graphql-compat.mdc @src/schema/schema.graphql

Add a new 'analytics' section to the User type:
1. Add lastLoginAt: DateTime field
2. Add loginCount: Int field
3. Add a new UserAnalytics type with detailed metrics
4. Add a userAnalytics(userId: ID!): UserAnalytics query

Do NOT modify or remove any existing fields on the User type.
All changes must be additive only.
```

> Pro tip: Start every GraphQL prompt with 'Do NOT modify or remove any existing fields.' This is the single most effective instruction for preventing breaking changes.

**Expected result:** Cursor adds new fields and types without touching any existing schema definitions.

### 3. Generate deprecation notices for fields being phased out

When you need to eventually remove a field, ask Cursor to add a @deprecated directive with a reason and migration path. This gives clients time to update while maintaining backward compatibility during the transition.

```
@graphql-compat.mdc @src/schema/schema.graphql

Deprecate these fields (do NOT remove them):
1. User.fullName -> deprecated in favor of User.displayName
2. Query.getUser -> deprecated in favor of Query.user
3. User.avatarUrl -> deprecated in favor of User.avatar.url

Add @deprecated directives with clear reasons and migration paths.
Add the new replacement fields/queries alongside the deprecated ones.
Both old and new must work simultaneously.
```

**Expected result:** Cursor adds @deprecated directives to old fields and creates new replacement fields, keeping both functional.

### 4. Validate schema changes with a compatibility check

Use Cursor Chat to compare your proposed schema changes against the existing schema and identify any breaking changes before they reach production.

```
@graphql-compat.mdc @src/schema/schema.graphql @src/schema/schema-proposed.graphql

Compare the existing schema with the proposed changes.
Identify any breaking changes:
1. Fields removed from any type
2. Return types changed on existing fields
3. Required arguments added without defaults
4. Enum values removed
5. Types renamed or removed

For each breaking change found, explain the impact on existing
clients and suggest a backward-compatible alternative.
```

**Expected result:** Cursor identifies breaking changes in the proposed schema and suggests backward-compatible alternatives.

### 5. Generate resolver updates that maintain both old and new fields

When adding replacement fields alongside deprecated ones, both need working resolvers. Ask Cursor to generate resolvers that serve both the old and new schema simultaneously.

```
@graphql-compat.mdc @src/schema/schema.graphql @src/resolvers/user.resolver.ts

Update the User resolver to support both deprecated and new fields:
1. fullName (deprecated) — still returns firstName + lastName
2. displayName (new) — returns the preferred display name
3. avatarUrl (deprecated) — still returns the URL string
4. avatar (new) — returns { url, width, height, format }

Both old and new resolvers must work simultaneously.
Share logic between deprecated and new resolvers to avoid duplication.
```

**Expected result:** Cursor generates resolvers that serve both deprecated and new fields with shared logic to avoid duplication.

## Complete code example

File: `.cursor/rules/graphql-compat.mdc`

```markdown
---
description: Enforce backward-compatible GraphQL schema changes
globs: "*.graphql,*.gql,*.resolver.ts,*.schema.ts"
alwaysApply: true
---

# GraphQL API Contract Rules

## Core Principle:
The GraphQL schema is a CONTRACT with clients. Every change must be backward-compatible.

## NEVER (Breaking Changes):
- Remove existing fields from any type
- Change the return type of an existing field
- Rename existing queries, mutations, or subscriptions
- Make previously optional arguments required
- Remove values from enums
- Remove types that are used in any operation

## ALWAYS (Safe Changes):
- ADD new fields to existing types
- ADD new queries, mutations, subscriptions
- ADD new types, enums, unions, interfaces
- ADD optional arguments with default values
- USE @deprecated(reason: "Use newField instead") before removal

## Deprecation Pattern:
```graphql
type User {
  fullName: String @deprecated(reason: "Use displayName instead")
  displayName: String
}
```

## Versioning:
- Minor changes: additive fields, new operations
- Major changes (breaking): require /v2 API version
- Deprecated fields: minimum 6-month deprecation window
```

## Common mistakes

- **Asking Cursor to 'refactor' a GraphQL schema without specifying backward compatibility** — The word 'refactor' implies restructuring, which Cursor interprets as permission to rename, remove, and reorganize fields. This breaks existing clients. Fix: Use 'extend' or 'add to' instead of 'refactor'. Always include 'do not remove or modify existing fields' in the prompt.
- **Not referencing the existing schema when requesting changes** — Without seeing the current schema, Cursor may generate a new schema that conflicts with or duplicates existing types and fields. Fix: Always reference your schema file with @file so Cursor sees the complete current state before suggesting changes.
- **Removing deprecated fields immediately after adding replacements** — Clients need time to migrate from deprecated fields to new ones. Removing them immediately breaks clients that have not updated yet. Fix: Add a rule specifying a minimum deprecation period (e.g., 6 months). Only remove fields after confirming no clients still use them.

## Best practices

- Always reference the current schema with @file before requesting changes
- Use additive language in prompts: add, extend, augment — not refactor, restructure, replace
- Add @deprecated with clear reasons and migration paths before removing any field
- Generate resolvers for both old and new fields to support the transition period
- Validate proposed schema changes with a compatibility check prompt before implementing
- Keep a changelog of schema changes committed alongside the schema file
- Test schema changes against existing GraphQL client queries before deploying

## Frequently asked questions

### Can I use GraphQL schema linting to catch breaking changes?

Yes. Tools like graphql-schema-linter and GraphQL Inspector can diff schemas and flag breaking changes in CI. Configure these alongside Cursor rules for defense in depth.

### How do I handle required field additions?

New required fields must have default values or be nullable initially. Add the field as optional first, backfill existing data, then make it required in a later release.

### What about union and interface changes?

Adding new types to a union is safe. Removing types from a union is breaking. Adding fields to an interface is breaking for implementors. Add these specifics to your rules.

### How long should I keep deprecated fields?

Industry standard is 6-12 months. Monitor field usage through GraphQL analytics before removing. Add the minimum period to your rules file.

### Does this apply to REST APIs too?

The same principles apply: additive changes only, deprecation before removal, versioning for breaking changes. Adjust the rules for REST-specific patterns like URL versioning.

### Can RapidDev help design our API evolution strategy?

Yes. RapidDev designs API versioning strategies, sets up schema validation in CI, and configures Cursor rules to maintain backward compatibility across GraphQL and REST APIs.

---

Source: https://www.rapidevelopers.com/cursor-tutorial/how-to-limit-cursor-ai-from-suggesting-graphql-schema-changes-that-break-backward-compatibility
© RapidDev — https://www.rapidevelopers.com/cursor-tutorial/how-to-limit-cursor-ai-from-suggesting-graphql-schema-changes-that-break-backward-compatibility
