# How to reuse shared utilities with Cursor

- Tool: Cursor
- Difficulty: Beginner
- Time required: 10-15 min
- Compatibility: Cursor Free+, any monorepo setup (npm workspaces, Turborepo, Nx)
- Last updated: March 2026

## TL;DR

Cursor often generates duplicate utility functions instead of importing existing shared ones from a monorepo's root packages. By creating .cursor/rules with explicit import paths, referencing shared packages with @file in prompts, and structuring your monorepo so Cursor can discover shared code, you eliminate duplication and keep your codebase DRY.

## Making Cursor aware of shared utilities in a monorepo

In monorepo setups, shared utility functions live in a common package like packages/shared or libs/utils. Cursor often does not know these exist and generates duplicate implementations. This tutorial shows you how to configure Cursor rules, reference shared packages in prompts, and structure your project so the AI always imports from the right place.

## Before you start

- Cursor installed with a monorepo project open
- A shared utilities package in your monorepo (e.g., packages/shared)
- Basic familiarity with Cursor Chat (Cmd+L) and Composer (Cmd+I)
- Understanding of your monorepo's import path aliases

## Step-by-step guide

### 1. Create a shared utilities index file

Ensure your shared package has a clean index file that re-exports all utilities. Cursor reads this file to understand what shared functions are available. A well-organized barrel export makes it easy for the AI to discover existing utilities.

```
// packages/shared/src/index.ts

// String utilities
export { capitalize, slugify, truncate } from './string';

// Date utilities
export { formatDate, parseISO, daysBetween } from './date';

// Validation utilities
export { isEmail, isURL, isUUID } from './validation';

// HTTP utilities
export { fetchWithRetry, buildQueryString } from './http';

// Type guards
export { isNonNull, isString, isNumber } from './guards';
```

**Expected result:** A single entry point that lists all available shared utilities for Cursor to reference.

### 2. Add monorepo-aware rules to .cursor/rules

Create a rule file in each sub-package that tells Cursor where shared utilities live and how to import them. This rule auto-attaches when Cursor works on files in that package.

```
---
description: Import rules for apps/web package
globs: "apps/web/src/**/*.{ts,tsx}"
alwaysApply: true
---

## Shared Utilities
- ALWAYS check @packages/shared/src/index.ts before creating utility functions
- Import shared utilities with: import { fn } from '@myorg/shared'
- NEVER duplicate functions that already exist in packages/shared
- Available shared utilities: capitalize, slugify, truncate, formatDate,
  parseISO, daysBetween, isEmail, isURL, isUUID, fetchWithRetry,
  buildQueryString, isNonNull, isString, isNumber

## Import Paths
- Shared package: @myorg/shared
- UI components: @myorg/ui
- Config: @myorg/config
```

> Pro tip: List the most commonly used shared functions directly in the rule. This way Cursor knows what exists without needing to read the actual file every time.

**Expected result:** Cursor will check for existing shared utilities before generating new ones in any apps/web file.

### 3. Reference shared packages in your prompts

When asking Cursor to generate code that might need utilities, explicitly reference the shared package using @file or @folder. This gives the AI direct visibility into what already exists. Open Cmd+L and include the reference before your request.

```
// Cursor Chat prompt (Cmd+L):
// @packages/shared/src/index.ts
// @packages/shared/src/validation.ts
// Create a registration form handler in apps/web that
// validates email and URL inputs. Use the validation
// functions from our shared package instead of writing
// new ones.
```

**Expected result:** Cursor generates a handler that imports isEmail and isURL from @myorg/shared instead of reimplementing them.

### 4. Configure .cursorignore for monorepo performance

Large monorepos can overwhelm Cursor's indexing. Exclude build artifacts, node_modules, and unrelated packages from indexing while keeping shared packages visible. This improves performance and reduces noise in AI suggestions.

```
# .cursorignore (project root)
node_modules/
dist/
build/
.next/
coverage/
*.log

# Exclude packages you never work on
# packages/legacy-api/
# packages/deprecated-ui/
```

> Pro tip: Do NOT add your shared packages to .cursorignore. Cursor needs to index them to suggest correct imports.

**Expected result:** Cursor indexes only relevant source code, with shared packages fully visible for import suggestions.

### 5. Test with a new feature generation prompt

Verify the setup by asking Cursor to generate a new feature that would typically need utility functions. The AI should import from the shared package rather than creating local copies. Use Composer (Cmd+I) for a multi-file generation.

```
// Composer prompt (Cmd+I):
// @packages/shared/src/index.ts Generate a new API route
// at apps/api/src/routes/users.ts that:
// 1. Validates email input using shared utilities
// 2. Slugifies the username using shared utilities
// 3. Formats dates using shared utilities
// Import all utilities from @myorg/shared. Do not create
// any new utility functions.
```

**Expected result:** Cursor generates the route file with correct imports from @myorg/shared and zero duplicate utility code.

## Complete code example

File: `.cursor/rules/monorepo-imports.mdc`

```markdown
---
description: Monorepo import rules and shared package awareness
globs: "apps/*/src/**/*.{ts,tsx},packages/*/src/**/*.{ts,tsx}"
alwaysApply: true
---

## Monorepo Structure
This is a monorepo using npm workspaces with the following packages:
- packages/shared — utility functions, type guards, validators
- packages/ui — shared React components (Button, Modal, Input)
- packages/config — shared configuration (ESLint, TypeScript, Tailwind)
- apps/web — Next.js frontend application
- apps/api — Express.js backend API

## Import Rules
- ALWAYS check packages/shared before writing utility functions
- Import shared utils: import { fn } from '@myorg/shared'
- Import UI components: import { Component } from '@myorg/ui'
- NEVER create local utility files that duplicate shared functionality
- NEVER import directly from relative paths across packages
  (use package names: @myorg/shared, not ../../packages/shared)

## Available Shared Utilities
- String: capitalize, slugify, truncate, camelCase, kebabCase
- Date: formatDate, parseISO, daysBetween, isExpired
- Validation: isEmail, isURL, isUUID, isPhoneNumber
- HTTP: fetchWithRetry, buildQueryString, parseSearchParams
- Guards: isNonNull, isString, isNumber, isDefined

## Before Creating New Utilities
1. Search @packages/shared for existing implementation
2. If it does not exist, add it to packages/shared (not locally)
3. Export from packages/shared/src/index.ts
4. Import in consuming packages via @myorg/shared
```

## Common mistakes

- **Adding shared packages to .cursorignore** — If packages/shared is in .cursorignore, Cursor cannot index it and will never suggest imports from it. Fix: Only add build artifacts and node_modules to .cursorignore. Keep all source packages indexed.
- **Not listing available utilities in .cursor/rules** — Cursor may not always read the shared package index file. Listing utilities directly in rules ensures the AI knows what exists. Fix: Add a bulleted list of available shared functions to your monorepo-imports.mdc rule file.
- **Using relative import paths across packages** — Cursor may generate imports like '../../packages/shared/src/string' which breaks when packages are moved or built. Fix: Add a rule requiring package name imports (@myorg/shared) and never relative cross-package paths.

## Best practices

- Maintain a barrel index.ts in every shared package that re-exports all public utilities
- List available shared functions directly in .cursor/rules files for quick AI reference
- Reference @packages/shared/src/index.ts in every prompt that may need utility functions
- Open separate Cursor windows for different packages in very large monorepos
- Use .cursorindexingignore for files that should not be indexed but can still be read when referenced
- Commit .cursor/rules/ to Git so all team members get the same monorepo-aware AI behavior
- Use Notepads to store frequently referenced shared package documentation

## Frequently asked questions

### Why does Cursor keep creating duplicate utility functions?

Cursor generates duplicates when it cannot see the shared package. Reference @packages/shared/src/index.ts in your prompt and add an alwaysApply rule listing available utilities.

### Should I open the whole monorepo or just one package in Cursor?

For daily work in a specific package, opening just that package is faster. For cross-package work or refactoring shared code, open the whole monorepo so Cursor can index all packages.

### How do I handle tsconfig path aliases in Cursor?

Cursor reads your tsconfig.json paths. Ensure @myorg/shared is properly mapped in tsconfig.json. Reference the tsconfig in your .cursorrules if Cursor generates wrong import paths.

### Can Cursor create new shared utilities automatically?

Yes. Use Composer (Cmd+I) with a prompt like: 'Add a new sanitizeHTML function to packages/shared/src/string.ts and export it from the index. Then use it in apps/web/src/components/RichText.tsx.'

### What if my shared package is in a different repository?

Use @docs to index the shared package documentation. Alternatively, use a Notepad containing the shared package API surface and reference it with @notepad-name in your prompts.

---

Source: https://www.rapidevelopers.com/cursor-tutorial/how-to-ensure-cursor-ai-references-shared-utility-functions-in-a-monorepo-s-root-folder
© RapidDev — https://www.rapidevelopers.com/cursor-tutorial/how-to-ensure-cursor-ai-references-shared-utility-functions-in-a-monorepo-s-root-folder
