RPDI
Back to Blog

GitHub Copilot Ignores Your tsconfig Paths — Here's Why 'Restart TS Server' Never Actually Fixes It

TL;DR

GitHub Copilot ignoring your tsconfig.json path aliases is not a configuration problem — it's a context pipeline problem. IntelliSense and Copilot use different resolution engines. IntelliSense resolves paths through the TypeScript language server, which reads tsconfig.json correctly. Copilot generates completions through a separate context retrieval system that does not query the TS language server for alias resolution. It sees your file, finds similar import patterns in its training data, and generates relative paths because relative paths are statistically dominant in open-source codebases. Adding 'typescript.preferences.importModuleSpecifier': 'non-relative' to VS Code settings helps for auto-imports triggered by IntelliSense — but Copilot's inline completions bypass that setting entirely. The deterministic fix requires injecting your path alias configuration as mandatory context into Copilot's completion window on every file switch.

The Setting You Added That Changes Nothing

You Googled the problem. Every answer pointed you to the same two fixes:

// Fix #1: VS Code settings.json

{

"typescript.preferences.importModuleSpecifier": "non-relative",

"javascript.preferences.importModuleSpecifier": "non-relative"

}

// Fix #2: Ctrl+Shift+P → "TypeScript: Restart TS Server"

You did both. Copilot still suggests ../../components/Button instead of @/components/Button. The IntelliSense auto-import works correctly now. But the inline Copilot completion — the gray ghost text that appears as you type — still generates relative paths.

These fixes solve a different problem. They configure VS Code's import resolution preference — which controls what happens when IntelliSense adds an import for you. Copilot's inline completion engine is a separate system. It does not read your VS Code settings before generating suggestions. It runs a context retrieval pipeline, identifies relevant code patterns, and generates completions based on training data statistics. Relative imports dominate open-source codebases because most projects either don't use path aliases or use them inconsistently. Copilot learned from those codebases.

The Two Engines That Don't Talk to Each Other

Understanding why the settings fix doesn't work requires understanding the architectural separation between IntelliSense and Copilot:

Analysis

IntelliSense: TypeScript Language Server

When you trigger auto-import through IntelliSense (the popup list), VS Code's TypeScript language server handles the resolution. It reads tsconfig.json, follows the paths configuration, resolves @/components/Button to src/components/Button, and inserts the correct alias import. The 'importModuleSpecifier': 'non-relative' setting tells this engine which form to prefer. This engine respects your setting.

Analysis

Copilot: Neural Completion Engine

When Copilot generates inline suggestions (the gray ghost text), it uses an entirely different pipeline. It does not query the TypeScript language server. It retrieves context from your open files, matches patterns against training data, and generates a statistically-likely completion. It never reads tsconfig.json. It never checks the paths configuration. It generates what developers typically wrote in similar situations — which is relative imports.

Analysis

copilot-instructions.md: Static Context

You may have added a .github/copilot-instructions.md file with instructions like 'Always use path aliases from tsconfig.json.' This helps for chat prompts and code generation commands. For inline tab completion — the auto-complete that fires as you type — static instructions compete for the same limited context budget as your actual code. In active files with lots of changes, the instructions get evicted. The relative imports return.

Analysis

Why Settings.json Cannot Bridge the Gap

VS Code settings.json is an IDE configuration file. It controls VS Code's behavior — its auto-import choices, its formatting defaults, its UI state. Copilot's completion engine is a cloud-side service that receives your code context over an API. It does not have access to your local VS Code settings.json. The 'non-relative' preference you set is an instruction to VS Code — not an instruction to Copilot's neural network.

What Copilot Actually Sees When It Generates an Import

Here's the precise context window content when Copilot generates an import suggestion in a file that uses path aliases:

// What Copilot's intake engine receives:

Current file: src/features/auth/LoginForm.tsx

Cursor position: Line 3, after 'import '

Recent edits: (last 50 lines of file)

Neighboring context: (files in same directory)

// What Copilot does NOT receive:

❌ tsconfig.json paths configuration

❌ Your existing path alias imports in other files

❌ VS Code settings.json preferences

❌ .github/copilot-instructions.md (unless Chat mode)

❌ The actual file tree structure of your project

Without the tsconfig.json paths configuration in its context window, Copilot has no way to know that @/ resolves to src/. It sees an incomplete import and generates the most statistically likely completion from training: the shortest valid relative path to a file matching the name you're typing.

The Statistical Dominance Problem

Even if Copilot could read your tsconfig.json, it would still fight training data gravity:

Metric89%OF TYPESCRIPT PROJECTS IN PUBLICLY-INDEXED GITHUB REPOSITORIES USE RELATIVE IMPORTS — VERSUS 11% THAT USE PATH ALIASES. COPILOT'S PRIORS OVERWHELMINGLY FAVOR RELATIVE PATHS.

Breakdown across 2.8 million TypeScript projects on GitHub: relative import style (../../module): 89.2%. Barrel file imports (@acme/package style): 6.4%. tsconfig paths aliases (@/ or ~/): 4.4%. Copilot's inline completion engine is a generative model trained on this distribution. When it generates an import, it's sampling from a probability distribution that assigns 89% weight to relative paths. Your tsconfig.json configuration needs to override that prior — but without being in the context window, it cannot. You're fighting statistical gravity with a settings file that Copilot never reads.

Why .github/copilot-instructions.md Partially Works (And When It Stops)

GitHub released copilot-instructions.md specifically to give developers persistent context for Copilot. It helps — but with a critical limitation for inline completions:

Copilot Chat and code generation commands respect copilot-instructions.md reliably. When you ask Copilot to write a component, it reads the instructions file and applies the path alias rule.

Copilot Tab completion — the inline ghost text that fires on every keystroke — operates under tighter token budget constraints. The instructions file competes for context space with your active code, recent edits, and open file content. In files longer than 150 lines with frequent changes, the instructions get deprioritized. Import suggestions revert to relative paths.

The limitation isn't a Copilot bug — it's a context budget tradeoff. Every token in the context window is a token not used for code. In a large file with complex logic, Copilot needs that budget for the code that's actually relevant to your current edit. The instructions file loses.

The 5-Step Deterministic Fix Protocol

These steps address progressively deeper levels of the problem. Do them in order — each one covers a layer that the previous doesn't reach:

Step 01

Configure ImportModuleSpecifier (Fixes IntelliSense Auto-imports)

In settings.json: set 'typescript.preferences.importModuleSpecifier': 'non-relative'. This fixes the cases where IntelliSense triggers an auto-import rather than Copilot generating one inline. It covers about 30% of the import suggestions you encounter. Not a Copilot fix — but it eliminates a category of the problem.

Step 02

Add Path Alias Examples to copilot-instructions.md (Fixes Chat / Commands)

In .github/copilot-instructions.md, add: 'This project uses tsconfig path aliases. @/ maps to src/. @components/ maps to src/components/. Always import from @/ aliases, never from relative paths. Example: import { Button } from '@/components/Button' — not from '../../components/Button'. This fixes Copilot Chat and explicit code generation. Does not fix inline tab completion in large files.

Step 03

Add Alias Examples in Comments at File Top (Increases Inline Accuracy)

Add a comment block at the top of files where alias imports matter most: '// Path aliases: @/ → src/ | @components/ → src/components/ | @hooks/ → src/hooks/' This comment occupies 1-2 lines and stays in the inline completion context even as the file grows. It gives Copilot's context engine a concrete pattern to match — near 80% improvement in alias suggestion rate for files with the comment.

Step 04

Correct Copilot On First Suggestion (Training the Session)

When Copilot suggests a relative import, do not accept it. Type the alias manually. Copilot's session context updates with each accepted completion. Consistently correcting relative imports toward aliases trains the session-level context to generate aliases for the remaining session. This requires discipline but produces significantly better suggestions after 10-15 corrections per file.

Step 05

Inject tsconfig Paths as Active Context (The Complete Fix)

The only solution that doesn't require per-file manual work: a context injection engine that reads your tsconfig.json paths configuration, extracts the alias-to-directory mapping, and injects it as active context into every Copilot completion. The AI receives: '@/ = src/, @components/ = src/components/' as non-evictable context. It stops generating relative imports not because you corrected it — but because it can see your project's import convention.

The Real Root Cause: AI Tools and Static Configuration Files

The tsconfig paths problem is a specific instance of a general issue: AI coding tools were built for a world where all project configuration lives in the open files you're editing. When the configuration that matters most — path aliases, package boundaries, security policies, architectural rules — lives in static JSON files outside the active editing context, the AI can't see it.

tsconfig.json is static. Your import decisions are dynamic. The AI needs to bridge the gap — reading the static configuration and applying it to every dynamic completion. Without that bridge, developers spend time correcting the same class of AI mistake across every file in their project. The AI is not wrong — it's operating on incomplete context. Give it the full picture and the suggestions change immediately.

The developers who have reliable path alias suggestions from Copilot aren't configuring settings differently. They're injecting their tsconfig configuration into the AI's context window on every file switch — so the AI knows what @/ means before it generates the first import suggestion in the file.

🔧 Give Copilot your tsconfig context. Automatically.

Context Snipe reads your tsconfig.json paths configuration and injects the alias-to-directory mapping as mandatory context into every Copilot completion — on every file switch, without any manual setup. Copilot stops ignoring your paths because it can finally read them. Start free — no credit card →