
5 Cursor AI Rules That Save Hours Every Week (Real Examples) I've been shipping SaaS...
I've been shipping SaaS products with Cursor for over a year. Most of that time, I was wasting hours on repetitive corrections — fixing the same patterns, re-explaining the same conventions, catching the same bugs.
Then I started writing .cursorrules that actually work.
Not generic advice like "write clean code." Real, specific rules that changed how Cursor generates code for my projects. Here are the 5 that save me the most time every single week.
This is the single highest-ROI rule I've ever written:
You are an expert software engineer. Always write production-ready code.
Never write placeholder comments like "// TODO" or "// implement later"
— implement it now or tell me what information you need.
Without this rule, Cursor does this constantly:
export async function processPayment(amount: number) {
// TODO: Implement payment processing
console.log('Payment amount:', amount);
}
That TODO becomes a bug in production. Every single time.
With this rule, Cursor generates complete implementations:
export async function processPayment(amount: number) {
if (!process.env.STRIPE_SECRET_KEY) {
throw new Error('STRIPE_SECRET_KEY not configured');
}
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);
return await stripe.paymentIntents.create({
amount,
currency: 'usd'
});
}
Time saved: ~2 hours/week chasing down incomplete implementations.
This rule prevents the most common production bug: "it just stopped working and I don't know why."
Always wrap async operations in try/catch. Return typed error
objects, don't just throw strings. Log errors with context:
console.error('[ComponentName] Error:', error).
In UI components, always provide user-facing error states.
Without this rule:
export async function createSubscription(userId: string, planId: string) {
const stripe = new Stripe(process.env.STRIPE_KEY!);
const subscription = await stripe.subscriptions.create({
customer: userId,
items: [{ price: planId }]
});
return subscription;
}
One network blip and this crashes with no useful information.
With this rule:
export async function createSubscription(userId: string, planId: string) {
try {
const stripe = new Stripe(process.env.STRIPE_KEY!);
const subscription = await stripe.subscriptions.create({
customer: userId,
items: [{ price: planId }]
});
return { success: true, data: subscription };
} catch (error) {
console.error('[createSubscription] Failed:', error);
return {
success: false,
error: error instanceof Stripe.errors.StripeError
? error.message
: 'Subscription creation failed'
};
}
}
Time saved: ~3 hours/week debugging production errors that would've been caught.
I've seen apps start fine, serve 100 requests, then crash because one env var was missing. This rule eliminates that entire class of bugs:
All environment variables must be validated on startup using
a Zod schema in lib/env.ts. Server-only vars have no prefix.
Public vars use NEXT_PUBLIC_ prefix. Never hardcode values
that belong in env.
Without this rule:
// Hardcoded — security risk
const stripe = new Stripe('sk_test_...');
// No validation — crashes at runtime
const apiKey = process.env.API_KEY;
fetch(`https://api.example.com?key=${apiKey}`); // undefined if missing
With this rule:
// lib/env.ts
import { z } from 'zod';
const envSchema = z.object({
DATABASE_URL: z.string().url(),
STRIPE_SECRET_KEY: z.string().startsWith('sk_'),
NEXT_PUBLIC_APP_URL: z.string().url(),
});
export const env = envSchema.parse(process.env);
// Usage — fails fast on deploy, not on first request
import { env } from '@/lib/env';
const stripe = new Stripe(env.STRIPE_SECRET_KEY);
Time saved: ~1 hour/week of "why is this undefined in production" debugging.
Every npm package is a supply chain risk, a bundle size increase, and a maintenance burden. This rule has prevented me from adding 50+ unnecessary packages:
Before suggesting a new npm package, tell me: (1) what it does,
(2) its weekly downloads and last update, (3) whether we could
do it without adding a dependency. Never add dependencies for
tasks under 20 lines of code.
Without this rule:
import { capitalize } from 'lodash'; // 4MB bundle increase
import { formatDate } from 'date-fns'; // 100KB
export function formatUserName(name: string, date: Date) {
return `${capitalize(name)} - ${formatDate(date, 'yyyy-MM-dd')}`;
}
With this rule:
export function formatUserName(name: string, date: Date) {
const capitalized = name.charAt(0).toUpperCase() + name.slice(1);
const formatted = date.toISOString().split('T')[0];
return `${capitalized} - ${formatted}`;
}
Same result. Zero dependencies. 4 lines of code.
Time saved: ~1 hour/week of dependency management, version conflicts, and bundle size debugging.
If you're using Next.js 14+, this rule alone cuts your bundle size and eliminates waterfall requests:
This project uses Next.js 14+ with App Router. Always use server
components by default. Add "use client" only when necessary
(event handlers, hooks, browser APIs). Explain your choice
when adding "use client".
Without this rule:
"use client";
import { useState, useEffect } from 'react';
export function UserProfile({ userId }: { userId: string }) {
const [user, setUser] = useState(null);
useEffect(() => {
fetch(`/api/users/${userId}`)
.then(r => r.json())
.then(setUser);
}, [userId]);
return user ? <div>{user.name}</div> : <div>Loading...</div>;
}
Client component, useEffect fetch, loading state, waterfall request. All unnecessary.
With this rule:
// Server component — no "use client" needed
export async function UserProfile({ userId }: { userId: string }) {
const user = await db.user.findUnique({ where: { id: userId } });
return user ? <div>{user.name}</div> : <div>User not found</div>;
}
Smaller bundle. Faster load. No loading spinner. No waterfall.
Time saved: ~2 hours/week refactoring unnecessary client components back to server components.
Each rule saves 1-3 hours per week. Together, that's ~9 hours/week of work that just... doesn't need to happen anymore.
The key insight: good .cursorrules aren't about making Cursor smarter. They're about making it consistent. You define the pattern once, Cursor applies it everywhere, and you stop repeating yourself.
These 5 rules are from my Cursor Rules Pack v2 — a collection of 50 production-tested rules with real TypeScript/Next.js code examples. If you're using Claude Code instead of Cursor, check out the CLAUDE.md Rules Pack — same patterns, optimized for Claude's instruction format.
One good rule prevents one production bug. One production bug costs hours. Do the math.
cursorCursor Automations in 2026: wire event-triggered coding agents to Slack, CI, and...
aiThe specs exist. The AI just can't see them. I've always been the type who builds hobby...
amazonbedrockConnect Claude Code, Cursor and Codex to Amazon Bedrock's new console (2026) Summary. On 5...
aiThere is a weird uncanny valley with LLM-generated UI right now. The code functions perfectly, but if...
aiI went down a rabbit hole this morning reading the late-2025 Juejin AI roundups side by side, and the...
mcpInstall guide and config at curatedmcp.com Zendesk MCP: Let Claude Handle Your Support...
Workflows from the Neura Market marketplace related to this Cursor resource