Skip to content

The Anatomy of a Good Coding Prompt

Structure your prompts for AI coding tools to get better, more predictable results.

12 min readai-tools, prompt-engineering, best-practices

The difference between an AI-generated app that works and one that's a mess often comes down to one thing: the prompt. Not the AI model. Not the tool. The prompt.

A well-structured prompt gets you 80% of the way to what you want on the first try. A vague prompt gets you 30% of the way, and you spend the next hour in a frustrating back-and-forth trying to get the other 70%.

This lesson breaks down what makes a coding prompt good, gives you a repeatable structure, and shows you real examples that work.

Why Prompts Matter More Than You Think

When you talk to another person, they fill in gaps. If you say "make me a website," a human designer asks clarifying questions: "What kind? For whom? What content? What style?"

AI doesn't ask those questions (usually). It fills in the gaps with assumptions. And its assumptions are often generic. "Make me a website" produces a generic website. "Make me a generic website" is probably not what you wanted.

The quality of your prompt is the quality of your first result. And the quality of your first result determines how many rounds of revision you need. Fewer rounds means faster building.

The Five Elements of a Good Coding Prompt

Every effective coding prompt contains some combination of these five elements:

1. Context — What Are We Working With?

Tell the AI about the project, the technology stack, and where this work fits in the bigger picture.

Without context:

Add a search feature

With context:

This is a Next.js e-commerce app using Supabase for the database.
The products table has columns: id, name, description, price, category, and image_url.
Add a search feature to the products page.

Context prevents the AI from making wrong assumptions about your technology, data structure, or architecture.

2. Specifics — What Exactly Do You Want?

The more precise you are about the desired outcome, the closer the first attempt will be to what you want.

Vague:

Make the search work well

Specific:

The search should:
- Filter products by name and description (case-insensitive)
- Update results as the user types (debounced, 300ms delay)
- Show "No results found" when nothing matches
- Display the number of matching results
- Clear the search with an X button in the input field

Each bullet point eliminates a decision the AI would otherwise make on its own. Some of those AI decisions would be fine. Others would produce something you don't want.

3. Constraints — What Should the AI NOT Do?

Telling the AI what to avoid is just as important as telling it what to build. Without constraints, AI tends to over-engineer.

Common constraints:

Constraints:
- Don't install any new dependencies
- Keep all search logic client-side (no new API routes)
- Don't modify the existing product card component
- Use the existing Tailwind classes — don't add custom CSS

Constraints are especially important with tools like Cursor's Composer or Claude Code, which can modify multiple files. Without boundaries, the AI might "improve" parts of your project you didn't ask it to touch.

4. Examples — Show, Don't Just Tell

When you can, show the AI what you want. Examples are more precise than descriptions.

Description only:

Format the price nicely

With examples:

Format prices like these examples:
- 1234.5 should display as "$1,234.50"
- 0.99 should display as "$0.99"
- 1000000 should display as "$1,000,000.00"

Examples work especially well for formatting, data transformations, and UI behavior. They remove ambiguity that words alone can't eliminate.

5. Output Format — How Should the Result Be Structured?

Tell the AI how to organize its output. This is particularly important for larger generations.

Create the search feature as:
- A new SearchBar component in src/components/SearchBar.tsx
- A useProductSearch custom hook in src/hooks/useProductSearch.ts
- Update the existing ProductList component to use the search hook

Specifying the file structure, component organization, or code style prevents the AI from dumping everything into one massive file or splitting things in ways that don't match your project's conventions.

Putting It All Together

Here's a complete prompt using all five elements:

Context:
I'm building a recipe sharing app with Next.js 16 (App Router), TypeScript,
Tailwind CSS, and Supabase. The recipes table has: id, title, description,
ingredients (text array), instructions (text array), cook_time_minutes,
difficulty (easy/medium/hard), and author_id.
 
Task:
Add a recipe filtering sidebar to the browse page.
 
Specifics:
- Filter by difficulty (checkboxes for easy, medium, hard)
- Filter by max cook time (slider from 0-120 minutes, in 15-minute increments)
- Filter by ingredient (text input that matches against the ingredients array)
- Filters should combine (AND logic)
- Show active filter count on each section header
- Include a "Clear All Filters" button
 
Constraints:
- Client-side filtering only (all recipes are already loaded)
- Don't modify the RecipeCard component
- Don't add any new npm dependencies
- Keep the sidebar responsive — it should collapse to a horizontal filter bar on mobile
 
Output:
- New FilterSidebar component in src/components/FilterSidebar.tsx
- New useRecipeFilters hook in src/hooks/useRecipeFilters.ts
- Update src/app/browse/page.tsx to integrate the filter sidebar

This prompt is detailed enough that the AI's first attempt will be very close to what you want. Maybe you'll adjust the slider range or tweak the mobile layout, but the core functionality will be right.

The Quick Prompt vs. The Detailed Prompt

You don't need a five-element prompt for everything. Here's a guide:

| Situation | Prompt Detail Needed | |-----------|---------------------| | Fixing a typo | Minimal — "Change 'recieve' to 'receive' in the header" | | Adding a simple button | Low — "Add a 'Back to Home' button below the form" | | Building a new feature | High — Use the full five-element structure | | Generating a complete page | High — Describe layout, content, behavior | | Refactoring existing code | Medium — Describe what to change and what to preserve | | Debugging an error | Medium — Include the error message and what you expected |

For small changes, a one-liner is fine. For anything that involves multiple decisions, invest the time in a detailed prompt.

Common Prompt Patterns

The "Build This" Pattern

Build [component/feature] that does [core function].
It should [specific behavior 1], [specific behavior 2], and [specific behavior 3].
Use [technology/style preferences].
Don't [constraint 1] or [constraint 2].

The "Fix This" Pattern

I'm getting this error: [paste the error]
It happens when [describe the trigger].
The relevant code is [paste or reference the code].
I expected [what should happen instead].

The "Modify This" Pattern

In [file/component], change [current behavior] to [desired behavior].
Keep [what should stay the same].
The reason for this change is [context for why].

The "Explain Then Build" Pattern

I want to add [feature]. Before building it:
1. Explain what approach you'd take and why
2. List any new files or changes to existing files
3. Wait for my approval before making changes

This last pattern is powerful because it gives you a chance to course-correct before the AI generates a lot of code.

Real Examples: Good vs. Bad

Bad: Too Vague

Add authentication to my app

This could mean a hundred different things. What auth provider? What pages need protection? What should happen when someone isn't logged in?

Good: Specific and Constrained

Add Clerk authentication to this Next.js app.
- Protect all routes under /dashboard (redirect to /sign-in if not authenticated)
- Add a sign-in page at /sign-in using Clerk's pre-built components
- Add a user button in the top-right of the navigation bar (show on all pages)
- After sign-in, redirect to /dashboard
- Don't modify any existing page content, only add the auth wrapper and navigation change

Bad: Over-Specified

Create a button component. It should be a React functional component that accepts
props of type ButtonProps which extends React.ButtonHTMLAttributes<HTMLButtonElement>.
The component should use forwardRef. It should have variants: default, destructive,
outline, secondary, ghost, and link. Each variant should use the following exact
Tailwind classes: default: "bg-primary text-primary-foreground hover:bg-primary/90"...

This is too much. You're doing the AI's job for it. If you know exactly what classes to use, you might as well write the component yourself.

Good: Clear Intent with Room for AI Expertise

Create a reusable Button component with these variants: primary, secondary,
outline, danger, and ghost. Each should be visually distinct. Support three
sizes: small, medium, large. Include a loading state that shows a spinner
and disables the button. Use Tailwind CSS for styling.

This tells the AI what you want without micromanaging how. The AI can apply its training on thousands of button components to produce a good result.

Try this now

Take the last feature prompt you gave an AI tool and rewrite it using the five elements from this lesson:

  1. Context
  2. Task
  3. Specifics
  4. Constraints
  5. Output

If you cannot fill in one of those sections clearly, that is usually the missing piece that causes the agent to guess.

Prompt to give your agent

Use this with Cursor or Claude Code before you ask for implementation work: "Help me tighten this coding prompt before any files are changed. Project context: [stack, app purpose, relevant data model] Goal: [the feature or fix I want] Rough prompt: [paste your current prompt]

Rewrite it using these sections:

  1. Context
  2. Task
  3. Specifics
  4. Constraints
  5. Output

Keep the scope limited to one reviewable change. Tell me which assumptions are still missing. Tell me what I must verify manually before I let an agent write code."

What you must review yourself

  • Whether the prompt is asking for one bounded change or three unrelated ones
  • Whether the constraints actually match your real repo rules
  • Whether the requested file changes make architectural sense
  • Whether the output asks the agent to stop before risky changes like auth, billing, schema, or infra edits

Common mistakes to avoid

  • Starting with the feature name instead of the project context. "Add search" is rarely enough.
  • Combining design, debugging, and refactoring in one prompt. Separate those jobs.
  • Leaving non-goals unstated. If the agent must not add dependencies, move files, or rewrite UI, say so.
  • Skipping the output format. If you do not ask for a plan, file list, or approval gate, the agent will often jump straight to code.

Key takeaways

  • Good prompts reduce agent guesswork by making key decisions explicit
  • Constraints are not optional; they are part of the task
  • Match prompt detail to task size instead of writing every prompt the same way
  • A strong prompt tells the agent what to do, what not to do, and what to show you before it acts

What's Next

Next up: System Prompts — .cursorrules and CLAUDE.md Explained. A strong task prompt helps in the moment. A strong system prompt keeps the same rules in place every time your agent starts working.