Desk Clarity

A field guide to everyday digital problems.

Developer tools / Practical guide

JSON and Large Integer IDs: Preserve the Digits with a String Contract

Avoid rounding an identifier before serialization or converting every numeric field globally.

By ON Lab2 min readSources checked November 10, 2026 (KST)

For an integer identifier beyond the safe Number range, use a decimal string through the JSON contract. Turning a rounded Number into a string afterwards cannot restore lost digits. Native BigInt needs an explicit serialization decision.

Reproduce the boundary in a disposable fixture

Avoid rounding an identifier before serialization or converting every numeric field globally.

Use a new empty temporary directory for this fixture. The example creates only local test data. Commands marked with example.invalid do not identify a real service.

const assert = require('node:assert/strict');
const text = '12000000000002539';
const unsafe = Number(text);
assert.notEqual(String(unsafe),text);
const exact = BigInt(text);
assert.throws(() => JSON.stringify({id:exact}),TypeError);
const wire = JSON.stringify({id:exact.toString()});
const parsed = JSON.parse(wire);
assert.equal(parsed.id,text);
assert.equal(BigInt(parsed.id),exact);
console.log(wire);

Observed result

{"id":"12000000000002539"}

What the result means

The first conversion loses the original decimal value. BigInt constructed from the original string preserves it, but JSON.stringify does not encode that BigInt by default. The final object uses a string field with the exact original digits, so the receiving application can decide whether to keep it as an identifier or parse it into an exact integer type. The serialized type is part of the interface, not merely display formatting.

Choose the correction for your workflow

If you control both sides, specify which fields are decimal strings, their allowed signs and range, and whether leading zeros matter. Preserve the original text before any Number conversion. For an identifier, string comparison and storage may be enough; arithmetic may require a separate exact integer type. If a server already sends an oversized integer as a JSON numeric token, ordinary parsing can lose precision before application code sees it. Fix that server contract or choose a reviewed parser designed for the required numeric semantics.

Limits and the next check

This fixture addresses one identifier field; it does not transform every number into a string or install a global BigInt prototype serializer. A generic replacer needs a matching consumer contract, especially for nested objects and third-party schemas. Converting BigInt to Number is appropriate only after checking the accepted numeric range and precision needs. The guide does not claim that changing JSON formatting alone repairs values already rounded in a database driver or upstream service.

Related: Compare the related workflow boundary.

This isolated example was executed on macOS on November 10, 2026 (KST). Available tools: node v26.5.0, git git version 2.39.3 (Apple Git-145), npm 11.17.0, jq jq-1.7.1-apple. Shell fixtures use Bash and repository-path identity uses Python 3. This checks the illustrated contract, not your project, host service or every tool version.

Sources & further reading