How to Use Multi-File Context in GitHub Copilot: Automate Large-Scale Refactoring with #file and @workspace
Introduction: Why Multi-File Context Matters in GitHub Copilot
Modern codebases rarely live in a single file. When you refactor a service layer, rename a shared interface, or migrate an API version, dozens of files may need coordinated changes. GitHub Copilot Chat’s #file references and @workspace agent give you the power to feed cross-file context into the AI, producing suggestions that are aware of your entire project structure rather than just the open tab.
This guide walks you through a practical, step-by-step workflow for leveraging these features to automate large-scale refactoring tasks safely and efficiently.
Prerequisites
- VS Code 1.90 or later (or a recent VS Code Insiders build)- GitHub Copilot extension (
GitHub.copilot) and GitHub Copilot Chat extension (GitHub.copilot-chat) installed- An active GitHub Copilot Individual, Business, or Enterprise subscription- A workspace with at least one folder open (multi-root workspaces are supported)
Step 1 — Install and Verify Extensions
- Open VS Code and navigate to the Extensions panel (Ctrl+Shift+X).- Search for GitHub Copilot and install both the core extension and the Chat extension.- Confirm activation by opening the Copilot Chat panel with Ctrl+Shift+I (or Cmd+Shift+I on macOS). You should see the chat input ready.
# Verify from the command line (optional) code —list-extensions | grep -i copilot
Expected output:
GitHub.copilot
GitHub.copilot-chat
Core Concepts
The #file Reference
Inside Copilot Chat, typing #file followed by a filename lets you explicitly attach a file's content to your prompt. Copilot then reads that file and uses it as context when generating a response.
# Example prompt in Copilot Chat:
# "Refactor the logger calls in #file:src/services/userService.ts
# to use the new LoggerV2 interface defined in #file:src/utils/loggerV2.ts"
You can reference multiple files in a single prompt. This is essential when changes in one file depend on types, interfaces, or constants defined in another.
The @workspace Agent
The @workspace agent automatically indexes your entire workspace and retrieves relevant files without you having to name them. It uses embeddings-based search behind the scenes.
# Example prompt:
“@workspace Find every file that imports the old AuthMiddleware
and show me what needs to change to use AuthMiddlewareV2.”
Use @workspace when you are unsure which files are affected. Use #file when you know exactly which files to target.
Step-by-Step: Automating a Multi-File Refactoring
Let’s walk through a realistic scenario: renaming an interface from IUserRepository to UserRepository across a TypeScript project and updating all imports and usages.
Step 2 — Discover Affected Files with @workspace
Open Copilot Chat and ask:
@workspace Which files import or reference IUserRepository? List them with line numbers.
Copilot will scan your workspace index and return a list like:
- src/repositories/userRepository.ts (line 3, 15)
- src/services/userService.ts (line 2)
- src/controllers/userController.ts (line 4)
- src/tests/userService.test.ts (line 1, 22)
src/di/container.ts (line 8)
Step 3 — Define the Target State with #file Context
Rename the interface in the source file first:
// src/repositories/userRepository.ts
export interface UserRepository {
findById(id: string): Promise
Then ask Copilot to propagate the change:
# Copilot Chat prompt:
"I renamed IUserRepository to UserRepository in
#file:src/repositories/userRepository.ts.
Update all imports and usages in:
#file:src/services/userService.ts
#file:src/controllers/userController.ts
#file:src/di/container.ts
#file:src/tests/userService.test.ts
Preserve all existing logic. Only change the interface name and imports."
### Step 4 — Review and Apply Changes
Copilot Chat will generate diffs for each referenced file. Review each suggestion carefully:
- Click the **Apply in Editor** button (or the diff icon) next to each code block.- VS Code opens an inline diff view. Accept or reject individual hunks.- After applying, run your test suite to verify nothing broke:npm test
# or
pnpm test --filter=user*
### Step 5 — Handle Complex Cascading Changes
For deeper refactoring where types flow through multiple layers, chain your prompts:
# Prompt 1 — Update the repository layer
"@workspace Update every concrete class that implements UserRepository
to match the new method signatures in #file:src/repositories/userRepository.ts"
Prompt 2 — Update the service layer
“Now update the service layer. The repository changes are in
#file:src/repositories/postgresUserRepository.ts
and the service is in #file:src/services/userService.ts.
Keep error handling intact.”
Pro Tips for Power Users
- Combine
@workspacewith#file: Use@workspaceto discover files, then pin specific ones with#filefor precise edits. This hybrid approach gives you breadth and depth.- Use#selectionfor surgical edits: Highlight a block of code, then reference#selectionin your prompt to scope Copilot’s attention to just that region.- Batch via terminal: For repetitive changes across 50+ files, ask Copilot to generate a sed or codemod script instead of editing files one by one:
- Workspace settings for large repos: If# Copilot prompt: “Generate a bash one-liner using sed to rename IUserRepository to UserRepository in all .ts files under src/”@workspaceis slow on a monorepo, exclude heavy directories from indexing by adding them to.github/copilot-ignoreor your.gitignore.- Save reusable prompts: Store frequently used refactoring prompts in a.github/copilot-prompts/directory as Markdown files. You can reference them via the/slash command in Copilot Chat.
Troubleshooting Common Issues
| Problem | Cause | Solution |
|---|---|---|
#file reference not resolving | File path is relative and ambiguous in a multi-root workspace | Use the full path from the workspace root, e.g., #file:packages/api/src/auth.ts |
@workspace returns no results | Workspace index has not been built yet | Wait for the indexing indicator in the status bar to complete, or run **Developer: Reload Window** |
| Suggestions ignore referenced file content | Context window overflow — too many files referenced | Reduce to 3-5 #file references per prompt; split into multiple prompts |
| Applied changes introduce type errors | Copilot lacks visibility into transitive dependencies | Add the missing dependency file as another #file reference and re-prompt |
| Chat says "I don't have access to your workspace" | Copilot Chat extension outdated or workspace trust disabled | Update extensions and ensure the workspace is trusted via **File → Workspace Trust** |
@workspace to identify all affected files.- **Pin** — Attach critical files with #file for precise context.- **Prompt** — Write a clear, scoped instruction describing the change.- **Review** — Inspect every diff before applying.- **Verify** — Run tests and type checks after each batch of changes.- **Iterate** — Chain follow-up prompts for cascading updates.
## Frequently Asked Questions
How many files can I reference with #file in a single prompt?
There is no hard-coded limit on the number of #file references, but Copilot's context window is finite. In practice, referencing more than 5-8 large files may cause the model to truncate or ignore some content. For best results, keep each prompt focused on 3-5 files and split broader refactoring into sequential prompts.
What is the difference between @workspace and manually adding #file references?
@workspace performs an automated semantic search across your entire codebase and selects the most relevant files for your query. #file gives you explicit, deterministic control over exactly which files are included. Use @workspace for exploration and discovery; use #file when you already know the exact files that need changes and want guaranteed context inclusion.
Can I use these features with languages other than TypeScript?
Yes. Both #file and @workspace are language-agnostic. They work with Python, Java, Go, C#, Rust, and any other language supported by GitHub Copilot. The workspace indexer processes all text-based files in your project regardless of language.