Practical Cursor IDE tips
Cursor is a code editor with deeply integrated AI coding assistance. It is, hands down, the best value $192/year I spend on anything. Cursor has reportedly made Anysphere the fastest growing SaaS company of all time, and for good reason: the product is fantastic and the AI coding experience is unmatched as of February 2025.
The following is a list of configuration settings and practical techniques I've found make a noticeable difference to my productivity: they are small changes with a big impact. If you think I'm missing out on something, please !
- Establish global AI rules
- Add a .cursorrules file to every project
- Use Agent mode for code changes
- Write clear, detailed instructions
- Type @ to bring file context into conversation
- Create more smaller files instead of fewer larger files
- Keep conversations short and focused
- Don’t be afraid to use images
- Commit early, commit often
- Let the AI write tests
Establish global AI rules
Found under Settings → Cursor Settings → Rules → User Rules (or General → Rules for AI before v0.46), this free-form text box allows you to provide guidance to the AI every time you interact with it, without having to type it every time. In effect, this is a mini-prompt that you can use to establish universal guidelines you always want the AI to follow across all projects.
Here are my current global rules, which are pretty basic and in parts, overly-specific:
Prefer functional code over imperative where at all possible.
If the language is TypeScript or JavaScript, omit semi-colons at the end of lines.
Use Tailwind CSS for styling.
For network requests always use fetch instead of a library like axios.
Always prefer British-English spelling over American-English.
Always use date-fns for any date manipulation or comparison.
Use sentence case for all copy - not Title Case.
You can find lots more examples over at cursor.directory or in the awesome-cursorrules repository, and mix and match the best of them.
It's worth remembering that global rules are set at IDE level and will vary per developer, so shouldn't be relied upon when working as part of a team. Project-specific rules, covered next, solve that.
Add a .cursorrules file to every project
Adding a .cursorrules
file to the root of every project is a few minutes of upfront work which pays
back every single time you interact with the AI. While global rules set blanket preferences,
project rules establish the context and constraints specific to each codebase. Even a few words of guidance can make a big difference,
and you can (and should) keep iterating on these rules as you go.
Here's my .cursorrules
file from fitIQ:
This repository is fitIQ, the Advanced WHOOP Analytics platform. WHOOP is a smart wearable which offers unparalleled
insight into your physiological, activity and sleep data. fitIQ is the number one platform to get more insight into
your WHOOP data.
The tech stack is as follows:
- NextJS - using the older 'Pages' Router
- Supabase - auth and backend
- TailwindCSS - styling
- ShadCN components may be used if you wish
- Resend - transactional email
- Inngest - background jobs
All code is written in TypeScript.
The authenticated fitIQ experience is split into two distinct parts:
1. For individual users who own a WHOOP and want more out of their metrics
2. For team owners (health professionals, corporate wellness etc) who want to monitor their clients' progress
When writing code, please ensure you log liberally using console.log, console.warn and console.error as appropriate.
All interaction with Supabase is via the Supabase SDK. Most queries wrap PostgREST, so use that as the query format.
Sometimes I give hints about business logic which might be non-obvious. This is from a recent venture into the world of property management:
- The properties table is self-referential: a property can have a parent_id which refers to another row in the properties table. This allows for a hierarchical property structure (e.g. Building -> Floor -> Property, or Building -> Property).
- This hierarchy plays a crucial role everywhere properties are concerned, so bear it in mind at all times.
- A "leaf" property is one which has no children. Leaf properties can have leaseholders (people who own and live in them). Root or branch
properties cannot - by definition they represent things like buildings and floors, rather than dwellings.
Along with some code style preferences further down the file:
- Avoid having too many local functions inside React components. Extract them to the models structure.
- Don't add any container classes/padding to page components. This is taken care of in our layout. Make sure you use breadcrumbs in every page you create.
- Create small, self-contained components within pages. When doing so, create them in the same directory as the page.tsx file - do NOT create a components sub-directory.
- Create tests under the top-level tests directory, within the e2e or unit sub-directory, as relevant. We use playwright for e2e tests and vitest for unit tests.
The longest .cursorrules
file I've got is for Bluesky Playground, in which I briefly introduce the idea
behind the website and then dump in the entire offical Jetstream repository README markdown contents.
It's lazy, but it works pretty well—especially when I was bootstrapping the site from scratch.
Use Agent mode for code changes
Cursor has three primary modes of interacting with the AI:
- Chat mode - Conversations where you do not want the AI to make any code changes
- Edit mode - Direct file edits with AI assistance
- Agent mode - Complex, multi-step tasks with autonomous execution
I have found no good reason to use Edit over Agent mode, and I suspect the former’s time is limited (it predates agent mode, when Cursor's UI and UX was very different). Chat has its place (although agent mode is fairly good at not editing code if you tell it not to), but the ergonomics of the side panel interface make long-form conversation clunky—you’re better off switching to your favourite chat bot for that.
Agent mode is as it sounds: agentic, multi-step edits, across multiple files, with autonomous execution and the ability to execute shell commands to verify or enable behaviour. By default the latter will cause the agent to wait for your approval, but you can enable Yolo mode to have it execute them without asking.
Write clear, detailed instructions
For bigger tasks, I try and approach the start of a conversation like I'm writing a ticket I'd want a junior on my team to be able to follow. Clear requirements, a rough outline of what I expect (albeit with the freedom for the AI to pick a better approach), and lots of small, relevant files included as context.
You can use your judgement here: not everything needs to be war and peace. But it's almost always better to get as much pertinent information into that initial prompt rather than adding it haphazardly throughout a conversation.
Type @ to bring file context into conversation
Context is king, so providing the AI with relevant information dramatically improves the chances
that it will do the right thing. During any conversation you can type @
to start fuzzy-matching against file names—or even whole directories—in the project.
Use the latter with caution since AI context windows are limited, but drop file references in alongside your
requirements liberally.

Create more smaller files instead of fewer larger files
This is good general coding practice, and it comes with the nice side effect of being much easier for the AI to do the right thing. For starters, it lets you provide more granular and precise context (see above). Secondly, it reduces the risk the AI going off-piste half way through a complex changeset in a large file. Thirdly, when things do go wrong (and they will), it's far easier to deal with the fallout when it's confined to small, single-purpose files.
Instruct the AI on this, too: I sometimes go as far as creating empty placeholder files and tagging them as context to help the AI know where I want it to make changes if it needs a little nudge.
Keep conversations short and focused
AI context windows are limited and are a precious resource. You are guaranteed to lose context given a long enough conversation, even though under the hood Cursor does clever things to try and mitigate this, so try and avoid them dragging on indefinitely. If you're stuck in a loop where the AI is not making progress, scrap the conversation and start a new one, with a new set of tweaked requirements, being sure to include in your new prompt any relevant pointers you've since learned that the old one was missing.
Don’t be afraid to use images
Importing images into a conversation works surprisingly well. I regularly take screenshots of UI bugs, or v0.dev layouts I like the look of, and paste them in alongside my text. Frankly, I'm in awe that this works at all, but it does. I've talked about playing Cursor and v0 off against each other before, and I really recommend trying it out for yourself.

Commit early, commit often
Cursor creates checkpoints before each set of changes it makes, and more often than not you can use these to safely restore previous state if something goes off the rails. But complex conversations can be surprisingly non-linear - you might go back and edit a previous message, correct a typo, selectively reject some edit changes, etc. I often commit when I feel the conversation has contributed meaningful forward progress I'd be reluctant to lose, and I rely almost exclusively on git to revert to a known-good state if things go wrong.
Let the AI write tests
I'm behind the curve on this one and don't lean on the AI here nearly as much as I should, having for a long time been wary of the AI happily writing passing tests for incorrect code. But here, again, it is surprisingly good, especially if you're following other practices like having small files and writing clear, detailed instructions.
