JSONC to JSON — Remove Comments from JSON
100% in your browser
Your data is never uploaded. All processing happens locally on your device.
Read privacy policy →Last updated: 2026-09-17
Paste JSONC (JSON with comments) to strip all // and /* */ comments and trailing commas, producing valid standard JSON. Comments inside string values are preserved. Everything runs locally in your browser.
What this tool does
Strips // line comments and /* */ block comments from JSONC input, removes trailing commas, and produces valid standard JSON. Comment-like text inside string values is preserved. The tool reports how many comments were removed so you can verify nothing important was lost.
Example
Input (tsconfig.json with comments):
{
// Compiler options
"compilerOptions": {
"target": "ES2020", // modern target
"strict": true,
/* module resolution */
"moduleResolution": "node"
}
}Output:
{
"compilerOptions": {
"target": "ES2020",
"strict": true,
"moduleResolution": "node"
}
}The tool reports “Removed 3 comments” so you know exactly what was stripped.
JSON vs JSONC vs JSON5
| Feature | JSON | JSONC | JSON5 |
|---|---|---|---|
| Comments | No | // and /* */ | // and /* */ |
| Trailing commas | No | Yes | Yes |
| Single quotes | No | No | Yes |
| Unquoted keys | No | No | Yes |
| Hex numbers | No | No | Yes |
| Multi-line strings | No | No | Yes |
| Used by | APIs, data interchange | tsconfig, VS Code, devcontainers | Config files, modern tooling |
Common JSONC files
- tsconfig.json — TypeScript compiler configuration
- jsconfig.json — JavaScript project configuration
- .vscode/settings.json — VS Code workspace settings
- devcontainer.json — VS Code dev container configuration
- .eslintrc (when using JSON format with comments)
- tslint.json — legacy TSLint rules, often annotated with rationale notes
- jsdoc.config.json — JSDoc configuration, which accepts comments describing each tag
All of these files use JSONC but tools that consume them have their own parsers. When you need to feed them to a standard JSON parser (like JSON.parse in Node.js or json.loads in Python), this tool strips the comments and trailing commas first. This matters in pipelines that diff a checked-in configuration against a generated baseline, in documentation generators that read the raw file, and in migration scripts that move settings between editors without carrying the explanatory comments along.
Converting tsconfig.json
tsconfig.json is the file people most often paste into this tool. TypeScript treats it as JSONC, so teams annotate every compiler option with a line comment explaining why it was chosen. A realistic project configuration might look like this:
{
// Root of the TypeScript project
// Keep this in sync with the build script in package.json
"compilerOptions": {
"target": "ES2021", // ship to modern browsers only
"lib": ["ES2021", "DOM", "DOM.Iterable"], // type the platform we run on
"module": "ESNext", // let the bundler handle module output
"moduleResolution": "Bundler", // matches Vite and Webpack 5
"strict": true, // turn on every strict flag
"noUncheckedIndexedAccess": true, // force undefined checks on array access
"noImplicitOverride": true, // require the override keyword
"exactOptionalPropertyTypes": true, // forbid explicit undefined on optionals
/* Project layout */
"rootDir": "src",
"outDir": "dist",
"resolveJsonModule": true, // import .json files as modules
"esModuleInterop": true, // allow default imports from CommonJS
"skipLibCheck": true, // faster builds, trust shipped types
"isolatedModules": true, // each file compiles independently
"verbatimModuleSyntax": true // preserve import / export shapes
},
"include": ["src"],
"exclude": [
"node_modules",
"dist",
"**/*.test.ts", // tested by vitest, not the compiler
"vite.config.ts" // built separately
]
}The trailing comma after "vite.config.ts" is legal in JSONC but would throw a parse error in JSON.parse. After conversion the output is plain JSON that any linter, schema validator, or runtime loader can read. The tool counts every // line comment and every /* */ block comment as one removal, so the report for this file reads “Removed 18 comments”.
Converting VS Code settings.json
Workspace settings live in .vscode/settings.json and are written as JSONC. Teams check them in with comments explaining which editor behaviour is enforced and why. A typical file:
{
// Formatting — enforced on save across the whole team
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.tabSize": 2, // matches the Prettier config
"editor.insertSpaces": true,
// TypeScript in the editor
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true,
"typescript.preferences.importModuleSpecifier": "relative",
"typescript.updateImportsOnFileMove": "always",
/* Files we never want opened by mistake */
"files.exclude": {
"**/.git": true,
"**/.DS_Store": true,
"**/node_modules": true,
"**/dist": true
},
"search.exclude": {
"**/package-lock.json": true, // too noisy in search results
"**/yarn.lock": true
}
}Pasting this into the tool removes every comment and the trailing comma after the last entry in files.exclude. The cleaned JSON can be loaded by a script that diffs workspace settings against a shared baseline, or by a CI check that forbids certain keys.
Converting devcontainer.json
A dev container definition in .devcontainer/devcontainer.json mixes VS Code extension settings, Docker build arguments, and lifecycle hooks, all annotated with comments. A representative file:
{
"name": "Node 20 service container",
// Pull the official image and add our toolchain on top
"image": "mcr.microsoft.com/devcontainers/javascript-node:20",
"features": {
"ghcr.io/devcontainers/features/docker-outside-of-docker:1": {}, // sibling Docker
"ghcr.io/devcontainers/features/github-cli:1": {} // gh inside the box
},
"forwardPorts": [3000, 5173], // app server and the dev server
"portsAttributes": {
"3000": { "label": "app", "onAutoForward": "notify" },
"5173": { "label": "vite", "onAutoForward": "openBrowser" }
},
/* Run after the container is created, once */
"postCreateCommand": "npm install",
// Run before each attach
"postStartCommand": "git config --global --add safe.directory ${containerWorkspaceFolder}",
"customizations": {
"vscode": {
"extensions": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"ms-python.python" // for the occasional script
],
"settings": {
"editor.formatOnSave": true
}
}
},
"remoteEnv": {
"LOCAL_WORKSPACE_FOLDER": "${localWorkspaceFolder}"
}
}Running this through the tool leaves the structure intact and strips the comments and the trailing comma after the last extension. The output is safe to hand to JSON.parse inside a Node script that generates container documentation from the definition.
How the parser distinguishes comments from strings
The conversion is a single left-to-right scan over the input. At every position the parser asks one question: are we currently inside a quoted string? The answer decides whether a / character starts a comment or is just text.
String mode. When the parser meets a double quote, it copies the quote and switches into string mode. It keeps copying characters until it hits the closing double quote. While inside the string,
//and/*are treated as ordinary characters and copied verbatim, so a value like"https://example.com"or"a /* b */"is preserved exactly. The parser also honours the backslash escape character: when it sees a backslash inside a string, it copies the backslash and the next character together, so an escaped quote\"does not end the string.Line comment mode. Outside a string, a
/immediately followed by another/starts a line comment. The parser skips forward until the next newline character, counts one comment, and resumes normal scanning on the newline.Block comment mode. Outside a string, a
/immediately followed by*starts a block comment. The parser skips forward until it finds*/, counts one comment, and continues after the closing slash. Block comments can span many lines.Default. Any other character is copied to the output unchanged.
After the scan, two cleanup passes run on the result. A regular expression removes a comma that appears immediately before a closing } or ], allowing whitespace between them. Then each line is trimmed of trailing whitespace, and lines that are empty after trimming are dropped, so removing a comment does not leave a blank gap. Finally the cleaned text is passed to JSON.parse; if it succeeds the output is returned, and if it fails the cleaned text is still returned alongside the parse error.
Common mistakes when stripping comments
- Using a naive regex. A pattern like
//.*removes comment markers that appear inside string values, corrupting URLs such as"https://example.com". The character-by-character scan avoids this because it never treats comment markers as comments while inside a quoted string. - Forgetting block comments. Tools that only handle
//leave/* */blocks in the output, which still failJSON.parse. This tool handles both forms and counts each block comment as one removal. - Ignoring escape sequences. A string that contains
\"ends later than a scan for the next"would predict. The parser consumes the character after every backslash so an escaped quote does not close the string prematurely. - Leaving trailing commas. Stripping a comment that sat after the last array element can leave a comma before
], which is invalid JSON. The trailing-comma pass removes exactly these commas. - Assuming single quotes are converted. JSONC does not allow single-quoted strings; that is a JSON5 feature. Input with single quotes will fail validation after conversion, and the error is returned with the cleaned text.
- Expecting unquoted keys to work. Unquoted object keys are also JSON5, not JSONC. The tool does not add quotes around them, so a file using them will still fail
JSON.parse. - Counting comment lines instead of comments. A multi-line block comment is one comment, not several. The reported number reflects comment markers removed, not the number of lines they occupied.
- Trusting the output blindly when validation fails. When
JSON.parserejects the cleaned text, the tool returns it anyway with the error. Read the error and fix the remaining syntax, usually a JSON5 feature the converter does not handle.
Reading the reported comment count
After conversion the tool prints “Removed N comments” where N is the number of comment markers stripped from the input. Each // line comment counts as one, regardless of how many lines it occupies, and each /* */ block comment also counts as one, even when it spans dozens of lines. A file with five short inline notes and one large header block therefore reports six removals.
The count is computed during the scan, before the trailing-comma and empty-line cleanup passes run, so it reflects exactly what was removed from the source rather than what the finished output looks like. If the scan finishes but JSON.parse then rejects the cleaned text, the count is still reported alongside the error, because the comments were genuinely removed even though leftover syntax prevented validation. Comparing the reported number against the comments you expected to see is a quick way to confirm the conversion matched your intent before you paste the output anywhere.
Limitations and what this tool does not do
The converter targets JSONC only. It strips comments and trailing commas and then validates with JSON.parse, so anything else that standard JSON rejects will still fail. Single-quoted strings, unquoted object keys, hexadecimal literals, leading decimal points, and multi-line template strings are JSON5 features and are not transformed. If your file uses them, the cleaned text is returned with the parse error so you can decide whether to rewrite those parts by hand or switch to a JSON5 parser.
The tool does not reformat, minify, or re-indent the output. It preserves the indentation of the original lines and only trims trailing whitespace from each line. Run a formatter or minifier afterwards if you want a different layout. Nested block comments are not supported because JSONC itself does not allow them; a /* */ block ends at the first */, and any later */ becomes ordinary text that will likely break validation. Finally, the converter does not interpret comment directives such as @ts-expect-error — those are comments, so they are removed along with everything else between the markers. The entire conversion runs locally inside your browser; nothing is uploaded, which makes the tool safe for proprietary configuration files.
Do it in code
Node.js (strip-json-comments):
const stripJsonComments = require('strip-json-comments');
const cleanJson = stripJsonComments(jsoncString);
const config = JSON.parse(cleanJson);Python:
import re, json
def strip_comments(jsonc):
# Remove // line comments (not inside strings)
jsonc = re.sub(r'//.*?$', '', jsonc, flags=re.MULTILINE)
# Remove /* */ block comments
jsonc = re.sub(r'/\*.*?\*/', '', jsonc, flags=re.DOTALL)
# Remove trailing commas
jsonc = re.sub(r',(\s*[}\]])', r'\1', jsonc)
return json.loads(jsonc)CLI (jq with strip-json-comments):
npx strip-json-comments tsconfig.json | jq '.'Edge cases handled
- Comments inside string values are preserved — the parser tracks string boundaries.
- Both
//line comments and/* */block comments are stripped. - Trailing commas before
}or]are removed. - Lines that become empty after comment removal are filtered out.
- The cleaned output is validated with
JSON.parseto ensure it is valid JSON. - If validation fails, the cleaned output is still returned with an error message so you can fix remaining issues manually.