Eight Cursor Prompts That Actually Work (With Explanations)
After six months of building with Cursor, these are the eight prompt structures I come back to most — the ones that produce working results on the first try, and why they work.
Cursor is good. Using Cursor well takes a bit of learning.
I figured this out the slow way — six months of sessions that ranged from "this is incredible" to "why did it change four files I didn't ask it to touch." The difference wasn't Cursor. It was how specific I was about what I wanted.
Cursor doesn't guess well. When it doesn't have enough information, it makes assumptions — and those assumptions are often almost-right in a way that creates more work. The prompts that work are the ones that leave nothing important to assumption.
Here are the eight I come back to most. Each one has the structure and a short note on why it works.
1. Building a new component
Create components/OrderCard.tsx.
Props: orderId (string), orderDate (string), total (number),
status ('pending' | 'fulfilled' | 'cancelled').
Display all four. Show status as a colored badge —
match the color logic from components/StatusBadge.tsx.
Tailwind only. No new packages. No test file.
Why it works: Pointing to an existing component for style reference means Cursor matches your actual patterns instead of inventing new ones. It keeps your codebase consistent without you having to explain your design system.
2. Adding a field to an existing form
In components/ProfileForm.tsx, add an optional company name field.
Label: "Company name". Text input, no validation required.
Position it below the full name field.
Include company_name in the form submission object.
Do not change any other fields or the submit handler.
Why it works: The "do not change" instruction does a lot of heavy lifting. Without it, Cursor will often refactor nearby code it thinks could be improved. One small addition turns into a larger change you didn't ask for.
3. Writing a database query
In lib/queries/orders.ts, add a function called getRecentOrdersByUser.
Accepts: userId (string)
Returns: 5 most recent orders for that user
Select only: id, created_at, total, status
Order by: created_at descending
Use the Supabase client from lib/supabaseClient.ts.
Follow the same pattern as the other functions in this file.
Typed return. No console.logs.
Why it works: "Follow the same pattern as existing functions" is one of the most useful instructions I've found. It keeps the codebase consistent without requiring you to explain your conventions — Cursor just reads the file and matches what it sees.
4. Fixing a bug
In components/Dashboard.tsx around line 47, I'm seeing this error:
[paste the full error message and stack trace]
Here's the relevant function:
[paste the function]
Fix only this error. Do not refactor or change anything else.
Why it works: Paste the full error. "It doesn't work" tells Cursor almost nothing. A complete stack trace tells it exactly what broke and where. The "fix only this" constraint keeps a targeted fix from becoming a refactor of adjacent code.
5. Creating an API route
Create app/api/waitlist/route.ts.
POST handler:
- Read email from request body
- Validate it's present and non-empty (return 400 if not)
- Insert into Supabase table 'waitlist': id (uuid, auto), email, created_at (default now())
- Return { success: true } on success
- Return { error: 'Failed to save' } on Supabase error
Use the Supabase client from lib/supabaseClient.ts with the service role key.
No auth required on this route.
Why it works: Spelling out the exact success and error responses means you get exactly what you expect to handle on the frontend. No guessing what format the response will be in.
6. Adjusting a page layout
Update the layout of app/dashboard/page.tsx:
- Full-width header with the title "Dashboard" left-aligned
- Three stat cards in a row below it (they already exist as components — arrange them)
- Full-width OrdersTable component below the cards
- 24px gaps between sections
Tailwind only. Do not change any component logic or props.
Match the spacing style from app/settings/page.tsx.
Why it works: "Do not change component logic" keeps layout changes from turning into a component refactor. Referencing an existing page for spacing reference keeps things consistent.
7. Consolidating duplicated code
In lib/utils/formatDate.ts, the formatDate function is duplicated
three times with slight variations.
Consolidate into one function that accepts an optional format parameter:
'short' | 'long' | 'relative' — default to 'short'.
Update all three call sites to use the new function.
Do not change the output format at any call site — only consolidate the implementation.
Why it works: "Do not change the output format" is the critical constraint here. Without it, Cursor might "improve" the output in ways that break things downstream. You want the implementation consolidated, not the behavior changed.
8. Adding loading and error states
In components/UserList.tsx, add three conditional rendering states:
1. If isLoading is true: show the text "Loading..."
2. If error is present: show "Something went wrong. Please refresh."
3. If the data array is empty: show "No users found."
Use the existing isLoading and error values already coming from the hook.
Do not change the data fetching logic.
Why it works: Pointing to existing values from the hook stops Cursor from adding new state management. You're wiring up UI states to things that already exist, not adding new complexity.
The pattern across all eight
Every one of these prompts has: one specific target, a reference to existing code where relevant, explicit constraints on what not to touch, and a clear output to aim for. Cursor is a capable tool — these prompts make it reliable.
If writing this level of detail for every request feels like a lot of work, Briefli generates Cursor-ready prompts through a short interview. You describe the task, it asks the clarifying questions, it writes the output.
Get your free AI prompt
Enter your email and we’ll send you a custom prompt for your project.
Stop re-writing prompts. Let Briefli build them for you.
Two-minute interview → precise, first-attempt prompt. Free to start.
Try It Free →