guide

How to Write Better Prompts for AI Coding Tools

Bad prompts waste your AI credits and break your flow. Learn how to write better prompts for Cursor, Claude Code, and Copilot — with before/after examples.

Sam OkaforBy Sam Okafor · The teacherMay 10, 2026
Verified June 2026

Sam Okafor is a fictional AI persona, not a real person. This article was written by AI and reviewed by a human editor before publishing. How we work →

How to Write Better Prompts for AI Coding Tools

Most beginners hit the same wall. The AI tool looks impressive in demos, but when they sit down and type their first request, it produces something useless — or worse, something almost right that silently breaks something else. The problem is rarely the tool.

Vague prompts get vague results. Specific prompts get working code. This guide shows you the difference with real before/after rewrites you can copy and adapt right now.

Why Your Prompts Are Failing

AI coding tools like Cursor, Claude Code, and GitHub Copilot don't know your codebase, your conventions, or what "make it better" actually means to you. They work with the context you give them. If your prompt is vague, they fill the gaps with assumptions — and those assumptions are often wrong.

The four most common beginner mistakes:

  • Asking for the outcome without describing the current state
  • Using subjective words like "clean," "fix," or "improve" without defining what's wrong
  • Leaving out the tech stack or framework
  • Writing one giant request instead of breaking it into steps

The Core Pattern: Context + Task + Constraint

Every good coding prompt has three parts. You don't need to be formal about it — just make sure all three are present.

Context — What file, function, or feature is this about? What does it currently do?

Task — What exactly do you want changed or built?

Constraint — What are the limits? Language, framework, style, what not to touch?

Here's the pattern in plain English: "In [file], [current behavior]. Change it to [desired behavior]. Use [language/framework] and don't modify [thing to leave alone]."

That's it. Everything below is just this pattern applied to real situations.

Before/After: The Most Common Prompt Mistakes

Mistake 1: The Vague Fix Request

Before:

Fix my login function

After:

In `auth.js`, the `loginUser()` function returns undefined when the email doesn't exist instead of throwing an error.
Change it to throw a new Error("User not found") in that case.
Don't change the password hashing logic.

The "before" prompt forces the AI to guess what's broken. The "after" tells it exactly where to look, what the bug is, and what to protect.

Mistake 2: The Floating Feature Request

Before:

Add a dark mode toggle

After:

Add a dark mode toggle button to the `<Header>` component in `components/Header.jsx`.
It should toggle a `dark` class on `<body>` and persist the preference in localStorage.
Use plain React state — no external state library. Tailwind CSS is already set up.

Without context, the AI doesn't know if you're using React, Vue, plain HTML, or some other framework. It doesn't know where your header lives. It will guess and often guess wrong.

Mistake 3: The "Make It Better" Prompt

Before:

Make this code cleaner

After:

Refactor the `fetchUserData()` function in `api/users.js`.
It currently has nested callbacks — convert them to async/await.
Keep the existing error handling. Don't change the function signature.

"Clean" means something different to every developer and every AI model. Telling it to convert callbacks to async/await is a concrete, verifiable instruction it can execute correctly.

Mistake 4: The Giant Everything Prompt

Before:

Build me a full todo app with a database, user auth, and a nice UI

After (broken into steps):

Step 1:

Create a new Next.js 14 app with TypeScript and the App Router.
Set up Tailwind CSS. Create a basic layout with a header that says "Todo App"
and an empty main area. No auth yet, no database yet.

Step 2:

In `app/page.tsx`, add a todo list component. It should show a hardcoded array
of todo items (just strings), render them as `<li>` elements, and have a text input
and button to add new items using useState. No backend yet.

One giant prompt produces one giant mess. Breaking the work into steps gives you a working checkpoint after each one — so when something goes wrong, you know exactly where it broke.

Tool-Specific Tips

Different tools handle prompts slightly differently based on how they process context.

Claude Code

reads your entire project directory before responding. That means you can reference files by name and it will find them — but you still need to be specific about what you want changed.

The most powerful pattern with Claude Code is using it for multi-step agentic tasks. Give it a clear end goal plus constraints and let it work:

In this Next.js project, create a `/api/todos` route that handles GET and POST.
Use the existing Supabase client in `lib/supabase.ts`.
GET should return all todos for the authenticated user.
POST should insert a new todo and return the created row.
Follow the same error handling pattern used in `/api/users`.

Telling it to follow an existing pattern ("same error handling as /api/users") is one of the highest-leverage things you can do — it keeps your codebase consistent without you having to spell out every convention.

For a full setup walkthrough, see How to Set Up Claude Code on Mac or How to Install Claude Code on Windows.

Cursor

's chat works best when you explicitly use @ references to pin the right files into context. Don't assume it knows which file you mean.

@auth.js @middleware.ts
The middleware currently redirects all unauthenticated users to /login.
Add an exception for the /public/* route pattern so those pages are accessible
without auth. Don't change anything else in the middleware.

Cursor also has an inline edit mode (Cmd/Ctrl+K) for smaller, contained changes. Use chat for multi-file work and inline edit for single-function changes — the smaller the scope, the more reliable the result.

Learn how Cursor stacks up against Claude Code for beginners in our Cursor vs Claude Code comparison.

GitHub Copilot

Copilot works primarily through autocomplete and inline suggestions, so your "prompt" is mostly what you type in your editor. Write a detailed comment before the function you want it to generate — Copilot reads that comment as instruction.

// Fetch the current user's profile from /api/users/me
// Return null if the request fails (don't throw)
// Use the existing fetchWithAuth helper from lib/api.ts
async function getCurrentUser() {

The more specific your comment, the better Copilot's suggestion. Vague comments like // get user will get you a vague function.

Copilot's free tier includes completions in VS Code. For a full breakdown of what you get without paying, see our GitHub Copilot Free Tier Review.

Trae

Trae has a Builder mode that's designed for scaffolding entire features from a single prompt. When using Builder mode, it responds well to a short project brief followed by numbered steps:

Project: A simple task manager web app using plain HTML, CSS, and vanilla JS.
No frameworks, no build tools — just files a browser can open directly.

Step 1: Create index.html with a task input, an Add button, and an empty list.
Step 2: Wire up the JS so clicking Add appends the task to the list.
Step 3: Add a delete button on each list item that removes it.

For regular chat and inline edits, use the same context + task + constraint pattern as any other tool.

Compare and Cursor side by side in our Trae vs Cursor comparison.

Prompts for Common Beginner Scenarios

"I have an error and I don't know why"

I'm getting this error in `components/UserCard.jsx`:
TypeError: Cannot read properties of undefined (reading 'name')

The component receives a `user` prop. Here's the relevant code:
[paste the component]

Figure out why `user` might be undefined and fix it. Don't change the prop signature.

Always paste the error message and the relevant code. The AI can't read your mind or your terminal.

"I want to add a feature similar to one I already have"

I have a `<CommentForm>` component in `components/CommentForm.jsx` that handles
text input and submits to `/api/comments`. Create a similar `<ReplyForm>` component
that does the same thing but submits to `/api/comments/:id/replies`.
Follow the same structure and style as CommentForm.

Referencing an existing component is one of the best prompting techniques available. It constrains the AI to your style, your patterns, and your conventions without you having to document all of them.

"Something works but I want to understand it"

Explain what the `useEffect` in `hooks/useAuth.js` is doing step by step.
Don't change any code — just explain each line and why it's there.

This is underused. AI tools are excellent at explaining code you didn't write (or code you wrote six months ago). Asking for an explanation first before asking for a change is a good habit that prevents you from applying a fix you don't understand.

What Good Prompts Have in Common

Looking at every example above, a few patterns hold:

  • File names and function names — always specific, never vague references like "my login code"
  • Current behavior — what it does now, not just what you want
  • Desired behavior — the exact outcome, not a quality descriptor
  • What to protect — what to leave untouched, so the AI doesn't refactor things you didn't ask about
  • Tech stack — language, framework, libraries already in use

You don't have to write essays. A four-sentence prompt that covers these points will consistently outperform a one-paragraph dump of vague requirements.

One More Habit: Verify Before You Move On

AI tools produce code that looks correct. That's the trap. Make it a rule: read the diff before you accept it, run the code before you close the chat. If something changed that you didn't ask to change, that's a sign your constraint was missing.

When a result is wrong, don't start over — correct it in the same chat:

That's close but you changed the error handling in loginUser(). 
Revert that change and only apply the null check we talked about.

Treating the conversation as iterative rather than one-shot gets dramatically better results.

Which Tool Should You Start With?

If you're choosing between these tools for the first time, the prompting patterns above work with all of them — but the tools themselves have different strengths and price points.

See our full breakdown: Best Free AI Coding Tools for 2026.

From the comments

AI personas · answered by the author
promptpls

Dumb question but where do I actually find the file and function names the article keeps saying to include? I'm so new I don't even know what my files are called yet.

Sam Okafor
Sam Okafor · author

Not dumb at all. Your editor's file tree (the sidebar in VS Code, Cursor, etc.) is the list of file names, and the function name is whatever comes after `function` or `const` at the top of the block you're looking at. If you genuinely can't find where something lives, the article actually covers a fallback for that: the "Something works but I want to understand it" prompt. You can also ask the tool to locate it first, then make the change in a follow-up message.

promptpls

So I could just paste the error and let it find the file? The article's error example does that, right?

Sam Okafor
Sam Okafor · author

Right. That "I have an error and I don't know why" example pastes the error message plus the relevant code and tells the AI to figure out why and fix it. The article's point is to always include the error text and the code, since the tool can't read your terminal. Once it points you at the file, you'll know the name for next time.

cachemoney

The intro says bad prompts "waste your AI credits." Does writing these longer, more detailed prompts actually save money, or am I just paying for more tokens up front?

Sam Okafor
Sam Okafor · author

The article's framing is about wasted work, not token count. A vague prompt that produces something "almost right that silently breaks something else" costs you the follow-up rounds to fix it, plus the giant-everything prompt that produces "one giant mess." The longer prompt is a few extra words; the re-dos from a vague one are full extra exchanges. That's the waste it's pointing at.

cachemoney

Fair. So the step-by-step approach in Mistake 4 is partly a cost thing too?

Sam Okafor
Sam Okafor · author

That's a reasonable read. The article's stated reason for breaking work into steps is that you get "a working checkpoint after each one," so when something breaks you know exactly where. Catching a problem at step 2 instead of unwinding a whole app is fewer redo cycles. The article doesn't put a dollar figure on it, but yes, fewer wasted rounds is the throughline.

ships@2am

Be honest, do I really need to write a four-sentence prompt every time? Half my workflow is just firing off a one-liner and re-rolling if it's wrong.

Sam Okafor
Sam Okafor · author

The article actually makes room for your style at the end. It says don't start over when a result is wrong, correct it in the same chat, and treat the conversation as iterative rather than one-shot. So fast first shot, then refine, is endorsed. The catch it adds: "read the diff before you accept it, run the code before you close the chat." The re-roll is fine; skipping the diff read is where it bites you.

ships@2am

Reading the diff is the part I skip. What's the actual risk per the article?

Sam Okafor
Sam Okafor · author

Its words: AI tools "produce code that looks correct, that's the trap." The specific failure it calls out is the tool changing something you didn't ask it to, which it says is "a sign your constraint was missing." The article even shows the recovery prompt for exactly that: telling it you changed the error handling, revert that, and only apply the null check. So at minimum, skim the diff for changes outside what you asked for.

The StackBrief weekly

New reviews and the AI-coding-tool news worth knowing — with our take. One email a week, unsubscribe anytime.

Keep reading