Cursor Chat vs Composer: what I open first

Table of Contents
Table of Contents
I used to treat Cursor Chat vs Composer like one tool with two tabs. Then a six-file “small” change landed in the sidebar, I hit apply, and the PR looked like three juniors had a fight.
Chat is for questions. Composer (the multi-file edit surface, Agent in some builds) is for changing files. I mix them up when I am tired. The PR pays for it.
I’m Aris Setiawan. Senior full-stack, first Cursor Ambassador in Indonesia. I ship client work in Cursor every week. This is not a UI tour. It is what I open first on a real repo.
The full production loop is How to use Cursor AI to ship faster without wrecking the codebase. The messy-repo version is How to use Cursor AI effectively on a real repo. This post is just the fork: Chat or Composer.
They are not the same tool

Chat lives in the sidebar. You ask. It reads what you @, plus whatever it needs. It writes an answer. Sometimes it offers an apply. I treat that apply as a suggestion, not a commit.
Composer (or Agent) is a job. You give it a scoped change. It opens files, edits several of them, and comes back with a diff you are supposed to read like a junior’s PR.
If I ask Chat to “add CSV export on invoices,” it will explain a plan, maybe dump a snippet that does not match this repo’s helper, and I will paste it into the wrong folder. If I give Composer the same sentence with no fence, it will touch billing, rename a shared type, and open a 30-file diff.
Same model. Different job. The surface is the contract.
When I use Chat
I use Chat when I do not know the shape yet.
Trace. Where does this invoice status actually get set? Which package owns the CSV helper? I @ one or two files and ask. I want a map, not a patch.
Plan. “We need export on the list. Propose the smallest change. Do not write files. Name the paths.” I make it argue with me in Chat until the plan fits on a sticky note.
Explain a weird error. Stack traces, a failing test, a type that only explodes in CI. Chat is faster than me grepping with one eye on Slack.
Review a small hunk. I paste a function and ask what looks off. I do not ask Chat to rewrite the module while I am still reading it.
A Chat prompt I actually use:
In
apps/web/app/invoices, where does list filtering live? Do not suggest new files. Point me at the existing helper if there is one.
If the answer names a folder I did not know about, I open that folder. Then I decide if Composer is allowed to touch it.
I do not use Chat to “just apply this across the app.” Apply-from-chat on a client repo is how a helper lands in utils2.ts next to the one we already have.
When I use Composer
I use Composer when I can name the files.
The change is clear. The blast radius is a sentence. I already looked at a sibling file so it can match the local pattern.
Multi-file, still small. A list page plus the export helper. A form plus the action. Not “refactor the billing package.”
PR-sized. A teammate should finish the diff in one sitting. If Composer wants a second package I did not name, I stop it.
A Composer prompt I actually use:
Add CSV export on the invoices list. Touch
apps/web/app/invoicesandpackages/exportonly. Do not touchpackages/billingor webhooks. Reuse the existing CSV helper. Match the error shape in the nearby list route.
Open the files first. @ those paths. Name what is off-limits. Same habit as the effective-on-a-real-repo post. Composer without a fence is Chat with write access. That is worse, not faster.
If I cannot name the folders, I am not ready for Composer. Back to Chat.
My loop

Unclear: Chat. Clear change: Composer. Then I still read it.
I do not skip the last box. Composer is confident. Confident is not correct. I read the diff like a senior reading a junior. Types, names, the extra file I did not ask for, the test it skipped because “the pattern was obvious.”
If the diff is bigger than the sticky note, I revert the extra and split the work. Two Composer jobs beat one “while we are here” job.
A loop I trust:
- Ask Chat where this kind of change lives.
- Open those files. Write the fence.
- Run Composer once.
- Read every file it touched. If it opened a stranger, stop.
That is Cursor Chat vs Composer without letting Chat quietly become an unscoped agent.
Mistakes I still see
Pasting a spec into Chat and hitting apply. The spec was a wish. Apply is a commit-shaped object. Keep the wish in Chat. Keep the commit in Composer, with a fence.
Composer with the whole repo in context. It will “help” the neighboring app. Helpful without a map is how Friday’s PR becomes Monday’s revert.
Skipping review because the summary sounded right. Summaries are marketing. The diff is the work. I read the diff.
Using Composer to ask questions. You can. I do not. Questions are cheaper in Chat. Composer will start editing while it explains.
Switching models to fix a bad surface pick. A better model in the wrong surface still writes the wrong size of change. Pick the surface first.
What I tell people who ship
If you are still installing Cursor, start with the beginner tutorial. If you already ship, remember this:
Chat is the senior in the room when you are lost. Composer is the junior you hired for a scoped ticket. You are still the one who merges.
The fix for huge diffs is almost never “use a smarter model.” It is stop asking Chat to ship, and stop asking Composer to think. Practice that loop on your actual repo once.
If you want a second pair of eyes while you install the habit, that is Level up.



