<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Anjaneyulu</title>
    <description>The latest articles on DEV Community by Anjaneyulu (@anjioo7).</description>
    <link>https://dev.to/anjioo7</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4211994%2Ffccf7433-9c02-4792-9c01-509302435297.jpeg</url>
      <title>DEV Community: Anjaneyulu</title>
      <link>https://dev.to/anjioo7</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/anjioo7"/>
    <language>en</language>
    <item>
      <title>Why JavaScript Silently Changes Large JSON Numbers</title>
      <dc:creator>Anjaneyulu</dc:creator>
      <pubDate>Thu, 29 Oct 2026 06:01:00 +0000</pubDate>
      <link>https://dev.to/anjioo7/why-javascript-silently-changes-large-json-numbers-2cfh</link>
      <guid>https://dev.to/anjioo7/why-javascript-silently-changes-large-json-numbers-2cfh</guid>
      <description>&lt;p&gt;JavaScript can silently change large integers when it parses perfectly valid JSON. That matters for database IDs, API responses, and the tools you use to look at them. Run this in Node or a browser console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{"orderId": 9007199254740993, "amount": 1.50}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orderId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;9007199254740992
{"orderId":9007199254740992,"amount":1.5}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The ID is now off by one. There's no exception and no warning, and the result is still valid JSON. If you pass that ID to the next request, you're asking about a different order.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the digit goes
&lt;/h2&gt;

&lt;p&gt;JSON's grammar puts no limit on the size of a number. &lt;code&gt;JSON.parse&lt;/code&gt; does: it turns every number into a JavaScript &lt;code&gt;Number&lt;/code&gt;, which is an IEEE 754 double. A double has a 53-bit significand, so every integer up to 2^53 − 1 is stored exactly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MAX_SAFE_INTEGER&lt;/span&gt; &lt;span class="c1"&gt;// 9007199254740991&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Above that, only some integers fit. Between 2^53 and 2^54, a double can only hold even integers. &lt;code&gt;9007199254740993&lt;/code&gt; is odd, so it's rounded to a neighbour, &lt;code&gt;9007199254740992&lt;/code&gt;. The same thing happens to the literal in your source code, before any JSON is involved:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="mi"&gt;9007199254740993&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;9007199254740992&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Further up the range the gaps get wider, so the error gets bigger:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{"big": 12345678901234567890}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;big&lt;/span&gt; &lt;span class="c1"&gt;// 12345678901234567000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not every large integer changes: &lt;code&gt;9007199254740992&lt;/code&gt; is stored exactly. The trouble is that you can't tell from the parsed value whether it was rounded.&lt;/p&gt;

&lt;p&gt;Two related changes come from the same step. &lt;code&gt;1.50&lt;/code&gt; comes back as &lt;code&gt;1.5&lt;/code&gt;: the value is the same, but once it's a &lt;code&gt;Number&lt;/code&gt; there's no record of the trailing zero, so &lt;code&gt;JSON.stringify&lt;/code&gt; can't reproduce what you sent. And a number too large for a double becomes &lt;code&gt;Infinity&lt;/code&gt;, which JSON can't represent, so it's written out as &lt;code&gt;null&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{"d": 1e400}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// '{"d":null}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;JSON input&lt;/th&gt;
&lt;th&gt;After &lt;code&gt;JSON.parse&lt;/code&gt; + &lt;code&gt;JSON.stringify&lt;/code&gt;
&lt;/th&gt;
&lt;th&gt;What changed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;9007199254740993&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;9007199254740992&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Integer rounded&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;12345678901234567890&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;12345678901234567000&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Integer rounded&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1.50&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1.5&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Trailing zero dropped, value unchanged&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;1e400&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;null&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Too large: parsed as &lt;code&gt;Infinity&lt;/code&gt;, which JSON can't represent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;"9007199254740993"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;"9007199254740993"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Nothing: strings are kept as written&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;JSON itself doesn't limit number size. &lt;a href="https://www.rfc-editor.org/rfc/rfc8259#section-6" rel="noopener noreferrer"&gt;RFC 8259&lt;/a&gt; lets implementations set their own limits, and notes that integers between −(2^53 − 1) and 2^53 − 1 are the ones every implementation using double-precision numbers will agree on. The rounding comes from JavaScript's &lt;code&gt;Number&lt;/code&gt;, not from JSON.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's usually affected
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;64-bit integer IDs (&lt;code&gt;BIGINT&lt;/code&gt;) once their values pass 2^53, for example IDs generated from timestamps or random bits rather than a small counter.&lt;/li&gt;
&lt;li&gt;Snowflake-style IDs. X (Twitter) and Discord both use them, and both are far above 2^53.&lt;/li&gt;
&lt;li&gt;Numbers produced by backends with native 64-bit integers. The server serializes them correctly; the precision is lost only when JavaScript parses them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some APIs work around it. Discord's API reference says snowflakes are always returned as strings in the HTTP API, to avoid integer overflow in some languages. Twitter's API returned every ID twice, as the number &lt;code&gt;id&lt;/code&gt; and the string &lt;code&gt;id_str&lt;/code&gt;, and its documentation told JavaScript developers to use &lt;code&gt;id_str&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checking whether a value may have been rounded
&lt;/h2&gt;

&lt;p&gt;After parsing, &lt;code&gt;Number.isSafeInteger&lt;/code&gt; tells you whether an integer is inside the exact range:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isSafeInteger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orderId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// false&lt;/span&gt;
&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isSafeInteger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9007199254740991&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;false&lt;/code&gt; means the value &lt;em&gt;may&lt;/em&gt; have been rounded, not that it was: &lt;code&gt;9007199254740992&lt;/code&gt; is itself representable. To know for sure you need the original text, and newer runtimes give it to you. The reviver function passed to &lt;code&gt;JSON.parse&lt;/code&gt; now receives a third argument, &lt;code&gt;context&lt;/code&gt;, whose &lt;code&gt;source&lt;/code&gt; property is the number exactly as it was written. This comes from the TC39 proposal &lt;a href="https://github.com/tc39/proposal-json-parse-with-source" rel="noopener noreferrer"&gt;JSON.parse source text access&lt;/a&gt;, which is at Stage 4.&lt;/p&gt;

&lt;p&gt;This function finds integers outside JavaScript's safe integer range and shows their original text alongside the parsed value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;unsafeIntegers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;found&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isInteger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isSafeInteger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="nx"&gt;found&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;found&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;unsafeIntegers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{"id": 9007199254740993, "user": {"id": 42}, "ids": [12345678901234567890]}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output in Node 23:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[
  { key: 'id', source: '9007199254740993', parsed: 9007199254740992 },
  {
    key: '0',
    source: '12345678901234567890',
    parsed: 12345678901234567000
  }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second key is &lt;code&gt;'0'&lt;/code&gt; because the value is the first element of the &lt;code&gt;ids&lt;/code&gt; array. In runtimes that don't support the proposal, &lt;code&gt;context&lt;/code&gt; is &lt;code&gt;undefined&lt;/code&gt;, so check your target environments before relying on it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping large integers exact
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Send them as strings.&lt;/strong&gt; If you control the API, &lt;code&gt;"orderId": "9007199254740993"&lt;/code&gt; is the most robust fix, because it works in every client and language. This is what Discord does.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Convert them in a reviver.&lt;/strong&gt; This approach requires a runtime that supports JSON.parse source text access. With it, you can turn a specific field into a &lt;code&gt;BigInt&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{"orderId": 9007199254740993, "amount": 1.50}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;exact&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;orderId&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nc"&gt;BigInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;exact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orderId&lt;/span&gt; &lt;span class="c1"&gt;// 9007199254740993n&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;JSON.stringify&lt;/code&gt; refuses to write a &lt;code&gt;BigInt&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TypeError: Do not know how to serialize a BigInt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same proposal adds &lt;code&gt;JSON.rawJSON&lt;/code&gt;, which lets a replacer emit the digits unchanged:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;exact&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bigint&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rawJSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// '{"orderId":9007199254740993,"amount":1.5}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The ID survives the round trip and &lt;code&gt;amount&lt;/code&gt; still loses its trailing zero, because the reviver only touched &lt;code&gt;orderId&lt;/code&gt;. MDN lists &lt;code&gt;JSON.rawJSON&lt;/code&gt; as Baseline 2025, so it's available in current browsers but not in older ones.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use a parser built for it.&lt;/strong&gt; Libraries such as &lt;code&gt;json-bigint&lt;/code&gt; ("JSON.parse with bigints support") and &lt;code&gt;lossless-json&lt;/code&gt; ("Parse JSON without risk of losing numeric information") parse numbers without going through &lt;code&gt;Number&lt;/code&gt;. Check how each one represents numbers before choosing; their APIs differ.&lt;/p&gt;

&lt;h2&gt;
  
  
  A quick test for JSON tools
&lt;/h2&gt;

&lt;p&gt;Formatters, viewers and diff tools often call &lt;code&gt;JSON.parse&lt;/code&gt; and &lt;code&gt;JSON.stringify&lt;/code&gt; internally. To see whether one does, paste this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;9007199254740993&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"b"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;12345678901234567890&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"c"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"d"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1e400&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A tool built on the standard functions gives back:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"a"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;9007199254740992&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"b"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;12345678901234567000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"c"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"d"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the numeric text survives unchanged, that's a good sign the tool preserves number precision for this test. It doesn't guarantee every operation is lossless, so test the transformations you actually use.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse" rel="noopener noreferrer"&gt;MDN: JSON.parse()&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER" rel="noopener noreferrer"&gt;MDN: Number.MAX_SAFE_INTEGER&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/rawJSON" rel="noopener noreferrer"&gt;MDN: JSON.rawJSON()&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tc39.es/proposal-json-parse-with-source/" rel="noopener noreferrer"&gt;TC39: JSON.parse source text access&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;Written with AI assistance. Every code sample was run in Node 23, and the outputs shown are the actual results.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>json</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
