How to configure repository-level custom instructions for GitHub Copilot
Explains how to use the .github/copilot-instructions.md file to enforce coding standards and framework-specific patterns across an entire development team. Compares this repository-level configuration to individual user settings.

How to configure repository-level custom instructions for GitHub Copilot
A .github/copilot-instructions.md file is a plain Markdown document, committed to your repository, that GitHub Copilot reads automatically on every chat request, suggestion, and code review tied to that repo. It applies to everyone with access regardless of their personal settings, which makes it the right mechanism for enforcing team-wide coding standards instead of hoping each developer configures their own Copilot preferences correctly.
I started using this file on a mixed PHP and React codebase after getting tired of leaving the same three PR comments every week: wrong brace style, a useEffect missing a dependency array, raw console.error calls in route handlers. The file fixed roughly two of those three problems within a day of adding it. The third took some trial and error, which is its own lesson about what this feature can and can't do.
What actually reads this file, and when
Copilot picks up .github/copilot-instructions.md for chat in the IDE, for Copilot's PR code review feature, and for the coding agent, whenever the request happens in the context of that repository. GitHub documents this as one of three supported instruction types, alongside path-specific instruction files scoped to particular directories or file patterns, and instructions tied to specific features like code review, as described in GitHub's documentation on adding custom instructions.
The repository-wide file is the blunt instrument of the three. It applies everywhere in the repo, every request, no scoping. That's exactly right for rules that should be universal (PSR-12, no raw error throwing, no new state libraries) and exactly wrong for rules that only make sense in one subdirectory. If your backend is PHP and your frontend is React, cramming both rule sets into one file works, but it also means every PHP-only request is paying token cost to load React rules it will never use, and vice versa. Path-specific instruction files solve that, at the cost of one more file to maintain.
Setting it up
There's no schema or frontmatter to learn for the repository-wide version. The steps are mechanical:
- Create a .github directory at the repo root if it doesn't already exist.
- Add copilot-instructions.md inside it.
- Write instructions in plain Markdown: headings, bullet points, whatever a human reviewer would find easy to scan.
- Commit and open a PR like you would for any other file.
That last point matters more than it sounds. Because the file lives in version control, you get blame history, review comments, and rollback for free. If a rule turns out to be wrong or outdated, you revert it the same way you'd revert a bad config change, not by tracking down who set a personal preference somewhere.
Three rule sets worth copying directly
PHP: enforcing PSR-12 and strict types
1## PHP coding standards23- Follow PSR-12: 4-space indentation, opening braces for classes and4 methods on their own line, one statement per line.5- Every file starts with `declare(strict_types=1);` immediately after6 the opening `<?php` tag.7- Type-hint all parameters and return types. Avoid `mixed` unless8 there's no reasonable alternative.9- camelCase for methods and variables, PascalCase for classes.10- Use constructor property promotion (PHP 8.1+) for simple value objects.PSR-12 is a named, well-documented standard, so Copilot has a lot to anchor to. Naming it explicitly beats a vague "follow best practices" instruction almost every time, because "best practices" is underspecified and the model will default to whatever's statistically common in public code, which is not necessarily what your team does.
React: locking down hooks behavior
1## React conventions23- Functional components only, no class components.4- Hooks must never be called conditionally, in loops, or from plain5 functions. Follow the Rules of Hooks strictly.6- Every useEffect needs a complete dependency array. If a dependency7 is intentionally left out, add a comment explaining why instead of8 disabling the lint rule.9- Custom hooks are prefixed with `use` and return a single value or a10 plain object, not an array, unless mirroring a built-in hook's tuple11 shape.12- No new state management libraries. We use React Context plus13 useReducer for shared state. Redux and Zustand are not approved14 for this repo.The last bullet is the one that does the most work. Telling Copilot what's off-limits, specific libraries and specific patterns, stops it from reaching for whatever pattern dominates its training data when your team has deliberately standardized on something narrower. Without that line, I've watched Copilot suggest pulling in Zustand for a component that just needed useReducer, which is technically reasonable advice and completely wrong for that codebase.
Node/Express: naming your actual error classes
1## Error handling23- Never throw raw strings or plain Error objects from route handlers.4 Use the custom AppError class in src/errors/AppError.js, which takes5 a status code and a message.6- Wrap all async route handlers in the asyncHandler utility from7 src/middleware/asyncHandler.js so rejected promises reach the global8 error middleware.9- Log through the shared logger in src/lib/logger.js. No console.log10 or console.error in application code.11- Catch database errors and translate them into an AppError before12 they reach the client. Never leak raw ORM stack traces in responses.This category saves the most review time in my experience. Generic Node suggestions default to bare try/catch with console.error, because that's the median pattern in public repos. Naming your actual internal class and file paths gives Copilot something concrete instead of a generic fallback, and it tends to actually import the right module rather than just describing the pattern in a comment.
How does this compare to personal Copilot settings?
Copilot also supports personal custom instructions, usually set per-user through your IDE, which apply across every repository you touch regardless of which project you're in. VS Code documents how these personal and workspace-level instruction sources interact in its Copilot customization guide, and the two systems are additive, not exclusive. Copilot can draw on both at once.
The practical difference is scope and visibility. Personal instructions are about you: maybe you want terse answers, or you always want TypeScript over JavaScript in ambiguous scaffolding. That's genuinely useful, but it's invisible to teammates and not enforced on anyone but you. Repository instructions are about the project: visible to everyone with access, reviewed in PRs, versioned alongside the code. A developer who joined yesterday and hasn't touched their personal Copilot settings still gets the PSR-12 rules and the error handling conventions, because those live in the repo, not in anyone's profile.
In practice, when a personal preference and a repository instruction conflict on an in-context request, the repository instruction tends to win out, which matches the way GitHub frames repo-level instructions as giving Copilot direct project context for building, testing, and validating changes, per GitHub's best practices guidance for using Copilot. Don't rely on personal settings to patch gaps in your team's standards. They don't reach anyone else.
What happens if the instructions file gets too long?
This is the part that bites people. Copilot doesn't have unlimited room to read your instructions and your actual code and the conversation history all at once, everything competes for the same context budget on a given request. GitHub doesn't publish an exact token ceiling for the repository instructions file, but in practice, once a file grows past a few hundred words of dense prose, you start noticing the cost: Copilot gives suggestions that seem to ignore obviously relevant surrounding code, not because it's disregarding your rules, but because there wasn't enough context budget left to load the file you're actually editing after your instructions ate into it.
I saw this directly on a project where someone (not me, allegedly) added a full internal style guide, several thousand words, including a changelog of why we migrated off Redux in 2023. Copilot Chat got noticeably worse at referencing actual files in the repo during that stretch. Trimming the file back down to about 40 lines of imperative bullets fixed it within the same day, no other changes.
The fix is straightforward: write short, unambiguous rules, not paragraphs of justification. Skip the "why" unless the why changes the rule's application. If React conventions and PHP standards never share a request context, split them into separate path-specific instruction files rather than keeping one giant document. A tight file of 30 to 50 lines will consistently outperform a 400-line one, both because it costs fewer tokens and because specific, narrow instructions are just easier for the model to apply consistently than a wall of guidance.
Rolling it out without overbuilding it
Don't write a comprehensive style guide on day one. Pick the two or three rules causing the most repeated friction in code review right now, the ones generating the same PR comment every week, and put only those in the file first. Commit it, watch Copilot's output over the next few days of real work, and add to the file only when you notice a genuine new gap, not preemptively.
A few other things worth checking before you assume the file is working:
- Confirm that Copilot code review has its own setting for respecting custom instructions, separate from chat and inline completions. If your reviews still read generically after adding the file, that toggle is the first thing to check rather than assuming the file itself is broken.
- If you maintain several repos with different stacks, expect to maintain several lightweight instruction files rather than one master document that tries to cover everything. That's the right instinct, not a sign you've organized something wrong.
- Revisit the file every few months the way you'd revisit a linter config. Rules that made sense six months ago sometimes stop matching how the team actually writes code, and a stale instruction is worse than no instruction because it actively fights the patterns already in your codebase.
Treat the file like a linter config you can write in prose: narrow, enforced, versioned, and worth less the longer and vaguer it gets.
Related Articles

How to manage AI context windows in large monorepos
Strategies for preventing AI coding assistants from getting confused by massive monorepos. Covers workspace configuration, targeted indexing, and scoping queries.

How to configure .cursorignore to prevent context pollution and protect secrets
Cursor indexes your working directory, not just what Git tracks, so an untracked .env file can still leak straight into a prompt. Here's how to lock that down properly.

How to manage API costs when using Claude Sonnet for automated coding
Explains how to utilize Anthropic's Prompt Caching to reduce API bills when using tools like Cline or Continue.dev. Details the mechanics of context window reloading and how to structure files to maximize cache hits.