cd /news/artificial-intelligence/how-to-prompt-ai-coding-tools-like-a… · home topics artificial-intelligence article
[ARTICLE · art-15624] src=dev.to pub= topic=artificial-intelligence verified=true sentiment=· neutral

How to Prompt AI Coding Tools Like a Senior Dev (2026)

A developer has outlined a structured prompting strategy for AI coding tools that can produce production-ready code in seconds rather than broken outputs requiring hours of cleanup. The approach breaks prompts into three components—context, constraints, and task—with specific templates for building new features, debugging, refactoring, and generating tests. By providing precise file paths, expected behaviors, and patterns to follow or avoid, developers can consistently get working code from AI tools instead of ambiguous assumptions.

read7 min publishedMay 27, 2026

Two developers use the same AI tool. One gets working code in 30 seconds. The other gets a broken mess and spends an hour fixing it.

The difference isn't the tool. It's the prompt.

AI coding tools are pattern matchers with enormous context windows. Feed them a clear pattern and they complete it brilliantly. Feed them ambiguity and they invent assumptions — usually wrong ones.

The common mistakes:

The fix isn't a different AI tool. It's a different way of writing prompts.

Every effective coding prompt has three parts:

[CONTEXT] Given this [file/system/function],
[CONSTRAINT] following these [conventions/rules],
[TASK] do [specific, scoped thing].

Bad prompt:

"Add a delete button"

Good prompt:

"In

src/components/ProjectCard.tsx

, add a delete button that calls thedeleteProject

Server Action fromsrc/actions/projects.ts

. On click, show a confirmation dialog using the existingAlertDialog

from shadcn/ui. After deletion, callrevalidatePath('/dashboard')

. Follow the existing error handling pattern: catch errors and show a toast with sonner, don't throw."

Same request. The second one takes 40 extra seconds to write. The output is production-ready instead of a starting point that needs an hour of cleanup.

For building new features. The most common — and the easiest to get wrong.

Template:

Add [feature] to [file/component].
It should [behavior description].
Use [specific library/pattern] — not [what to avoid].
Follow the existing pattern in [example file or function].
The return/export should look like: [description].

Example:

Add pagination to `getUserProjects` in `src/lib/queries.ts`.
It should accept `{ page: number, limit: number }` and return
`{ data, total, hasMore }`.
Use Drizzle's `.offset()` and `.limit()` — not cursor-based pagination.
Follow the same select pattern as `getUserById`: select specific
columns, never `select *`.
Type the return with a `PaginatedResult<T>` generic.

For debugging. The mistake is not giving enough context about expected vs actual behavior.

Template:

[function/component] in [file] is broken.
Expected: [what should happen]
Actual: [what is happening]
Error: [exact error message if any]
Relevant context: [the failing code + what it calls]

Example:

The `createProject` Server Action in `src/actions/projects.ts`
returns { error: "Unauthorized" } even when the user is logged in.

Expected: creates the project and returns { data: project }.
Actual: always hits the requireAuth() error branch.
Error: no error message, just the unauthorized return.

requireAuth() is in `src/lib/auth.ts` — pasting it below.
The user is definitely authenticated (visible in Clerk dashboard).

For improving existing code without breaking it. The critical constraint: specify what must not change.

Template:

Refactor [function/file] to [improvement goal].
Keep: [API, behavior, types that must stay identical]
Change: [what should change]
Don't: [specific things to avoid]

Example:

Refactor `UserTable.tsx` to extract the row actions into a
separate `UserTableActions` component.

Keep: the exact same props API on UserTable, same visual output,
same TypeScript types.
Change: move the action buttons and their handlers to
`UserTableActions.tsx`.
Don't: change how the parent passes data, don't add new dependencies.

For generating tests. Be explicit about the library, what to cover, and what to mock.

Template:

Write [unit/integration] tests for [function/component] in [file].
Testing library: [Vitest/Playwright/etc.]
Cover: [list of specific scenarios]
Mock: [external dependencies to mock and why]
Don't test: [implementation details to avoid]

Example:

Write Vitest unit tests for the `createProject` Server Action
in `src/actions/projects.ts`.

Cover:
- success case (user authorized, valid input)
- validation failure (name exceeds 50 chars)
- unauthorized user (requireAuth throws)
- database error (insert fails)

Mock: `src/lib/db.ts` (mock insert to return a fake project),
`src/lib/auth.ts` (mock requireAuth).
Don't test the actual database or actual auth — only the action's logic.

For understanding unfamiliar code. The mistake: asking for a general explanation.

Bad:

"Explain this code"

Good:

"Explain what this Drizzle query does. Specifically: what does

.$onConflictDoUpdate

do, and why istarget: [users.clerkId]

needed? Give me a one-sentence summary of the overall effect on the database."

Focused questions get focused answers. "Explain this code" gets a wall of text that covers things you already know.

For updating code to a new API version.

Template:

Migrate [file] from [old API] to [new API].
Breaking changes to handle: [list specific breaking changes]
Don't change: [function signatures your app uses]
Reference: [paste the relevant migration docs]

Example:

Migrate `src/lib/auth.ts` from Clerk v4 to Clerk v5.
Breaking changes: `auth()` is now async, `clerkMiddleware` replaces
`withClerkMiddleware`, user object shape changed.
Don't change the signatures my app uses: requireAuth() and getAuthUser().

Here are the relevant Clerk v5 migration notes:
[paste the breaking changes section from the docs]

The single biggest factor in output quality is context. AI tools can only use what you give them.

/lib

")The best context is the minimum needed to be unambiguous.

Tip (Claude Code):With Claude Code, you don't need to paste code into the prompt. Just reference the file path — "insrc/actions/projects.ts

" is enough, Claude Code reads it automatically. Save the pasting for specific snippets you want to highlight.

The problem with writing good prompts is repeating your conventions every time: "use cuid2 for IDs, use Server Actions not API routes, return { data }

or { error }

..."

With Claude Code, you write them once in a CLAUDE.md

file at the root:


## Stack
- Next.js 15 App Router, TypeScript strict mode
- Drizzle ORM + Neon (PostgreSQL)
- Clerk auth, Zod validation, shadcn/ui
- Biome for linting and formatting

## Conventions
- cuid2 for all IDs, never auto-increment integers
- Soft-delete users (deletedAt), never hard delete
- Server Actions for mutations, not API routes
- Import env from `@/lib/env`, never `process.env` directly
- `requireAuth()` at the top of every protected action
- Return `{ data }` or `{ error: string }`, never throw from actions
- Error messages lowercase, no periods

## File structure
- Server Actions: `src/actions/[feature].ts`
- DB queries: `src/lib/queries.ts`
- Shared types: `src/types/[domain].ts`

Claude Code reads this at startup and applies these rules to every prompt automatically. You never have to say "use cuid2" again — it just does it.

The single skill that separates developers who get great results from those who get frustrated: breaking tasks down to the right size.

Don't:

"Build me user authentication with sign-up, login, social auth, Google OAuth, password reset, email verification, session management, and account settings page."

Do:

requireAuth()

helper in src/lib/auth.ts

" → done/dashboard

routes" → done(dashboard)/settings/page.tsx

" → doneEach step is a 30-second prompt with a clear, verifiable output. The combined result is identical to the big request — but with zero hallucinated architecture, and you understand every line.

The rule: if a prompt would take more than 5 minutes for a human to fully spec out, it's two prompts.

Architecture decisions:

"Should I use microservices or a monolith?"

AI will give you a reasonable-sounding answer based on generic patterns. It doesn't know your team size, your traffic, your runway. Decide this yourself first, then ask AI to implement your decision.

Business logic:

"What should happen when a user cancels their subscription?"

This is a product decision with revenue implications. Define it yourself, then implement it.

Security auditing:

"Is this code secure?"

AI can write secure code when you ask for it. It will not spontaneously catch every vulnerability in existing code. Use dedicated tooling for audits.

Anything you won't read:

If you're going to copy AI output without reading it, stop. You're shipping code you don't understand. When it breaks — and it will — you won't know where to look.

Before (30 seconds to write, 45 minutes to fix):

"Add search to the projects list"

After (90 seconds to write, works first time):

"Add search to

src/app/(dashboard)/projects/page.tsx

. It should use a URL search param (?q=

) so search state persists on refresh. Filter the results fromgetUserProjects

wherename

contains the query (case-insensitive). Use a debounced input — debounce 300ms usinguseDebounce

fromsrc/hooks/useDebounce.ts

. Don't add any new dependencies."

Before:

"My form isn't submitting"

After:

"The

CreateProjectForm

insrc/components/CreateProjectForm.tsx

doesn't call the Server Action when submitted. React Hook Form'shandleSubmit

is wired up but the action (createProject

fromsrc/actions/projects.ts

) never fires — confirmed with console.log at the top of the action. No browser errors. Pasting both files below."

Before:

"Clean up this file"

After:

"The

src/lib/db.ts

file has three inline helper functions (withRetry

,paginate

,softDelete

) that are now used in 6+ places. Extract them tosrc/lib/db-helpers.ts

and update all imports. Don't change the function signatures or behavior — only the location."

The best way to get better at prompting is to notice when you get a bad result and ask why.

CLAUDE.md

Every bad output is feedback on the prompt. Fix the prompt, not just the output.

The developers getting 10x from AI tools aren't using a different tier or a different model. They're spending 60 extra seconds writing a better prompt. That's the entire edge — and it compounds every single day.

Full guide with CLAUDE.md templates and Claude Code workflow:

https://stacknotice.com/blog/ai-coding-prompts-senior-2026

── more in #artificial-intelligence 4 stories · sorted by recency
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/how-to-prompt-ai-cod…] indexed:0 read:7min 2026-05-27 ·