왜 이 글을 쓰나
VS Code를 설치하고 기본 설정 그대로 쓰는 개발자가 많다. 폰트는 Consolas, 탭은 4칸, formatOnSave는 꺼진 채로. 처음엔 그래도 된다. 그런데 하루 8시간 에디터를 쓰다 보면, 작은 설정 차이가 생산성에 누적 영향을 준다는 걸 알게 된다.
저장할 때마다 자동 포매팅, 언어별 다른 탭 크기, 파일 트리 아이콘, 팀 프로젝트에서 모두 같은 규칙 적용 — 이 모든 게 설정 파일 하나로 해결된다. 그리고 console.log 디버깅에서 벗어나게 해주는 launch.json까지.
매일 쓰는 에디터를 10%만 쓰고 있다면 아깝다. 실무에서 진짜 쓰는 설정만 추렸다.
settings.json 핵심 설정
에디터 기본
{
// 폰트
"editor.fontFamily": "'JetBrains Mono', 'Fira Code', Menlo, monospace",
"editor.fontSize": 14,
"editor.lineHeight": 1.7,
"editor.fontLigatures": true,
// 탭/인덴트
"editor.tabSize": 2,
"editor.insertSpaces": true,
"editor.detectIndentation": false,
// 저장 동작
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.organizeImports": "explicit"
},
// 파일 끝 처리
"files.trimTrailingWhitespace": true,
"files.insertFinalNewline": true,
"files.trimFinalNewlines": true,
// 인코딩
"files.encoding": "utf8",
"files.eol": "\n",
// 자동 저장
"files.autoSave": "onFocusChange",
// UI
"editor.minimap.enabled": false,
"editor.wordWrap": "off",
"editor.rulers": [100],
"editor.cursorBlinking": "smooth",
"editor.smoothScrolling": true,
"workbench.tree.indent": 14,
"explorer.compactFolders": false,
// 2024년 안정화된 신규 옵션
"editor.stickyScroll.enabled": true,
"editor.stickyScroll.maxLineCount": 5
}
fontLigatures: true는 =>, !==, >= 같은 조합을 합자(ligature)로 렌더링한다. JetBrains Mono, Fira Code 모두 지원한다. 취향 타지만 한 번 켜면 못 끈다.
detectIndentation: false는 중요하다. 기본값이 true라서, 파일마다 탭 크기가 들쑥날쑥하게 인식되는 문제가 생긴다. false로 두고 직접 지정하는 게 낫다.
stickyScroll.enabled: true는 VS Code 1.90에서 기본값이 true로 변경된 기능이다. 중첩된 함수나 클래스 내부를 스크롤할 때, 현재 위치의 부모 스코프(클래스명, 함수명 등)를 에디터 상단에 고정해서 보여준다. 깊은 중첩 코드를 탐색할 때 "지금 어디 있는 거지?" 를 줄여준다.
언어별 설정
{
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.tabSize": 2
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.tabSize": 2
},
"[javascriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.tabSize": 2
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.tabSize": 2
},
"[python]": {
"editor.defaultFormatter": "ms-python.black-formatter",
"editor.tabSize": 4,
"editor.formatOnSave": true
},
"[php]": {
"editor.defaultFormatter": "bmewburn.vscode-intelephense-client",
"editor.tabSize": 4
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.tabSize": 2
},
"[markdown]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.wordWrap": "on",
"files.trimTrailingWhitespace": false
}
}
언어별로 포매터를 명시하는 게 포인트다. defaultFormatter를 지정하지 않으면, VS Code가 적절한 포매터를 찾지 못해 "포매터를 선택하세요" 팝업이 계속 뜬다. 언어별로 한 번 고정해두면 그 후로는 신경 안 써도 된다.
Markdown은 trimTrailingWhitespace: false로 두는 게 맞다. 마크다운에서 줄 끝 공백 두 개는 <br> 역할을 하므로, 자동 트림이 의도치 않게 줄바꿈을 날린다.
바로 복붙 가능한 전체 settings.json
{
"editor.fontFamily": "'JetBrains Mono', 'Fira Code', Menlo, monospace",
"editor.fontSize": 14,
"editor.lineHeight": 1.7,
"editor.fontLigatures": true,
"editor.tabSize": 2,
"editor.insertSpaces": true,
"editor.detectIndentation": false,
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.organizeImports": "explicit"
},
"editor.minimap.enabled": false,
"editor.wordWrap": "off",
"editor.rulers": [100],
"editor.cursorBlinking": "smooth",
"editor.smoothScrolling": true,
"files.trimTrailingWhitespace": true,
"files.insertFinalNewline": true,
"files.trimFinalNewlines": true,
"files.encoding": "utf8",
"files.eol": "\n",
"files.autoSave": "onFocusChange",
"files.exclude": {
"**/.git": true,
"**/node_modules": true,
"**/.DS_Store": true
},
"workbench.iconTheme": "material-icon-theme",
"workbench.colorTheme": "Catppuccin Mocha",
"workbench.tree.indent": 14,
"explorer.compactFolders": false,
"terminal.integrated.fontSize": 13,
"terminal.integrated.fontFamily": "'JetBrains Mono', 'MesloLGS NF', monospace",
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[python]": {
"editor.defaultFormatter": "ms-python.black-formatter",
"editor.tabSize": 4
},
"[php]": {
"editor.defaultFormatter": "bmewburn.vscode-intelephense-client",
"editor.tabSize": 4
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[markdown]": {
"editor.wordWrap": "on",
"files.trimTrailingWhitespace": false
},
"eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact"],
"prettier.singleQuote": true,
"prettier.semi": false,
"prettier.tabWidth": 2,
"prettier.trailingComma": "es5",
"prettier.printWidth": 100,
"git.autofetch": true,
"git.confirmSync": false,
"diffEditor.ignoreTrimWhitespace": false,
"editor.stickyScroll.enabled": true,
"editor.stickyScroll.maxLineCount": 5,
"github.copilot.enable": {
"*": true
}
}
필수 확장 추천
코드 품질
| 확장 | 설명 | ID |
|---|---|---|
| ESLint | JS/TS 코드 규칙 검사 | dbaeumer.vscode-eslint |
| Prettier | 코드 포매터 | esbenp.prettier-vscode |
| Error Lens | 에러/경고를 코드 라인에 인라인으로 표시 | usernamehw.errorlens |
| SonarLint | 코드 품질/보안 취약점 정적 분석 | SonarSource.sonarlint-vscode |
Error Lens는 별도 설정 없이 설치만 해도 바로 체감 효과가 있다. 에러 메시지를 Problems 탭이 아닌 해당 라인 옆에 바로 표시해줘서, 파일을 왔다갔다하지 않아도 된다.
생산성
| 확장 | 설명 | ID |
|---|---|---|
| GitLens | Git blame, 히스토리, 브랜치 시각화 | eamodio.gitlens |
| Auto Rename Tag | HTML/JSX 태그 열기 이름 바꾸면 닫기도 자동 변경 | formulahendry.auto-rename-tag |
| Path Intellisense | 파일 경로 자동완성 | christian-kohler.path-intellisense |
| Better Comments | TODO, FIXME, 주석 색상 구분 | aaron-bond.better-comments |
| Import Cost | import하는 패키지 용량을 에디터에 표시 | wix.vscode-import-cost |
GitLens는 무료 플랜으로도 대부분 기능을 쓸 수 있다. git blame이 각 라인 끝에 인라인으로 표시되고, 파일 히스토리도 사이드바에서 바로 확인 가능하다.
테마/UI
| 확장 | 설명 | ID |
|---|---|---|
| Catppuccin for VS Code | 눈에 부드러운 파스텔 다크 테마 | Catppuccin.catppuccin-vsc |
| One Dark Pro | 대중적인 다크 테마 | zhuangtongfa.material-theme |
| Material Icon Theme | 파일/폴더 아이콘 세트 | PKief.material-icon-theme |
테마는 취향 영역이지만, Material Icon Theme는 취향과 관계없이 파일 탐색 효율을 올려준다. index.ts와 index.css를 아이콘만 봐도 구분할 수 있다.
언어별
| 확장 | 언어 | ID |
|---|---|---|
| Volar | Vue 3 | Vue.volar |
| Pylance | Python 타입 검사/자동완성 | ms-python.vscode-pylance |
| Black Formatter | Python 포매터 | ms-python.black-formatter |
| PHP Intelephense | PHP 자동완성/타입 분석 | bmewburn.vscode-intelephense-client |
| Tailwind CSS IntelliSense | Tailwind 클래스 자동완성 | bradlc.vscode-tailwindcss |
Vue를 쓴다면 Vetur 대신 Volar를 써야 한다. Vue 3 + TypeScript 조합에서 Volar가 타입 추론이 훨씬 정확하다.
AI 코딩 도구
2025-2026년 기준, AI 보조 도구는 선택이 아니라 기본 세팅이 됐다. 쓰냐 안 쓰냐가 아니라, 어떤 걸 쓰냐의 문제다.
| 도구 | 유형 | 특징 | 가격 |
|---|---|---|---|
| GitHub Copilot | VS Code 확장 | MS/GitHub 공식, 코드 완성 + Chat, GPT-4o/Claude 모델 선택 가능 | $10/월 |
| Cursor | VS Code fork | Composer(멀티파일 편집), Agent 모드, VS Code 설정/확장 호환 | $20/월 |
| Continue | VS Code 확장 | 오픈소스, 로컬 모델(Ollama) 지원, 자체 서버 가능 | 무료 |
| Claude Code | CLI 도구 | Anthropic 공식 CLI, 터미널에서 코드베이스 전체 이해/편집 | 사용량 과금 |
GitHub Copilot은 VS Code에 가장 자연스럽게 통합된다. 인라인 코드 완성 외에 Chat 패널, 인라인 편집(Cmd+I), 커밋 메시지 자동 생성까지 지원한다. settings.json에서 언어별 on/off가 가능하다.
{
"github.copilot.enable": {
"*": true,
"markdown": false,
"plaintext": false
}
}
Cursor는 VS Code fork라서 기존 VS Code 확장과 settings.json을 그대로 가져올 수 있다. Composer 기능이 핵심으로, 프롬프트 하나로 여러 파일을 동시에 생성하거나 수정한다. AI 의존도가 높은 프로젝트라면 VS Code 대신 Cursor를 메인 에디터로 쓰는 팀도 늘고 있다.
Continue는 오픈소스라 로컬 Ollama 모델과 연결하면 코드가 외부로 나가지 않는다. 보안 정책이 엄격한 환경에서 실용적인 선택이다. VS Code Marketplace에서 설치하면 된다 (continue.continue).
Claude Code는 에디터 확장이 아닌 터미널 CLI다. VS Code의 통합 터미널에서 실행하고, 레포지토리 전체를 컨텍스트로 이해한 뒤 파일을 직접 수정한다. 에디터 안에서 쓰는 AI와 달리, 여러 파일에 걸친 리팩토링이나 버그 추적에서 강점이 있다.
어떤 도구가 맞는지는 사람마다 다르다. Copilot 인라인 완성이 충분하다면 굳이 바꿀 필요 없다. 복잡한 피처를 처음부터 짜는 일이 많다면 Cursor의 Composer가 체감 차이가 크다.
Profile — 언어/프로젝트별 설정 분리
VS Code 1.75에서 정식 출시된 기능이다. 설정, 확장, 단축키, UI 상태를 묶어 "Profile"로 저장하고 전환할 수 있다.
Cmd+Shift+P → "Profiles: Create Profile"
활용 예시:
| 프로필 | 활성 확장 | settings.json 차이점 |
|---|---|---|
| Frontend | ESLint, Prettier, Volar, Tailwind IntelliSense | tabSize: 2, Catppuccin 테마 |
| Python | Pylance, Black Formatter, Jupyter | tabSize: 4, One Dark Pro 테마 |
| Writing | Markdown All in One, Spell Check | wordWrap: on, 밝은 테마 |
프로필 간 전환은 좌하단 상태바 계정 아이콘 옆에서 한다. 프로젝트를 열 때 특정 프로필을 자동으로 연결할 수도 있다.
Python 코드 짤 때마다 tabSize를 4로 바꾸고, 프론트엔드 넘어갈 때 다시 2로 바꾸는 반복이 있었다면 프로필로 해결된다.
workspace 설정 — 팀 프로젝트 설정 공유
.vscode/settings.json
프로젝트 루트의 .vscode/settings.json은 User settings보다 우선한다. 팀원 모두에게 동일한 설정을 강제할 때 쓴다.
// .vscode/settings.json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"editor.tabSize": 2,
"files.eol": "\n",
"typescript.tsdk": "node_modules/typescript/lib"
}
개인 취향 (테마, 폰트, 미니맵 등)은 여기에 넣지 않는다. 팀 전체에 영향을 주는 설정만 넣는다.
.vscode/extensions.json
프로젝트에서 권장하는 확장 목록이다. VS Code에서 이 파일이 있으면 "이 프로젝트에서 권장하는 확장을 설치하시겠습니까?"라고 물어본다.
// .vscode/extensions.json
{
"recommendations": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"usernamehw.errorlens",
"eamodio.gitlens",
"PKief.material-icon-theme"
]
}
신규 팀원이 프로젝트를 clone했을 때 확장 설치 안내를 자동으로 받는다. 팀 온보딩에서 "VS Code 확장 뭐 깔아요?" 질문이 없어진다.
설정 범위 비교
| 범위 | 파일 위치 | 우선순위 | 용도 |
|---|---|---|---|
| User | ~/.config/Code/settings.json |
낮음 | 전체 기본값, 개인 취향 |
| Workspace | .vscode/settings.json |
중간 | 프로젝트별 규칙, 팀 공유 |
| Folder | .vscode/settings.json (멀티루트) |
높음 | 멀티루트 워크스페이스의 폴더별 설정 |
숫자가 아닌 "낮음/높음"이 우선순위를 뜻한다. 동일한 키가 있으면 높은 쪽이 이긴다. Workspace가 User보다 높으므로, 팀 프로젝트에서 개인 User 설정을 덮어쓸 수 있다.
launch.json 디버깅 설정
console.log를 심고 제거하는 사이클을 끊는 게 목표다. 브레이크포인트를 걸면 실행 중 변수값을 그대로 볼 수 있고, 콜스택을 타고 올라갈 수 있다.
Node.js 디버깅
// .vscode/launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "Node: 현재 파일 실행",
"type": "node",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"skipFiles": ["<node_internals>/**"]
},
{
"name": "Node: npm start",
"type": "node",
"request": "launch",
"runtimeExecutable": "npm",
"runtimeArgs": ["run", "start"],
"console": "integratedTerminal",
"skipFiles": ["<node_internals>/**"]
},
{
"name": "Node: 현재 파일 (TypeScript)",
"type": "node",
"request": "launch",
"runtimeExecutable": "npx",
"runtimeArgs": ["ts-node", "${file}"],
"console": "integratedTerminal",
"skipFiles": ["<node_internals>/**"]
},
{
"name": "Node: 프로세스에 연결",
"type": "node",
"request": "attach",
"port": 9229,
"restart": true,
"skipFiles": ["<node_internals>/**"]
}
]
}
skipFiles: ["<node_internals>/**"]는 중요하다. 이게 없으면 Step Into 시 Node.js 내부 소스까지 들어가서 길을 잃는다.
"프로세스에 연결"은 이미 --inspect 옵션으로 실행 중인 서버에 붙을 때 쓴다.
node --inspect src/server.js
# 또는
node --inspect-brk src/server.js # 첫 줄에서 즉시 멈춤
Chrome 디버깅 (React/Next.js)
{
"name": "Chrome: localhost:3000",
"type": "chrome",
"request": "launch",
"url": "http://localhost:3000",
"webRoot": "${workspaceFolder}/src",
"sourceMapPathOverrides": {
"webpack:///src/*": "${webRoot}/*"
}
},
{
"name": "Chrome: 현재 열린 파일",
"type": "chrome",
"request": "launch",
"file": "${file}"
},
{
"name": "Chrome: 실행 중인 브라우저에 연결",
"type": "chrome",
"request": "attach",
"port": 9222,
"webRoot": "${workspaceFolder}/src"
}
React 앱을 디버깅할 때는 개발 서버(npm run dev)를 먼저 띄우고, "Chrome: localhost:3000" 구성으로 실행한다. VS Code가 Chrome을 열고, 소스맵을 통해 원본 JSX/TSX 파일에 브레이크포인트를 걸 수 있다.
compound 구성 — 서버+클라이언트 동시 디버깅
{
"version": "0.2.0",
"configurations": [
{
"name": "Server",
"type": "node",
"request": "launch",
"program": "${workspaceFolder}/server/index.js",
"skipFiles": ["<node_internals>/**"]
},
{
"name": "Client",
"type": "chrome",
"request": "launch",
"url": "http://localhost:3000",
"webRoot": "${workspaceFolder}/client/src"
}
],
"compounds": [
{
"name": "Full Stack",
"configurations": ["Server", "Client"]
}
]
}
"Full Stack" 하나를 실행하면 Node 서버와 Chrome이 동시에 뜨고, 양쪽 모두 브레이크포인트를 걸 수 있다.
자주 쓰는 단축키 모음
| 기능 | Mac | Windows |
|---|---|---|
| 명령 팔레트 | Cmd+Shift+P |
Ctrl+Shift+P |
| 파일 빠른 열기 | Cmd+P |
Ctrl+P |
| 사이드바 토글 | Cmd+B |
Ctrl+B |
| 통합 터미널 | `Ctrl+`` | `Ctrl+`` |
| 다중 커서 (클릭) | Opt+클릭 |
Alt+클릭 |
| 다중 커서 (같은 단어) | Cmd+D |
Ctrl+D |
| 전체 선택 (같은 단어) | Cmd+Shift+L |
Ctrl+Shift+L |
| 라인 이동 | Opt+↑/↓ |
Alt+↑/↓ |
| 라인 복사 | Opt+Shift+↑/↓ |
Alt+Shift+↑/↓ |
| 라인 삭제 | Cmd+Shift+K |
Ctrl+Shift+K |
| 전체 파일에서 찾기/바꾸기 | Cmd+Shift+H |
Ctrl+Shift+H |
| 심볼로 이동 | Cmd+Shift+O |
Ctrl+Shift+O |
| 정의로 이동 | F12 |
F12 |
| 참조 찾기 | Shift+F12 |
Shift+F12 |
| 인라인 힌트 토글 | Cmd+Opt+H |
Ctrl+Alt+H |
| 디버그 시작 | F5 |
F5 |
| 브레이크포인트 토글 | F9 |
F9 |
| Step Over | F10 |
F10 |
| Step Into | F11 |
F11 |
| Step Out | Shift+F11 |
Shift+F11 |
Cmd+D는 자주 쓰는 것 중 하나다. 같은 변수명을 여러 곳에서 동시에 바꿀 때, 하나 선택하고 Cmd+D를 반복하면 차례로 추가 선택된다. 정규식 없이도 다중 편집이 된다.
삽질 기록
Prettier vs ESLint 충돌
가장 흔한 문제다. ESLint의 포매팅 규칙(들여쓰기, 따옴표 등)과 Prettier 규칙이 다르면, 저장할 때마다 포매팅이 왔다갔다한다.
해결책은 두 가지다.
첫 번째: eslint-config-prettier를 사용해 ESLint에서 포매팅 규칙을 끄고 Prettier에 위임한다.
npm install -D eslint-config-prettier
// .eslintrc
{
"extends": ["eslint:recommended", "prettier"]
}
두 번째: eslint-plugin-prettier를 써서 Prettier를 ESLint 규칙으로 실행한다. 요즘은 첫 번째 방법이 더 권장된다. 레이어를 분리하는 게 관리가 쉽다.
formatOnSave가 안 먹힘
증상: 저장해도 포매팅이 안 됨. 주로 세 가지 원인이다.
1. defaultFormatter가 지정 안 됨
언어별 defaultFormatter를 지정하지 않으면, 포매터를 찾지 못하고 조용히 넘어간다. 한 번이라도 "포매터를 선택하세요" 팝업이 떴다면 이 케이스다. 위의 언어별 설정 섹션처럼 명시적으로 지정한다.
2. Prettier 설정 파일 충돌.prettierrc, prettier.config.js, package.json의 prettier 키가 동시에 있으면 충돌한다. 하나만 남긴다.
3. ESLint 에러가 있는 상태
ESLint 에러가 있는 파일은 formatOnSave가 동작하지 않는 경우가 있다. 에러를 먼저 해결하거나, "editor.formatOnSaveMode": "modificationsIfAvailable"로 변경한다.
확장 충돌
Vetur와 Volar를 동시에 설치하면 Vue 파일에서 타입 추론이 꼬인다. Vue 3 프로젝트라면 Vetur를 비활성화하고 Volar만 쓴다.
유사하게 Python 확장이 여러 개 (Pylance + Jedi + 구버전 Python) 동시에 깔려있으면 자동완성이 겹쳐서 느려진다. 하나만 남긴다.
확장 문제를 의심할 때는 Cmd+Shift+P → "Extensions: Disable All Installed Extensions for this Workspace"로 전체 비활성화 후 하나씩 켜면서 범인을 찾는다.
workspace settings가 적용 안 됨
.vscode/settings.json 파일이 있는데 설정이 안 먹을 때. 파일 열기 방식 문제인 경우가 많다. VS Code에서 폴더를 열 때 (File → Open Folder) .vscode 폴더가 포함된 프로젝트 루트를 열어야 한다. 파일을 직접 드래그로 열면 workspace context가 없어서 .vscode/settings.json을 읽지 않는다.
마무리
설정 하나하나는 작아 보인다. formatOnSave 하나, fontLigatures 하나. 그런데 하루에 수백 번 저장하고 수천 줄을 읽는 에디터에서, 이 작은 설정들이 누적되면 체감이 다르다.
모든 설정을 한꺼번에 바꿀 필요는 없다. 오늘 formatOnSave: true 하나만 켜봐도 된다. 저장할 때마다 코드가 정리되는 걸 보고 나면, 다음에 무엇을 더 설정할지 자연스럽게 궁금해진다.
launch.json은 좀 더 시간이 필요하다. 처음 브레이크포인트로 변수값을 살펴보는 순간, console.log로 돌아가기가 어려워진다.
에디터: VS Code 1.90+
관련 문서: VS Code 공식 문서 - settings.json
AI 도구: GitHub Copilot | Cursor | Continue | Claude Code
'개발 팁' 카테고리의 다른 글
| 개발 브랜치 전략 완전 정복 — Git Flow, GitHub Flow, Trunk-based 비교 (0) | 2026.03.19 |
|---|---|
| REST API 설계 원칙 — 네이밍부터 버전 관리까지 (0) | 2026.03.19 |
| CSS Flexbox & Grid 실전 치트시트 — 자주 쓰는 패턴 총정리 (0) | 2026.03.19 |
| 웹 보안 기초 — XSS, CSRF, SQL Injection 방어 실전 (1) | 2026.03.19 |
| Docker로 개발 환경 통일하기 — '내 컴퓨터에선 되는데'를 없애는 법 (0) | 2026.03.18 |