Project Setup and Repository Instructions
Introduction
Before Copilot can act like a disciplined member of your team, it needs to know what "good" looks like in this repository. Left on its own, Copilot only has your prompt and whatever files happen to be open — it has no idea that controllers should stay thin, that every service method validates its inputs, or that frontend components must go through a single API client.
GitHub Copilot solves this with custom instructions: Markdown files that are automatically added to the context of every chat request, without you having to repeat yourself in every prompt.
There are two levels:
- Repository instructions — a single
.github/copilot-instructions.mdfile that applies to every Copilot Chat request in the repo. - Path-specific instructions — one or more
.github/instructions/*.instructions.mdfiles, each scoped to matching files via anapplyToglob, so backend-only or frontend-only rules don't leak into the wrong context.
GitHub Copilot tip: Once your instructions file exists, ask Copilot Chat "What repository instructions are currently active?" — Copilot will echo back what it's been told, which is a quick way to confirm the file is actually being picked up.
Concepts
Repository-wide instructions
- Location:
.github/copilot-instructions.md(the path is fixed — Copilot looks for it by convention). - Applies to every chat request in the repository, including inline chat and agent mode.
- Best used for things that are true everywhere: repo layout, build/test commands, and cross-cutting standards ("every new behaviour needs a test").
Path-specific instructions
- Location:
.github/instructions/<name>.instructions.md. - Frontmatter declares an
applyToglob, e.g.applyTo: "backend/**/*.java". - Only added to context when a file matching the glob is open or referenced — this keeps backend rules (constructor injection,
IllegalArgumentException) out of the way when you're only editing React components, and vice versa.
What makes a good instructions file
- Concrete and specific to this codebase, not generic best-practice advice.
- Short enough to read in one sitting — a wall of text is as unhelpful to Copilot as it is to a new hire.
- States what "done" means, so Copilot knows when to stop.
Examples
.github/copilot-instructions.md:
# Account Dashboard — Repository Instructions
Full-stack account dashboard: Spring Boot backend (`backend/`), React frontend (`frontend/`).
## Build & test
- Backend: `./mvnw clean verify` (from `backend/`)
- Frontend: `npm test` and `npm run build` (from `frontend/`)
## Coding standards
- Controllers stay thin — no business logic. Business logic belongs in `@Service` classes.
- Services use constructor injection only, never field injection.
- Every public service method validates its inputs and throws `IllegalArgumentException`
with a clear message on invalid input.
- React components are functional components using hooks — no class components.
- All frontend API calls go through `src/api/client.js` — no direct `fetch`/`axios` calls
from components.
## Definition of done
- New behaviour has a corresponding backend and/or frontend test.
- `./mvnw clean verify` and `npm test` both pass.
.github/instructions/backend.instructions.md:
---
applyTo: "backend/**/*.java"
---
- Package by feature, not by layer.
- Constructor injection only; mark injected fields `private final`.
- Validate all public service method arguments; throw `IllegalArgumentException` with a
message naming the offending parameter.
- Controllers only translate HTTP <-> service calls — no `if`/business rules in a controller.
.github/instructions/frontend.instructions.md:
---
applyTo: "frontend/src/**/*.{js,jsx}"
---
- Functional components and hooks only.
- All network calls go through `src/api/client.js` — never call `fetch` directly in a component.
- Co-locate a component's test file next to it as `<Component>.test.jsx`.
Challenges
1. Create the project and make it a git repository
- Create a project folder for the account dashboard (e.g.
account-dashboard/), withbackend/andfrontend/subfolders. - Initialise it as a git repository.
Ask Copilot: What files should a Spring Boot + React monorepo typically ignore in .gitignore?
💡 Show Answer
mkdir account-dashboard
cd account-dashboard
mkdir backend frontend
git init
A sensible starting .gitignore combines Java/Maven build output (target/), Node output (node_modules/, frontend/build/) and IDE metadata (.idea/, .vscode/ if you don't want it shared).
2. Write the repository instructions file
- Create
.github/copilot-instructions.mdat the project root. - Include: the repo layout, build/test commands, the coding standards listed above, and a definition of done.
Ask Copilot: Given this instructions file, where should validation logic for a new "transfer funds" feature live — controller or service?
💡 Show Answer
Copilot should answer service, and should cite the instruction that controllers stay thin and validation belongs in @Service classes — if it doesn't, the instructions file isn't specific enough yet, or isn't being picked up (see the Introduction's tip above).
3. Split out path-specific instructions
- Create
.github/instructions/backend.instructions.mdscoped tobackend/**/*.java. - Create
.github/instructions/frontend.instructions.mdscoped tofrontend/src/**/*.{js,jsx}. - Move the backend-only and frontend-only rules out of the repository-wide file and into these, leaving only genuinely cross-cutting rules at the top level.
Ask Copilot: Why use path-specific instructions instead of putting everything in one repository instructions file?
💡 Show Answer
Path-specific instructions only enter context when a matching file is actually relevant, keeping prompts smaller and more focused, and avoiding Copilot applying backend-only rules (e.g. IllegalArgumentException wording) when you're purely working on a React component, or vice versa.
4. Verify the instructions are respected
- Open a backend Java file and ask Copilot Chat to add a new public service method with no validation.
- Observe whether Copilot proactively adds an
IllegalArgumentExceptioncheck, or whether you need to point it at the instructions explicitly.
💡 Show Answer
With the instructions correctly scoped, Copilot should add the validation unprompted. If it doesn't, check the applyTo glob actually matches the file's path, and that the instructions file is saved under .github/instructions/, not just .github/.