How to minify inline json to reduce javascript bundle size
- Step 1Find the heavy JSON in your bundle — Run a bundle analysis —
npx webpack-bundle-analyzerfor webpack,ANALYZE=true next buildfor Next.js, orrollup-plugin-visualizerfor Rollup. Translation files, icon sets, and country/currency/timezone lists are the usual large inline-JSON suspects. - Step 2Extract the JSON value — Copy the JSON out of the
const, the string literal, or the.jsonfile. Paste it into the tool above, or drop the.jsonfile directly. The data is parsed locally in your browser. - Step 3Decide on null removal — Leave Also remove null values off to measure whitespace-only savings. Turn it on for seed/fixture data where
nullmeans 'no value' and your code never checks for the field's presence — it permanently drops those properties and null array entries. - Step 4Minify and read the impact — Click Minify JSON and note
inputBytes → outputBytes · N% smaller. Remember this is the pre-Gzip saving. Most CDNs Brotli-compress JS, after which the marginal gain from whitespace removal is small — the percentage tells you whether minification is the right lever or whether you should code-split instead. - Step 5Prefer a .json import over an inline string — If the JSON lives in a template literal or string, move it to a
.jsonfile andimport data from './data.json'. Bundlers process JSON imports through their JSON loader and can tree-shake/code-split them — far more effective than minifying a string the bundler treats as opaque text. - Step 6Code-split JSON used on only some routes — For data needed on one page, use a dynamic import:
const data = await import('./large-data.json'). The bundler emits a separate chunk loaded only when that route runs. Deferring the bytes beats shrinking them. Use Copy/Download here to grab the minified file for the split module.
How bundlers treat your JSON
Whether minification helps depends on how the JSON enters the bundle. Behaviour reflects webpack 5 / Rollup / Next.js defaults at time of writing.
| How the JSON is held | Does the bundler minify it? | Best action |
|---|---|---|
Object literal const data = { ... } | Yes — Terser collapses the literal syntax | Already handled; minifying the source barely helps the shipped bundle |
String literal const data = '{ ... }' | No — treated as opaque text, shipped verbatim | Minify the string here, or move it to a .json import |
import data from './data.json' | Parsed by the JSON loader, then Terser minifies the result | Already compact; code-split if large |
Dynamic await import('./data.json') | Code-split into a separate chunk | Best for route-specific data; minify the chunk's source for a small extra win |
Bundle-size levers, ordered by impact
Minification is the smallest lever once Gzip/Brotli is in play. Use this tool to measure it; reach for the others for real wins.
| Lever | Typical effect | Notes |
|---|---|---|
| Code-split / lazy-load the JSON | Removes it from the initial bundle entirely | The biggest win for route- or feature-specific data |
| Brotli / Gzip (host or CDN) | 70–90% on the wire | Applied to JS bundles by default on most platforms |
| Drop unused entries / fields | Varies; large for wide lookup tables | Prune with json-key-filter before shipping |
| Minify (remove whitespace) | 10–30% pre-Gzip, marginal post-Gzip | Free for string literals the bundler won't touch |
Cookbook
Real inline-bundle JSON, before and after. Byte counts are illustrative UTF-8 sizes and are the pre-compression figures.
i18n catalog held as a string literal
ExampleA translation file stored as a template-literal string is shipped verbatim — Terser never reformats it. Minifying recovers the indentation bytes the bundler kept.
Before (pretty, 286 bytes):
{
"nav": {
"home": "Home",
"about": "About",
"contact": "Contact"
}
}
After (minified, 198 bytes · 31% smaller):
{"nav":{"home":"Home","about":"About","contact":"Contact"}}Seed data padded with null optionals
ExampleHand-written fixture records often include every optional field as null. With Also remove null values on, those fields vanish — only safe if your code never branches on the field being present.
Before:
{"products":[{"id":1,"name":"A","sku":null,"image":null}]}
After (removeNulls on):
{"products":[{"id":1,"name":"A"}]}
Note: the shipped objects no longer have sku/image keys.Trailing comma in a hand-maintained data file
ExampleEditing a data file by hand and leaving a trailing comma is a classic build breaker. The tool parses first, so it catches the error before your build does.
Input (trailing comma):
{"icons":["home","user","gear",]}
Result: parse error — "Unexpected token ] in JSON".
Fix the source, or clean non-standard JSON with json-format-fixer,
then minify the result for the bundle.Duplicate key in a merged config
ExampleWhen two config fragments were merged by hand, a repeated key collapses to the last value. Worth knowing if a default 'disappears' after minifying.
Input:
{"env":"dev","env":"prod","debug":false}
Minified:
{"env":"prod","debug":false}
The first env:dev was dropped — the source had a duplicate key.Number normalisation in a units table
ExampleLookup tables of constants often mix number forms. Minification canonicalises them; values stay numerically identical.
Before:
{"km":1.0,"mile":1.60934,"light_year":9.461e15}
Minified:
{"km":1,"mile":1.60934,"light_year":9461000000000000}
Values unchanged; only the textual form differs.Errors and edge cases
Real errors and silent failures sourced from each platform's own documentation. Match the wording to the row, fix what the row says to fix.
Minifying source that Terser already minifies
ExpectedIf your JSON is an object literal or a standard .json import, the bundler's Terser/JSON loader already produces compact output. Minifying the source file shows a saving here but barely changes the shipped bundle — the build was going to compact it anyway. The real win for those cases is code-splitting, not minification.
Comments or trailing commas in the data file
Parse errorStrict JSON forbids comments and trailing commas, but hand-maintained data files (and JSON5/JSONC) often have them. The tool rejects such input. Repair it with json-format-fixer first, then minify — the minifier only accepts valid JSON so it never silently mangles a malformed source.
Large integers in id/config data
Precision lossNumbers above 2^53 lose precision on the round-trip. If your seed data carries 64-bit IDs or large fixed-point values as numbers, store them as strings before minifying. This is a JavaScript number limitation, not a bundle-specific one.
Marginal saving after Brotli/Gzip
ExpectedWhitespace removal shows 10–30% pre-compression, but JS bundles are Brotli- or Gzip-compressed by most hosts, after which the additional gain from minified-vs-pretty JSON is small (compression already eliminates repeated whitespace). Use the measured percentage to decide whether minification is worth a build step or whether code-splitting is the better investment.
Removing nulls changes the shipped shape
By designAlso remove null values deletes null properties and null array elements. If any component checks 'field' in obj or relies on the field existing (even as null), removing it changes runtime behaviour, not just bytes. Keep the option off unless absent and null are equivalent everywhere the data is read.
NDJSON / multiple top-level objects
Parse errorSome build inputs (e.g. a .jsonl of records) contain many top-level objects. The tool parses the whole input as one JSON value and rejects multiple top-level objects. Wrap the records in a single array, or minify line by line. The .ndjson/.jsonl extensions are accepted only when the file is one valid JSON value.
Free-tier 2 MB limit on a large catalog
Upgrade requiredFree accounts accept up to 2 MB. A large translation catalog or icon manifest can exceed that; Pro raises the limit to 100 MB. A 2 MB inline JSON file is itself a strong signal to code-split or lazy-load rather than ship it in the initial bundle at all.
Non-ASCII strings in i18n data
PreservedTranslation catalogs are full of accented and CJK characters. JSON.stringify keeps them as literal UTF-8 rather than \uXXXX escapes, and byte counts are measured in UTF-8, so the reported size matches what actually ships. Minification never garbles non-ASCII text.
Frequently asked questions
Does webpack or Rollup already minify JSON I import?
For a standard import data from './data.json', yes — the bundler's JSON loader parses it and Terser (webpack) or the equivalent minifies the resulting object literal. The gap is JSON held as a string literal or inside a template literal: the bundler treats that as opaque text and ships it verbatim. Those are the cases where minifying here, or moving the data to a real .json import, actually changes the bundle.
How much bundle size can I save by minifying JSON?
Whitespace removal is 10–30% before compression. After Brotli/Gzip — which CDNs and hosts apply to JS by default — the extra gain over pretty JSON is small, because compression already collapses repeated whitespace. The high-impact moves are code-splitting (remove the JSON from the initial bundle) and dropping unused entries. Use this tool to measure the pre-compression delta and decide.
Should I inline JSON or import it from a file?
Import it from a .json file. Bundlers can then code-split it, lazy-load it on the routes that need it, and reliably minify it. Inlining large JSON as a string literal is the worst case — it cannot be split and is shipped exactly as written. Use this tool to compact the data before saving it as the .json you import.
Can it set indentation or sort keys for a diff-friendly source file?
No — this tool only minifies (plus an optional null removal). If you want a readable, diff-stable source file with consistent indentation and alphabetically sorted keys, use the json-prettifier, which exposes indent width and a sort-keys option. Prettify for the repo, minify for what ships.
Will minifying break tree-shaking of my data?
No — minification only changes formatting, not the data or how it is imported. Tree-shaking of JSON depends on how you reference it (named imports of an object's members are not tree-shaken the way ES exports are). The bigger lever is splitting large JSON into per-feature files so unused features' data is never loaded; minify each split file for a small extra saving.
Does removing nulls reduce my bundle meaningfully?
Only if your data is null-heavy. Seed and fixture records that pad every optional field with null shrink noticeably; dense lookup tables barely change. Measure both ways and compare the byte counts. Keep null removal on only if no code path depends on those fields existing.
Why did a value change form after minifying my constants table?
The round-trip canonicalises numbers (1.0 → 1, 9.461e15 → 9461000000000000) and collapses any duplicate keys to the last value. The numbers are equal; the text differs. If a duplicate key surprised you, your source genuinely had two entries with the same key and the last one won.
Can I run this in my build pipeline instead of by hand?
For a build step, a CLI like jq -c '.' data.json minifies in place and is easy to wire into a script. This tool is best for the exploratory step: measuring which assets are worth the effort and validating a hand-maintained data file before you automate. The output here is byte-equivalent to what JSON.stringify (and jq -c) produce.
Is the saving pre- or post-compression?
Pre-compression. The reported outputBytes is the raw minified size. Your CDN/host will then Brotli- or Gzip-compress the JS that contains it, so the real over-the-wire bytes are smaller still — and the marginal benefit of minified-vs-pretty mostly disappears under compression. The percentage here is the uncompressed lever.
What's the largest data file I can process?
2 MB on the free tier, 100 MB on Pro. If an inline JSON asset is approaching 2 MB it is a strong candidate for code-splitting or lazy-loading regardless of minification, since shipping that in the initial bundle hurts load time more than its whitespace does.
Does minified JSON parse faster at runtime?
Marginally — fewer characters for JSON.parse to walk on a .json import or runtime fetch. For inline object literals the parse is already part of evaluating the bundle, so the effect is negligible. The runtime win that matters is not loading the data at all until a route needs it.
Is my source data uploaded anywhere?
No. Parsing and minification run entirely in your browser. Proprietary lookup tables, pricing seeds and bundle assets never reach a JAD Apps server. Only an anonymous run counter (size and duration, no content) is recorded for signed-in users, and that is opt-out in account settings.
Privacy first
Conversion runs locally in your browser. No file is uploaded — only metadata counters are saved for signed-in dashboard stats.