What the file is and how Copilot uses it

If you place a file at .github/copilot-instructions.md in your repository, GitHub Copilot includes its contents as persistent context in every chat message and inline completion request made within that workspace. It's the equivalent of a standing briefing you give Copilot at the start of every session — without having to re-explain your project every time.

The file is Markdown. Copilot reads the whole thing. There's no special syntax required — plain prose and lists work fine. The contents are appended to the system prompt before each interaction, so they influence completions, chat responses, and agent-mode tasks equally.

Where it lives: .github/copilot-instructions.md in the root of your repository. The .github/ folder is already conventional for CI, dependabot, and issue templates — this fits right in. Commit it to the repo so every team member's Copilot uses the same instructions.

Without this file, Copilot infers project context from whatever files are open and the current cursor position. That works for simple completions. But for anything structural — naming conventions, architecture decisions, things you don't do — it guesses. The instructions file replaces guessing with explicit rules.

What to put in it

Think of it as onboarding documentation for a new developer — except the audience has no patience and perfect recall. Be direct, specific, and actionable. Avoid prose that explains history; just state the current rules.

The categories that produce the most noticeable improvement:

1. Tech stack and versions

State exactly what you're using, including version constraints that affect API choices:

## Tech stack

- SvelteKit 2 with TypeScript strict mode
- Vite 5 as the build tool
- SCSS modules for component styles (no CSS-in-JS)
- Vitest for unit tests
- Node 20 — use native fetch, not node-fetch

Do not suggest React, Vue, or any framework other than SvelteKit.
Do not add new npm dependencies without noting them explicitly.

The last two lines matter. Without them, Copilot will occasionally suggest React patterns, import hooks that don't exist in Svelte, or reach for a library when the standard library does the job.

2. Naming and file structure conventions

Copilot can match your naming convention accurately if you tell it what it is — but it won't infer it from a handful of existing files reliably:

## Naming conventions

- Components: PascalCase, e.g. `ProductCard.svelte`
- Utility functions: camelCase, e.g. `formatPrice.ts`
- SCSS files: kebab-case, co-located with component, e.g. `product-card.scss`
- Stores: `[name].store.ts`, exported as `[name]Store`
- Types: `[name].types.ts`, all interfaces prefixed with `I` only for
  external API contracts — not for internal types

3. Code style rules Copilot consistently gets wrong

Every codebase has a few rules that tools don't naturally follow. List yours explicitly:

## Code style

- Prefer `const` over `let` unless reassignment is needed
- No `any` types — use `unknown` and narrow
- Error handling: always handle the error case explicitly; do not swallow errors
- Async: prefer async/await over .then() chains
- No default exports from utility files — named exports only
- CSS class names follow BEM: `.block__element--modifier`

4. Architecture decisions and off-limits patterns

This is where the file earns its value most. Tell Copilot what you've deliberately decided not to do:

## Architecture

- State management: Svelte stores only — no Zustand, Redux, or Pinia
- Data fetching: SvelteKit load functions for SSR, fetch in actions for mutations
- Do not use localStorage directly — use the `storage` utility in `$lib/utils/storage.ts`
- Authentication is handled by the `auth` store — do not write auth logic inline
- All API calls go through `$lib/api/` — do not call fetch() directly in components

These rules prevent Copilot from suggesting technically correct code that violates the architecture you've already established. Without them, it reinvents patterns you've already solved.

5. Testing conventions

## Testing

- Unit tests: Vitest, co-located with the file as `[name].test.ts`
- Test descriptions: plain English, describe the behaviour not the implementation
- Mock external modules with `vi.mock()`, not manual stub objects
- No snapshot tests — assert on specific values

6. What not to generate

A short explicit "don'ts" section saves a surprising amount of correction time:

## Do not

- Add JSDoc comments to simple, self-explanatory functions
- Generate `console.log` statements in production code
- Use `!` non-null assertions — narrow the type properly
- Suggest class components — this project uses functional patterns only
- Add `@ts-ignore` or `@ts-expect-error` without a comment explaining why

A complete real-world example

Here's what the instructions file for a Shopify theme project looks like in practice:

# Copilot Instructions — Shopify Theme Project

## Stack
- Shopify theme, Online Store 2.0 architecture
- Liquid for all server-rendered templates and sections
- Vanilla JavaScript ES6+ (no framework, no bundler)
- SCSS compiled via Shopify CLI, BEM methodology
- Shopify CLI for local development

## Conventions
- Sections live in `sections/`, snippets in `snippets/`
- Each section has a paired `_[section-name].scss` in `assets/`
- Section schema settings use snake_case IDs
- JS class names follow BEM: `.section-hero__button--primary`
- All cart interactions use the Shopify Ajax Cart API — no page reloads

## Architecture rules
- Do not use `checkout.liquid` — all checkout customisation is done
  via Checkout UI Extensions
- Metafields use the `custom` namespace for merchant-managed content
- Images always use `image_url` + `image_tag` filters with explicit `width`
  and `loading: 'lazy'`
- Translations: all user-facing strings go through the `t` filter with keys
  in `locales/en.default.json` — no hardcoded English in Liquid

## Do not
- Suggest jQuery — this project uses vanilla JS only
- Use `document.write()` or synchronous DOM blocking patterns
- Add third-party CDN script tags — all assets go through Shopify's asset pipeline
- Generate inline styles — use CSS custom properties and SCSS classes

Notice the format: short, specific, imperative. No history, no explanation of why the pattern was chosen. Copilot follows directives, not reasoning. Save the reasoning for your actual team documentation.

What changes after you add the file

The improvement isn't dramatic on simple completions — single-line suggestions were already reasonable. The difference shows up on:

  • Multi-line generations — new functions, components, and test files match your patterns instead of a generic interpretation
  • Chat responses — when you ask Copilot to refactor something or explain an approach, it reasons within your stack instead of generic JavaScript or React examples
  • Agent mode tasks — scaffolding new files, adding features, writing tests all come out closer to production-ready and closer to your conventions
  • Consistency across sessions — you stop re-explaining the same constraints every time you open a new chat

The biggest practical gain: fewer corrections. Even saving two or three rounds of "no, not like that, we do it this way" per task adds up quickly across a week of development.

Keeping the file useful over time

An instructions file goes stale if you don't maintain it. A few practices that help:

  • Update it when you make architectural decisions. If you switch from direct fetch calls to a centralised API layer, add that rule. If you adopt a new naming convention, update the file before the inconsistency spreads.
  • Trim rules that are no longer relevant. A file full of obsolete rules is noise that dilutes the signal from the rules that matter.
  • Add a rule every time you correct the same Copilot mistake twice. If it generates code that violates a pattern you care about, the pattern belongs in the file.
  • Keep it under 150 lines. Beyond that, Copilot starts treating it as background context rather than active instructions. Prioritise ruthlessly.

Treat it like an onboarding doc for a contractor. If a new developer read only this file, would they know enough to write code that fits the project? If yes, it's good. If not, add what's missing. If it's longer than one screen, cut the least important third.

Beyond the instructions file

The copilot-instructions.md sets persistent, project-wide context. For more granular control:

  • `.github/instructions/*.instructions.md` with applyTo glob patterns — scoped instructions that apply only to specific file types or folders (e.g., different rules for sections/ vs assets/ in a Shopify theme)
  • Inline comments before complex blocks — for task-specific one-off context that doesn't belong in a global file
  • Prompt files (.github/prompts/*.prompt.md) — reusable prompt templates for recurring tasks like "write a test for this function" or "review this section schema"

The instructions file handles the 80% of context that applies everywhere. The other mechanisms handle the 20% that's file-type or task-specific. Used together, they turn Copilot from a smart autocomplete into something much closer to a developer who's been on the project for months.