{"slug": "how-to-prompt-ai-coding-tools-like-a-senior-dev-2026", "title": "How to Prompt AI Coding Tools Like a Senior Dev (2026)", "summary": "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.", "body_md": "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.\n\nThe difference isn't the tool. It's the prompt.\n\nAI 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.\n\nThe common mistakes:\n\nThe fix isn't a different AI tool. It's a different way of writing prompts.\n\nEvery effective coding prompt has three parts:\n\n```\n[CONTEXT] Given this [file/system/function],\n[CONSTRAINT] following these [conventions/rules],\n[TASK] do [specific, scoped thing].\n```\n\n**Bad prompt:**\n\n\"Add a delete button\"\n\n**Good prompt:**\n\n\"In\n\n`src/components/ProjectCard.tsx`\n\n, add a delete button that calls the`deleteProject`\n\nServer Action from`src/actions/projects.ts`\n\n. On click, show a confirmation dialog using the existing`AlertDialog`\n\nfrom shadcn/ui. After deletion, call`revalidatePath('/dashboard')`\n\n. Follow the existing error handling pattern: catch errors and show a toast with sonner, don't throw.\"\n\nSame 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.\n\nFor building new features. The most common — and the easiest to get wrong.\n\n**Template:**\n\n```\nAdd [feature] to [file/component].\nIt should [behavior description].\nUse [specific library/pattern] — not [what to avoid].\nFollow the existing pattern in [example file or function].\nThe return/export should look like: [description].\n```\n\n**Example:**\n\n```\nAdd pagination to `getUserProjects` in `src/lib/queries.ts`.\nIt should accept `{ page: number, limit: number }` and return\n`{ data, total, hasMore }`.\nUse Drizzle's `.offset()` and `.limit()` — not cursor-based pagination.\nFollow the same select pattern as `getUserById`: select specific\ncolumns, never `select *`.\nType the return with a `PaginatedResult<T>` generic.\n```\n\nFor debugging. The mistake is not giving enough context about expected vs actual behavior.\n\n**Template:**\n\n```\n[function/component] in [file] is broken.\nExpected: [what should happen]\nActual: [what is happening]\nError: [exact error message if any]\nRelevant context: [the failing code + what it calls]\n```\n\n**Example:**\n\n```\nThe `createProject` Server Action in `src/actions/projects.ts`\nreturns { error: \"Unauthorized\" } even when the user is logged in.\n\nExpected: creates the project and returns { data: project }.\nActual: always hits the requireAuth() error branch.\nError: no error message, just the unauthorized return.\n\nrequireAuth() is in `src/lib/auth.ts` — pasting it below.\nThe user is definitely authenticated (visible in Clerk dashboard).\n```\n\nFor improving existing code without breaking it. The critical constraint: **specify what must not change**.\n\n**Template:**\n\n```\nRefactor [function/file] to [improvement goal].\nKeep: [API, behavior, types that must stay identical]\nChange: [what should change]\nDon't: [specific things to avoid]\n```\n\n**Example:**\n\n```\nRefactor `UserTable.tsx` to extract the row actions into a\nseparate `UserTableActions` component.\n\nKeep: the exact same props API on UserTable, same visual output,\nsame TypeScript types.\nChange: move the action buttons and their handlers to\n`UserTableActions.tsx`.\nDon't: change how the parent passes data, don't add new dependencies.\n```\n\nFor generating tests. Be explicit about the library, what to cover, and what to mock.\n\n**Template:**\n\n```\nWrite [unit/integration] tests for [function/component] in [file].\nTesting library: [Vitest/Playwright/etc.]\nCover: [list of specific scenarios]\nMock: [external dependencies to mock and why]\nDon't test: [implementation details to avoid]\n```\n\n**Example:**\n\n```\nWrite Vitest unit tests for the `createProject` Server Action\nin `src/actions/projects.ts`.\n\nCover:\n- success case (user authorized, valid input)\n- validation failure (name exceeds 50 chars)\n- unauthorized user (requireAuth throws)\n- database error (insert fails)\n\nMock: `src/lib/db.ts` (mock insert to return a fake project),\n`src/lib/auth.ts` (mock requireAuth).\nDon't test the actual database or actual auth — only the action's logic.\n```\n\nFor understanding unfamiliar code. The mistake: asking for a general explanation.\n\n**Bad:**\n\n\"Explain this code\"\n\n**Good:**\n\n\"Explain what this Drizzle query does. Specifically: what does\n\n`.$onConflictDoUpdate`\n\ndo, and why is`target: [users.clerkId]`\n\nneeded? Give me a one-sentence summary of the overall effect on the database.\"\n\nFocused questions get focused answers. \"Explain this code\" gets a wall of text that covers things you already know.\n\nFor updating code to a new API version.\n\n**Template:**\n\n```\nMigrate [file] from [old API] to [new API].\nBreaking changes to handle: [list specific breaking changes]\nDon't change: [function signatures your app uses]\nReference: [paste the relevant migration docs]\n```\n\n**Example:**\n\n```\nMigrate `src/lib/auth.ts` from Clerk v4 to Clerk v5.\nBreaking changes: `auth()` is now async, `clerkMiddleware` replaces\n`withClerkMiddleware`, user object shape changed.\nDon't change the signatures my app uses: requireAuth() and getAuthUser().\n\nHere are the relevant Clerk v5 migration notes:\n[paste the breaking changes section from the docs]\n```\n\nThe single biggest factor in output quality is context. AI tools can only use what you give them.\n\n`/lib`\n\n\")The best context is the minimum needed to be unambiguous.\n\nTip (Claude Code):With Claude Code, you don't need to paste code into the prompt. Just reference the file path — \"in`src/actions/projects.ts`\n\n\" is enough, Claude Code reads it automatically. Save the pasting for specific snippets you want to highlight.\n\nThe problem with writing good prompts is repeating your conventions every time: \"use cuid2 for IDs, use Server Actions not API routes, return `{ data }`\n\nor `{ error }`\n\n...\"\n\nWith Claude Code, you write them once in a `CLAUDE.md`\n\nfile at the root:\n\n```\n# CLAUDE.md\n\n## Stack\n- Next.js 15 App Router, TypeScript strict mode\n- Drizzle ORM + Neon (PostgreSQL)\n- Clerk auth, Zod validation, shadcn/ui\n- Biome for linting and formatting\n\n## Conventions\n- cuid2 for all IDs, never auto-increment integers\n- Soft-delete users (deletedAt), never hard delete\n- Server Actions for mutations, not API routes\n- Import env from `@/lib/env`, never `process.env` directly\n- `requireAuth()` at the top of every protected action\n- Return `{ data }` or `{ error: string }`, never throw from actions\n- Error messages lowercase, no periods\n\n## File structure\n- Server Actions: `src/actions/[feature].ts`\n- DB queries: `src/lib/queries.ts`\n- Shared types: `src/types/[domain].ts`\n```\n\nClaude 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.\n\nThe single skill that separates developers who get great results from those who get frustrated: breaking tasks down to the right size.\n\n**Don't:**\n\n\"Build me user authentication with sign-up, login, social auth, Google OAuth, password reset, email verification, session management, and account settings page.\"\n\n**Do:**\n\n`requireAuth()`\n\nhelper in `src/lib/auth.ts`\n\n\" → done`/dashboard`\n\nroutes\" → done`(dashboard)/settings/page.tsx`\n\n\" → 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.\n\n**The rule:** if a prompt would take more than 5 minutes for a human to fully spec out, it's two prompts.\n\n**Architecture decisions:**\n\n\"Should I use microservices or a monolith?\"\n\nAI 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.\n\n**Business logic:**\n\n\"What should happen when a user cancels their subscription?\"\n\nThis is a product decision with revenue implications. Define it yourself, then implement it.\n\n**Security auditing:**\n\n\"Is this code secure?\"\n\nAI can write secure code when you ask for it. It will not spontaneously catch every vulnerability in existing code. Use dedicated tooling for audits.\n\n**Anything you won't read:**\n\nIf 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.\n\n**Before (30 seconds to write, 45 minutes to fix):**\n\n\"Add search to the projects list\"\n\n**After (90 seconds to write, works first time):**\n\n\"Add search to\n\n`src/app/(dashboard)/projects/page.tsx`\n\n. It should use a URL search param (`?q=`\n\n) so search state persists on refresh. Filter the results from`getUserProjects`\n\nwhere`name`\n\ncontains the query (case-insensitive). Use a debounced input — debounce 300ms using`useDebounce`\n\nfrom`src/hooks/useDebounce.ts`\n\n. Don't add any new dependencies.\"\n\n**Before:**\n\n\"My form isn't submitting\"\n\n**After:**\n\n\"The\n\n`CreateProjectForm`\n\nin`src/components/CreateProjectForm.tsx`\n\ndoesn't call the Server Action when submitted. React Hook Form's`handleSubmit`\n\nis wired up but the action (`createProject`\n\nfrom`src/actions/projects.ts`\n\n) never fires — confirmed with console.log at the top of the action. No browser errors. Pasting both files below.\"\n\n**Before:**\n\n\"Clean up this file\"\n\n**After:**\n\n\"The\n\n`src/lib/db.ts`\n\nfile has three inline helper functions (`withRetry`\n\n,`paginate`\n\n,`softDelete`\n\n) that are now used in 6+ places. Extract them to`src/lib/db-helpers.ts`\n\nand update all imports. Don't change the function signatures or behavior — only the location.\"\n\nThe best way to get better at prompting is to notice when you get a bad result and ask why.\n\n`CLAUDE.md`\n\nEvery bad output is feedback on the prompt. Fix the prompt, not just the output.\n\nThe 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.\n\nFull guide with CLAUDE.md templates and Claude Code workflow:\n\n[https://stacknotice.com/blog/ai-coding-prompts-senior-2026](https://stacknotice.com/blog/ai-coding-prompts-senior-2026)", "url": "https://wpnews.pro/news/how-to-prompt-ai-coding-tools-like-a-senior-dev-2026", "canonical_source": "https://dev.to/stacknotice/how-to-prompt-ai-coding-tools-like-a-senior-dev-2026-3bh9", "published_at": "2026-05-27 18:35:56+00:00", "updated_at": "2026-05-27 18:41:02.854035+00:00", "lang": "en", "topics": ["artificial-intelligence", "ai-tools", "ai-products", "generative-ai", "natural-language-processing"], "entities": ["shadcn/ui", "sonner", "Server Action", "AlertDialog"], "alternates": {"html": "https://wpnews.pro/news/how-to-prompt-ai-coding-tools-like-a-senior-dev-2026", "markdown": "https://wpnews.pro/news/how-to-prompt-ai-coding-tools-like-a-senior-dev-2026.md", "text": "https://wpnews.pro/news/how-to-prompt-ai-coding-tools-like-a-senior-dev-2026.txt", "jsonld": "https://wpnews.pro/news/how-to-prompt-ai-coding-tools-like-a-senior-dev-2026.jsonld"}}