| name | settings-precedence |
| description | VS Code settings precedence rules and common pitfalls. Essential for any code that reads or writes settings. Covers getConfiguration scope, inspect() vs get(), and multi-workspace handling. |
| argument-hint | Review settings handling in [file or component] |
| user-invocable | false |
VS Code Settings Precedence
Settings precedence bugs corrupt user configurations. This skill documents the correct patterns.
Precedence Order (Highest to Lowest)
- Workspace folder value - Per-folder in multi-root workspace
- Workspace value -
.vscode/settings.json or .code-workspace
- User/global value - User
settings.json
- Default value - From extension's
package.json (⚠️ may come from other extensions!)
Core Rules
Rule 1: Always Pass Scope to getConfiguration()
const config = vscode.workspace.getConfiguration('python-envs');
const value = config.get('pythonProjects');
const config = vscode.workspace.getConfiguration('python-envs', workspaceFolder);
const value = config.get('pythonProjects');
When to pass scope:
- Reading per-resource settings (
scope: "resource" in package.json)
- Any multi-workspace scenario
- When you need
workspaceFolderValue from inspect()
Rule 2: Use inspect() to Check Explicit Values
const config = vscode.workspace.getConfiguration('python');
if (config.get('useEnvironmentsExtension')) {
}
const config = vscode.workspace.getConfiguration('python', scope);
const inspected = config.inspect('useEnvironmentsExtension');
const hasExplicitValue =
inspected?.globalValue !== undefined ||
inspected?.workspaceValue !== undefined ||
inspected?.workspaceFolderValue !== undefined;
if (hasExplicitValue) {
const effectiveValue = inspected?.workspaceFolderValue ?? inspected?.workspaceValue ?? inspected?.globalValue;
}
Rule 3: Don't Overwrite User's Explicit Values
await config.update('pythonPath', detectedPath, ConfigurationTarget.Workspace);
const inspected = config.inspect('pythonPath');
const hasUserValue = inspected?.workspaceValue !== undefined;
if (!hasUserValue) {
await config.update('pythonPath', detectedPath, ConfigurationTarget.Workspace);
}
Rule 4: Update at the Correct Scope
ConfigurationTarget.Global;
ConfigurationTarget.Workspace;
ConfigurationTarget.WorkspaceFolder;
await config.update('pythonPath', undefined, ConfigurationTarget.Workspace);
Multi-Root Workspace Handling
The workspace Property
For multi-root workspaces, pythonProjects settings need a workspace property:
{
"python-envs.pythonProjects": [
{
"path": ".",
"workspace": "/path/to/workspace-folder",
"envManager": "ms-python.python:venv"
}
]
}
Without the workspace property, settings get mixed up between folders.
Getting the Right Workspace Folder
const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
const workspaceFolder = vscode.workspace.getWorkspaceFolder(documentUri) ?? vscode.workspace.workspaceFolders?.[0];
const uri = vscode.Uri.file(filePath);
const workspaceFolder = vscode.workspace.getWorkspaceFolder(uri);
Common Issues
Issue: workspaceFolderValue is undefined
Cause: Missing scope parameter in getConfiguration()
const config = vscode.workspace.getConfiguration('python-envs');
const inspected = config.inspect('pythonProjects');
console.log(inspected?.workspaceFolderValue);
const config = vscode.workspace.getConfiguration('python-envs', workspaceFolder.uri);
const inspected = config.inspect('pythonProjects');
console.log(inspected?.workspaceFolderValue);
Issue: defaultValue from other extensions
Cause: Using get() instead of inspect() for boolean checks
The defaultValue in inspect() may come from ANY extension's package.json, not just yours:
config.get('python.useEnvironmentsExtension')
const inspected = config.inspect('python.useEnvironmentsExtension');
if (inspected?.globalValue === true || ...) { }
Issue: Settings overwritten on reload
Cause: Not checking for existing values before writing
await config.update('defaultEnvManager', 'venv', ConfigurationTarget.Global);
const current = config.inspect('defaultEnvManager');
if (current?.globalValue === undefined && current?.workspaceValue === undefined) {
await config.update('defaultEnvManager', 'venv', ConfigurationTarget.Global);
}
Issue: Settings mixed up in multi-root
Cause: Not including workspace identifier in settings
{
"python-envs.pythonProjects": [
{ "path": ".", "envManager": "venv" }
]
}
const project = {
path: projectPath,
workspace: workspaceFolder.uri.fsPath,
envManager: selectedManager
};
Complete Example: Safe Settings Read/Write
import * as vscode from 'vscode';
async function getProjectConfig(projectUri: vscode.Uri): Promise<ProjectConfig | undefined> {
const workspaceFolder = vscode.workspace.getWorkspaceFolder(projectUri);
if (!workspaceFolder) {
return undefined;
}
const config = vscode.workspace.getConfiguration('python-envs', workspaceFolder.uri);
const inspected = config.inspect<ProjectConfig[]>('pythonProjects');
const projects = inspected?.workspaceFolderValue ?? inspected?.workspaceValue ?? inspected?.globalValue ?? [];
return projects.find((p) => path.resolve(workspaceFolder.uri.fsPath, p.path) === projectUri.fsPath);
}
async function saveProjectConfig(projectUri: vscode.Uri, projectConfig: ProjectConfig): Promise<void> {
const workspaceFolder = vscode.workspace.getWorkspaceFolder(projectUri);
if (!workspaceFolder) {
return;
}
const config = vscode.workspace.getConfiguration('python-envs', workspaceFolder.uri);
const inspected = config.inspect<ProjectConfig[]>('pythonProjects');
const existingProjects = inspected?.workspaceFolderValue ?? inspected?.workspaceValue ?? [];
const configToSave: ProjectConfig = {
...projectConfig,
workspace: workspaceFolder.uri.fsPath,
};
const projectIndex = existingProjects.findIndex(
(p) => path.resolve(workspaceFolder.uri.fsPath, p.path) === projectUri.fsPath,
);
const updatedProjects = [...existingProjects];
if (projectIndex >= 0) {
updatedProjects[projectIndex] = configToSave;
} else {
updatedProjects.push(configToSave);
}
const target =
vscode.workspace.workspaceFolders?.length > 1
? vscode.ConfigurationTarget.WorkspaceFolder
: vscode.ConfigurationTarget.Workspace;
await config.update('pythonProjects', updatedProjects, target);
}