Prahlad Yeri · June 24, 2026 · 21 min read
A guide for the power-user who values control, clarity, and a lean editor over feature bloat.
Notepad++ is a legendary text editor, but it lacks native LSP (Language Server Protocol) support, modern multi-cursor ergonomics, and integrated terminal profiling. Vim requires a steep cognitive load for configuration. Sublime is proprietary and its package ecosystem is fracturing. VS Code sits in the sweet spot: it is fundamentally a text editor with a standardized extension API, allowing you to build exactly the IDE you need, and nothing more.
VS Code ships with a massive amount of hidden functionality. Before installing an extension to “add a feature” check if it already exists. The minimalist rule: If a built-in feature can do 80% of what you need, use it. Do not install a “Live Server” extension when a simple terminal alias or built-in preview works. Do not install “GitLens” when the built-in Source Control gutter decorations suffice.
.code-workspace).code --install-extension) and .vscode/extensions.json.Avoid the .exe or .msi system installers if you want total control. They pollute the registry and scatter config across %APPDATA%.
winget install Microsoft.VisualStudioCode --source winget or download the .zip system archive.brew install --cask visual-studio-code.apt or dnf repositories.Portable mode keeps VS Code entirely self-contained. No registry keys, no %APPDATA% pollution. It can be run from a USB drive or a synced folder.
.zip (Windows) or .tar.gz (Linux) archive.C:\Tools\VSCode (or equivalent).data.Code.exe. VS Code will now store all settings, extensions, and logs inside data/.In Portable Mode (or standard install), understand your directories:
data/user-data/: Your settings.json and keybindings.json.data/extensions/: The actual extension code.data/logs/: Crash and telemetry logs.Create or edit argv.json (located in data/ for portable, or ~/.vscode/ for standard). Add these flags to kill telemetry and optimize startup:
{
"disable-telemetry": true,
"disable-workspace-trust": true,
"enable-proposed-api": [],
"locale": "en"
}
Ensure the code command is in your PATH. Verify with:
code --version
code --list-extensions # Should be empty on a fresh install
settings.json vs. the Settings UIThe Settings UI is a crutch that hides the underlying JSON structure and makes bulk-editing impossible. Press Ctrl+Shift+P, type Preferences: Open User Settings (JSON), and edit the raw file.
Precedence flows downward. Understand this to avoid “why isn’t my setting applying?”
settings.json (Global)..vscode/settings.json (Overrides User)..vscode/settings.json in a multi-root workspace folder.keybindings.json and when-clause contextsKeybindings are scoped by context. You don’t want Ctrl+Enter to run a script when your cursor is in the terminal. We use when clauses:
{
"key": "ctrl+enter",
"command": "workbench.action.tasks.runTask",
"when": "editorTextFocus && !terminalFocus"
}
Snippets are faster than macros. Define them in settings.json under editor.snippets or in dedicated .json files via Preferences: Configure User Snippets. Scope them to languages to prevent bloat in the autocomplete menu.
tasks.json automates CLI commands (build, lint). launch.json attaches the debugger. Keep these in .vscode/ at the project root. They are code, not magic.
Do not use one global profile. Create a “Web” profile (loads ESLint, Prettier) and a “Backend” profile (loads Python, PHP).
CLI: code --profile "Web" .
This ensures extensions only activate when needed, saving RAM and CPU.
Keep your settings.json, keybindings.json, and snippets/ in a private Git repository. Symlink them into your VS Code user directory. This is the only sane way to manage config across machines without relying on Microsoft’s Settings Sync.
Notepad++ saves open tabs in a “Session”. VS Code uses .code-workspace files.
Create myproject.code-workspace:
{
"folders": [
{ "path": "./frontend" },
{ "path": "./backend" }
],
"settings": {
"editor.fontSize": 14
}
}
Open this file, and VS Code restores the exact folder structure and tab state.
N++ requires Alt+Mouse Drag for column edit. VS Code has this built-in, but the muscle memory needs updating:
Shift+Alt+Mouse Drag (or Ctrl+Shift+Alt+Arrow Keys).Alt+Click.Ctrl+D (The most powerful multi-cursor tool in the editor).N++ uses Boost regex. VS Code uses Rust-based regex. They are 95% identical.
Difference: VS Code requires escaping forward slashes / in some contexts, and lookbehinds must be fixed-width. Use Ctrl+H, click the .* icon, and test.
N++’s Function List is replaced by the Outline view (Ctrl+Shift+O). It is driven by the language server, meaning it understands classes, methods, and variables dynamically, not just via regex parsing.
N++’s Document Map is the Minimap on the right edge.
Minimalist tip: It consumes GPU and screen real estate. Disable it globally in settings.json:
"editor.minimap.enabled": false
Use Ctrl+G to jump to lines instead.
N++ uses the “Compare” plugin. VS Code has native diffing.
CLI: code --diff file1.js file2.js
GUI: Select two files in Explorer, right-click -> “Compare Selected”.
N++ macros record keystrokes. VS Code removed macro recording because multi-cursor and snippets solve the problem better.
Instead of recording a macro to wrap 10 lines in <li> tags: Select the lines, Shift+Alt+I (adds cursor to end of each line), type <li>, End, type </li>.
To ease the transition, map N++ shortcuts in keybindings.json:
// Map N++ "Run macro multiple times" (Ctrl+Shift+R) to VS Code "Add Selection to Next Find Match" (Ctrl+D)
{ "key": "ctrl+shift+r", "command": "editor.action.addSelectionToNextFindMatch" }
Do not use external terminals. VS Code’s terminal supports profiles, split panes, and custom env vars.
"terminal.integrated.profiles.windows": {
"PowerShell Core": { "path": "pwsh.exe", "icon": "terminal-powershell" },
"Git Bash": { "path": "bash.exe", "icon": "terminal-bash" }
}
Built-in. No extension needed. Type div.container>ul>li*5 and press Tab. It works in HTML, CSS, JSX, and Blade.
Ctrl+P: Go to File (fuzzy search).Ctrl+Shift+P: Command Palette.Ctrl+P then :: Go to Line.Ctrl+P then @: Go to Symbol in file.Ctrl+P then @:: Go to Symbol in workspace.F12 / Ctrl+Click: Go to Definition.Shift+F12: Find All References.Ctrl+Tab: Switch between recent files (like N++’s Document Switcher).Ctrl+Shift+R or F2 (Rename Symbol). Built-in renaming updates all references across the workspace. Do not install “Refactor” extensions.
The built-in Git integration handles staging, committing, pushing, and pulling. The gutter decorations (blue/green/red) show line changes. Do not install GitLens unless you specifically need historical blame annotations; it is a massive performance sink.
Ctrl+Shift+M: Problems panel (linting/errors).Ctrl+Shift+U: Output channel (task logs).Ctrl+Shift+Y: Debug console.Create project-specific snippets in .vscode/project.code-snippets. This keeps boilerplate out of your global user settings.
Run shell scripts, npm, make, or python without extensions. Define them in .vscode/tasks.json. (See Section 7/8/9/10 for examples).
For simple HTML, use the built-in “Simple Browser” (Ctrl+Shift+P -> Simple Browser: Show). For actual dev servers, run them in the terminal. Avoid “Live Server” extensions that spawn hidden background processes.
Learn the defaults before remapping. Ctrl+K Ctrl+S opens the keyboard shortcuts UI, but we edit JSON.
keybindings.json by handCtrl+K Ctrl+Shift+K opens the raw JSON.
when clausesContexts are crucial. Examples:
editorTextFocus: Cursor is in the code editor.terminalFocus: Cursor is in the terminal.explorerViewletVisible: File explorer is open.inQuickOpen: Command palette is open.Remove vs. overrideIf a shortcut conflicts, don’t just override it. Remove the default binding first to prevent ghost triggers:
{ "key": "ctrl+shift+p", "command": "-workbench.action.showCommands" }
Chords are two-part shortcuts (e.g., Ctrl+K followed by Ctrl+C to comment). Define them by separating keys with spaces:
{ "key": "ctrl+k ctrl+m", "command": "editor.action.toggleMinimap" }
Keep it close to defaults. Only remap things that conflict with your OS or N++ muscle memory.
Case Study: A 3-person agency building React frontends for headless WordPress CMSs. They need fast linting, zero bloat, and reliable debugging.
Emmet, JSX highlighting, basic IntelliSense, and CSS color decorators are native.
dbaeumer.vscode-eslintJustification: Built-in JS validation only checks syntax. ESLint checks logic, React hooks rules, and team conventions.
Minimal config (.eslintrc.json):
{
"extends": ["react-app", "react-app/jest"],
"rules": { "no-unused-vars": "warn" }
}
Install per-project via .vscode/extensions.json so it doesn’t bloat your global profile.
esbenp.prettier-vscode (Optional)Justification: Only install if the team enforces strict formatting. Otherwise, rely on ESLint --fix. If used, disable VS Code’s default JS formatter:
"[javascript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }
Keep tsconfig.json strict.
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"strict": true,
"jsx": "react-jsx",
"moduleResolution": "node"
}
}
tasks.jsonNo extension needed.
{
"version": "2.0.0",
"tasks": [
{
"label": "Start React Dev Server",
"type": "shell",
"command": "npm start",
"group": "build",
"isBackground": true,
"problemMatcher": []
}
]
}
Use the built-in js-debug. .vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"request": "launch",
"name": "Debug React",
"url": "http://localhost:3000",
"webRoot": "${workspaceFolder}/src"
}
]
}
Built-in validation is fine. Only add csstools.postcss if you are actively writing PostCSS plugins. Otherwise, standard CSS variables and nesting (now native) are sufficient.
Create .vscode/react.code-snippets for component boilerplate. Avoid global snippet packs that pollute autocomplete.
Case Study: A solo data engineer writing ETL scripts and FastAPI endpoints. Needs fast linting and reliable debugging without Anaconda’s heavy IDE overhead.
ms-python.pythonJustification: The one unavoidable extension. It provides the Python language server, environment management, and debugger integration. It is heavy, but necessary.
Never use the global system Python for projects. Use venv.
"python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python"
debugpyThe Python extension uses debugpy under the hood. Configure it in launch.json:
{
"name": "Python: Current File",
"type": "python",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal"
}
Do not install Pylint, Flake8, and Pyflakes. Install charliermarsh.ruff. It is written in Rust, runs in milliseconds, and replaces all of them.
"python.linting.enabled": true,
"python.linting.ruffEnabled": true,
"[python]": {
"editor.codeActionsOnSave": { "source.organizeImports": "explicit" }
}
Skip Black or Autopep8. Ruff includes a formatter.
"[python]": {
"editor.defaultFormatter": "charliermarsh.ruff",
"editor.formatOnSave": true
}
Do not install “Code Runner”. It hides errors and manages processes poorly. Use the integrated terminal (python ${file}) or define a Task.
The built-in .ipynb renderer is sufficient for viewing. Only install ms-toolsai.jupyter if you need to execute cells and manage kernels directly inside the editor.
Do not install a mypy extension. Run it via tasks.json or pre-commit hooks. It keeps the editor fast.
Case Study: A freelancer maintaining 15 legacy WordPress sites and building custom Laravel APIs. Needs fast IntelliSense without the memory leak of older PHP extensions.
bmewburn.vscode-intelephense-clientJustification: The built-in PHP language server is basic and slow. Intelephense is blazing fast, handles large codebases (like WordPress core) without choking, and provides excellent go-to-definition.
To prevent conflicts and save RAM, disable the native PHP features:
"php.validate.enable": false,
"php.suggest.basic": false
Point VS Code to your local PHP binary for Intelephense and validation:
"php.validate.executablePath": "C:/php/php.exe",
"intelephense.environment.phpVersion": "8.2.0"
Do not install a Composer extension. Use tasks:
{
"label": "Composer Install",
"type": "shell",
"command": "composer install",
"options": { "cwd": "${workspaceFolder}" }
}
Run it in the terminal: ./vendor/bin/phpunit. Do not install heavy test-runner UI extensions. The terminal output is sufficient and faster.
xdebug.php-debugJustification: The only second PHP extension you need. Felix Becker’s debugger is the standard.
Configure launch.json:
{
"name": "Listen for Xdebug",
"type": "php",
"request": "launch",
"port": 9003
}
If you write Blade, add onecentlin.laravel-blade. It provides syntax highlighting. Do not add “Laravel Extension Pack” bundles; they include 5+ extensions you don’t need.
Case Study: A small shop maintaining a mix of modern .NET 8 microservices and a legacy .NET Framework 4.8 WinForms inventory app. Microsoft’s tooling wants to force you into a bloated IDE experience. We refuse.
CRITICAL WARNING: Microsoft will prompt you to install the “C# Dev Kit”. Do not install it. It is a massive suite that includes solution explorers, test explorers, and telemetry-heavy background services.
The Minimalist Choice: Install only the base ms-dotnettools.csharp extension (the modern Roslyn language server). It provides syntax highlighting, IntelliSense, and basic refactoring. That is all you need.
dotnet CLI.Do not use GUI Solution Explorers. Manipulate .sln and .csproj files via the dotnet CLI.
# Create a new console app
dotnet new console -n MyApp
# Add it to a solution
dotnet sln MyApp.sln add MyApp/MyApp.csproj
# Add a project reference
dotnet add MyApp/MyApp.csproj reference OtherApp/OtherApp.csproj
tasks.jsonMinimalist task configurations. No extensions required.
{
"version": "2.0.0",
"tasks": [
{
"label": "dotnet Build",
"command": "dotnet",
"type": "process",
"args": ["build", "${workspaceFolder}/MyApp.sln"],
"problemMatcher": "$msCompile"
},
{
"label": "dotnet Watch",
"command": "dotnet",
"type": "process",
"args": ["watch", "run", "--project", "${workspaceFolder}/MyApp/MyApp.csproj"],
"isBackground": true
}
]
}
The base C# extension includes the coreclr debugger. Configure launch.json:
{
"version": "0.2.0",
"configurations": [
{
"name": ".NET Core Launch (console)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "dotnet Build",
"program": "${workspaceFolder}/MyApp/bin/Debug/net8.0/MyApp.dll",
"cwd": "${workspaceFolder}",
"stopAtEntry": false
}
]
}
Do not install StyleCop or ReSharper clones. Leverage built-in .editorconfig support. Create an .editorconfig at your solution root:
root = true
[*]
indent_style = space
indent_size = 4
insert_final_newline = true
[*.cs]
csharp_style_var_for_built_in_types = true:suggestion
VS Code’s Roslyn server will enforce this automatically.
Do not use GUI package managers. Use the CLI:
dotnet add package Newtonsoft.Json --version 13.0.3
dotnet list package
Do not install heavy third-party test runners. Run tests via the terminal or tasks:
{
"label": "dotnet Test",
"command": "dotnet",
"type": "process",
"args": ["test", "${workspaceFolder}/MyApp.sln", "--logger:console;verbosity=normal"]
}
If you absolutely need a UI for test results, use the built-in VS Code “Test Explorer” (which the base C# extension supports natively), but avoid extensions like “Test Runner for .NET” which duplicate this functionality.
If you install a new extension, you must delete or disable an existing one. This forces you to evaluate if the new tool actually provides more value than what you have.
Run this monthly:
code --list-extensions --show-versions > extensions_backup.txt
Review the list. If you don’t recognize an extension or haven’t used it in a month, uninstall it.
package.jsonBefore installing an extension from the marketplace, download its .vsix, extract it, and read package.json. Look at activationEvents.
"*" (activates on startup), reject it. It will slow down your editor."onLanguage:python", it’s safe. It only loads when you open a Python file..vsixFor maximum control and offline use, download the .vsix from the marketplace website. Install via CLI:
code --install-extension my-extension-1.2.3.vsix
This prevents auto-updates from silently introducing bloat or telemetry.
Instead of global installs, use .vscode/extensions.json:
{
"recommendations": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
]
}
When a new dev opens the project, VS Code prompts them to install only what the project needs.
If you must have an extension globally, disable it in specific workspaces. Open the Extensions sidebar, right-click the extension, and select “Disable (Workspace)”.
Developer: Startup Performance in the Command Palette. If an extension takes >500ms to activate, remove it.Microsoft’s Settings Sync requires a GitHub/Microsoft account, sends your config to their cloud, and often overwrites local tweaks. The minimalist uses local files.
Create backup_vscode.sh (or .bat):
#!/bin/bash
# Assuming Portable Mode in ./data
cp data/user-data/User/settings.json ./backup/settings.json
cp data/user-data/User/keybindings.json ./backup/keybindings.json
cp -r data/user-data/User/snippets ./backup/snippets
code --list-extensions --show-versions > ./backup/extensions.txt
Create restore_vscode.sh:
#!/bin/bash
cp ./backup/settings.json data/user-data/User/settings.json
cp ./backup/keybindings.json data/user-data/User/keybindings.json
cp -r ./backup/snippets data/user-data/User/snippets
while read ext; do
code --install-extension "$ext"
done < ./backup/extensions.txt
Keep your VSCode_Portable folder on a fast USB-C drive. Plug it into any Windows/Mac/Linux machine, run Code.exe, and you have your exact environment, extensions, and settings. No installation required.
If not using portable mode, symlink your config to a Git repo:
# Linux/macOS
ln -s ~/dotfiles/vscode/settings.json ~/.config/Code/User/settings.json
# Windows (PowerShell Admin)
New-Item -ItemType SymbolicLink -Path "$env:APPDATA\Code\User\settings.json" -Target "C:\dotfiles\vscode\settings.json"
If VS Code feels sluggish, run Developer: Startup Performance. Look for extensions with high “Activation” times.
VS Code ships with extensions for Grunt, Gulp, Jake, npm, and more. If you don’t use them, disable them.
CLI: code --disable-extension vsix.vscode-grunt
Or via UI: Search @builtin grunt and disable.
This is the #1 performance fix. If you have node_modules, .git, or dist folders, exclude them from file watching and searching:
"files.watcherExclude": {
"**/.git/objects/**": true,
"**/.git/subtree-cache/**": true,
"**/node_modules/**": true,
"**/dist/**": true
},
"search.exclude": {
"**/node_modules": true,
"**/dist": true,
"**/package-lock.json": true
}
If you experience screen tearing or high GPU usage, disable hardware acceleration in argv.json:
"disable-hardware-acceleration": true
Conversely, if rendering is slow, ensure it’s set to false (meaning acceleration is enabled).
If VS Code crashes or hangs, launch it with extensions disabled to isolate the issue:
code --disable-extensions .
If the problem disappears, an extension is the culprit. Re-enable them one by one.
Ctrl+P: Go to FileCtrl+Shift+P: Command PaletteCtrl+Shift+O: Go to SymbolCtrl+G: Go to LineF12: Go to DefinitionShift+F12: Find ReferencesCtrl+D: Select Next OccurrenceCtrl+Shift+L: Select All OccurrencesAlt+Up/Down: Move Line Up/DownShift+Alt+Up/Down: Copy Line Up/DownCtrl+/: Toggle Line CommentCtrl+Shift+A: Toggle Block Commentsettings.json (Zero Bloat){
// UI & Visuals
"editor.minimap.enabled": false,
"editor.renderWhitespace": "selection",
"editor.bracketPairColorization.enabled": true,
"editor.guides.bracketPairs": true,
"workbench.activityBar.location": "top",
// Behavior
"editor.formatOnSave": true,
"editor.defaultFormatter": null,
"editor.tabSize": 4,
"editor.insertSpaces": true,
"files.trimTrailingWhitespace": true,
"files.insertFinalNewline": true,
"files.autoSave": "onFocusChange",
// Performance
"files.watcherExclude": {
"**/.git/objects/**": true,
"**/node_modules/**": true
},
"search.exclude": {
"**/node_modules": true,
"**/dist": true
},
// Telemetry & Trust
"telemetry.telemetryLevel": "off",
"security.workspace.trust.enabled": false,
"extensions.autoUpdate": false
}
keybindings.json with N++-friendly remaps[
{
"key": "ctrl+shift+r",
"command": "editor.action.addSelectionToNextFindMatch",
"when": "editorFocus"
},
{
"key": "ctrl+d",
"command": "editor.action.copyLinesDownAction",
"when": "editorTextFocus && !editorReadonly"
},
{
"key": "shift+alt+down",
"command": "-editor.action.copyLinesDownAction"
}
]
.vscode/extensions.json templatesReact/TS:
{
"recommendations": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
]
}
Python:
{
"recommendations": [
"ms-python.python",
"charliermarsh.ruff"
]
}
PHP:
{
"recommendations": [
"bmewburn.vscode-intelephense-client",
"xdebug.php-debug"
]
}
C#:
{
"recommendations": [
"ms-dotnettools.csharp"
]
}
.code-workspace file defining multiple folders and specific settings for a project context.package.json.onLanguage:python, onCommand:ext.run).when clause: A boolean expression in keybindings or menus that restricts their availability based on UI context (e.g., editorTextFocus).