# Why Cursor ignores ORM naming conventions

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

## TL;DR

Cursor generates TypeORM entities with camelCase column names that do not match your database's snake_case conventions because it ignores your NamingStrategy configuration. By referencing your ormconfig with @file, adding TypeORM rules to .cursorrules, and including your naming strategy in the entity generation prompt, you get entities that match your actual database schema.

## Why Cursor ignores ORM naming conventions

TypeORM naming strategies (like SnakeNamingStrategy) transform entity property names to database column names automatically. Cursor does not read your ormconfig or data source configuration, so it generates entities with default camelCase naming that fails at runtime. This tutorial fixes the disconnect.

## Before you start

- Cursor installed with a NestJS + TypeORM project
- A naming strategy configured (e.g., typeorm-naming-strategies)
- Existing database with established naming conventions
- Familiarity with Cursor Chat (Cmd+L) and Cmd+K

## Step-by-step guide

### 1. Add TypeORM rules to .cursor/rules

Create rules that specify your naming convention and TypeORM patterns. This ensures Cursor generates entities that match your database schema.

```
---
description: TypeORM entity conventions
globs: "src/**/*.entity.ts"
alwaysApply: true
---

## TypeORM Naming Rules
- Database uses snake_case column names
- Entity properties use camelCase
- SnakeNamingStrategy is configured in data source
- Do NOT add explicit @Column({ name: 'snake_case' }) — the strategy handles it
- Use @CreateDateColumn() for created_at (auto-mapped to snake_case)
- Use @UpdateDateColumn() for updated_at (auto-mapped to snake_case)
- Use @PrimaryGeneratedColumn('uuid') for IDs
- Join columns: @JoinColumn() without explicit name (strategy handles it)
- Table names: @Entity('table_name') with explicit snake_case name

## NestJS Patterns
- Entities in src/modules/{module}/entities/
- DTOs in src/modules/{module}/dto/
- Repositories use @InjectRepository(Entity)
```

**Expected result:** Cursor generates TypeORM entities that work with your SnakeNamingStrategy.

### 2. Reference your data source config in prompts

When generating entities, reference your TypeORM data source configuration so Cursor sees the naming strategy and connection settings.

```
// Cursor Chat prompt (Cmd+L):
// @src/config/data-source.ts @.cursor/rules/typeorm.mdc
// Generate a Product entity for the 'products' table with:
// - id (UUID primary key)
// - name (string, not null)
// - description (text, nullable)
// - price (decimal 10,2)
// - stockQuantity (integer, default 0)
// - isActive (boolean, default true)
// - categoryId (UUID foreign key to categories)
// - createdAt, updatedAt timestamps
//
// Our SnakeNamingStrategy maps camelCase properties to
// snake_case columns automatically.
```

**Expected result:** An entity with camelCase properties that the naming strategy maps correctly to snake_case columns.

### 3. Generate the entity with correct decorators

The generated entity should use camelCase properties without explicit column name overrides. The naming strategy handles the mapping.

```
import { Entity, Column, PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn, ManyToOne, JoinColumn } from 'typeorm';
import { Category } from './category.entity';

@Entity('products')
export class Product {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column({ type: 'varchar', length: 255 })
  name: string;

  @Column({ type: 'text', nullable: true })
  description: string | null;

  @Column({ type: 'decimal', precision: 10, scale: 2 })
  price: number;

  @Column({ type: 'int', default: 0 })
  stockQuantity: number;

  @Column({ type: 'boolean', default: true })
  isActive: boolean;

  @ManyToOne(() => Category)
  @JoinColumn()
  category: Category;

  @Column({ type: 'uuid' })
  categoryId: string;

  @CreateDateColumn()
  createdAt: Date;

  @UpdateDateColumn()
  updatedAt: Date;
}
```

> Pro tip: Do NOT add explicit column names like @Column({ name: 'stock_quantity' }). The SnakeNamingStrategy handles this automatically. Adding explicit names would double-transform the name.

**Expected result:** An entity with camelCase properties and no explicit column name overrides.

### 4. Audit existing entities for naming mismatches

Check your existing entities for naming issues that may have been introduced by Cursor without the rules in place.

```
// Cursor Chat prompt (Cmd+L, Ask mode):
// @src/ Find all TypeORM entities and check for:
// 1. Explicit @Column({ name: '...' }) that conflict with
//    the SnakeNamingStrategy (double transformation)
// 2. Properties that don't follow camelCase convention
// 3. @Entity() without explicit table name
// 4. Missing @CreateDateColumn or @UpdateDateColumn
// 5. @JoinColumn with explicit name that conflicts with strategy
```

**Expected result:** A report of naming mismatches and conflicts in existing entities.

### 5. Generate matching DTOs and migrations

Ask Cursor to generate DTOs and a migration for the entity, ensuring consistent naming throughout the module.

```
// Cursor Chat prompt (Cmd+L):
// @src/modules/product/entities/product.entity.ts
// Generate:
// 1. CreateProductDto with class-validator decorators
// 2. UpdateProductDto (Partial of Create)
// 3. A TypeORM migration that creates the products table
//    with snake_case column names matching our entity
//    (stock_quantity, is_active, category_id, created_at, updated_at)
```

**Expected result:** DTOs and migration that are consistent with the entity and naming strategy.

## Complete code example

File: `src/modules/product/entities/product.entity.ts`

```typescript
import {
  Entity,
  Column,
  PrimaryGeneratedColumn,
  CreateDateColumn,
  UpdateDateColumn,
  ManyToOne,
  JoinColumn,
  Index,
} from 'typeorm';
import { Category } from '../../category/entities/category.entity';

@Entity('products')
export class Product {
  @PrimaryGeneratedColumn('uuid')
  id: string;

  @Column({ type: 'varchar', length: 255 })
  @Index()
  name: string;

  @Column({ type: 'text', nullable: true })
  description: string | null;

  @Column({ type: 'decimal', precision: 10, scale: 2 })
  price: number;

  @Column({ type: 'int', default: 0 })
  stockQuantity: number;

  @Column({ type: 'boolean', default: true })
  isActive: boolean;

  @ManyToOne(() => Category, { onDelete: 'SET NULL', nullable: true })
  @JoinColumn()
  category: Category | null;

  @Column({ type: 'uuid', nullable: true })
  @Index()
  categoryId: string | null;

  @CreateDateColumn()
  createdAt: Date;

  @UpdateDateColumn()
  updatedAt: Date;
}

// With SnakeNamingStrategy, columns in database:
// id, name, description, price, stock_quantity,
// is_active, category_id, created_at, updated_at
```

## Common mistakes

- **Adding explicit @Column({ name: 'snake_case' }) with a naming strategy** — The naming strategy already transforms camelCase to snake_case. Adding explicit names causes double transformation: stockQuantity -> stock_quantity -> stock_quantity (works by coincidence) or worse, conflicts. Fix: Add 'Do NOT add explicit column names, the naming strategy handles it' to .cursorrules.
- **Cursor generating entities without @Entity('table_name')** — Without an explicit table name, TypeORM may generate a table name that does not match your database convention. Fix: Always specify the table name: @Entity('products'). Add this requirement to your TypeORM rules.
- **Using @Column() without type specification** — Cursor may omit the column type, letting TypeORM infer it. Inferred types can vary across databases and may not match your schema. Fix: Require explicit types: @Column({ type: 'varchar', length: 255 }). Add this to your .cursorrules.

## Best practices

- Reference your data source config with @file when generating entities
- Add TypeORM rules specifying naming conventions to .cursor/rules
- Use camelCase properties without explicit column names when using a naming strategy
- Always specify @Entity('table_name') with explicit snake_case table name
- Include explicit column types in @Column decorators
- Generate DTOs and migrations alongside entities for consistency
- Audit existing entities periodically for naming strategy conflicts

## Frequently asked questions

### What is the SnakeNamingStrategy?

It is a TypeORM naming strategy from the typeorm-naming-strategies package that automatically converts camelCase entity properties to snake_case database columns. For example, stockQuantity becomes stock_quantity.

### Can Cursor generate TypeORM migrations?

Yes. Reference the entity and ask Cursor to generate a migration. However, for production, always use TypeORM's CLI: npx typeorm migration:generate to ensure accuracy.

### How do I handle custom column names that differ from the naming convention?

For exceptions, use @Column({ name: 'custom_name' }). Add a comment explaining why the override exists. This should be rare with a proper naming strategy.

### Does this apply to Prisma or Drizzle?

Each ORM has its own naming conventions. Create separate .cursor/rules for your ORM. Prisma uses @map for column names, Drizzle uses explicit column definitions.

### Will Cursor respect the naming strategy in query builder code?

Not automatically. When generating QueryBuilder code, Cursor should use camelCase property names, not snake_case column names. The naming strategy translates at the ORM level.

---

Source: https://www.rapidevelopers.com/cursor-tutorial/how-to-fix-cursor-ai-suggestions-that-ignore-typeorm-naming-strategies-in-nestjs-apps
© RapidDev — https://www.rapidevelopers.com/cursor-tutorial/how-to-fix-cursor-ai-suggestions-that-ignore-typeorm-naming-strategies-in-nestjs-apps
