Skip to content
Algorand Developer Portal

JSON BigInt

← Back to Common Utilities

This example demonstrates parsing and stringifying JSON with BigInt support for handling large numbers safely without precision loss. Topics covered:

  • parseJson() for parsing JSON strings with large numbers
  • Numbers > Number.MAX_SAFE_INTEGER are parsed as BigInt
  • Numbers <= Number.MAX_SAFE_INTEGER are parsed as regular numbers
  • stringifyJson() for serializing objects containing BigInt values
  • Round-trip preservation: stringifyJson(parseJson(str))
  • Comparison with native JSON.parse() showing precision loss
  • Algorand-relevant examples with microAlgo amounts
  • No LocalNet required

From the repository root:

Terminal window
cd examples
npm run example common/07-json-bigint.ts

View source on GitHub

07-json-bigint.ts
/**
* Example: JSON BigInt
*
* This example demonstrates parsing and stringifying JSON with BigInt support
* for handling large numbers safely without precision loss.
*
* Topics covered:
* - parseJson() for parsing JSON strings with large numbers
* - Numbers > Number.MAX_SAFE_INTEGER are parsed as BigInt
* - Numbers <= Number.MAX_SAFE_INTEGER are parsed as regular numbers
* - stringifyJson() for serializing objects containing BigInt values
* - Round-trip preservation: stringifyJson(parseJson(str))
* - Comparison with native JSON.parse() showing precision loss
* - Algorand-relevant examples with microAlgo amounts
*
* Prerequisites:
* - No LocalNet required
*/
import { parseJson, stringifyJson } from '@algorandfoundation/algokit-utils/common';
import { printError, printHeader, printInfo, printStep, printSuccess } from '../shared/utils.js';
// ============================================================================
// Main Example
// ============================================================================
printHeader('JSON BigInt Example');
// ============================================================================
// Step 1: Understanding the Problem - Native JSON.parse Precision Loss
// ============================================================================
printStep(1, 'The Problem: Native JSON.parse Precision Loss');
printInfo('JavaScript numbers have limited precision:');
printInfo(` Number.MAX_SAFE_INTEGER = ${Number.MAX_SAFE_INTEGER}`);
printInfo(` = 2^53 - 1 = 9,007,199,254,740,991`);
printInfo('');
// Demonstrate precision loss with native JSON.parse
const largeNumberJson = '{"amount": 9007199254740993}';
const parsedWithNative = JSON.parse(largeNumberJson);
const parsedWithBigInt = parseJson(largeNumberJson);
printInfo('Parsing JSON with a large number (9007199254740993):');
printInfo(` Original JSON: ${largeNumberJson}`);
printInfo(` Native JSON.parse: ${parsedWithNative.amount}`);
printInfo(` parseJson (BigInt): ${parsedWithBigInt.amount}`);
printInfo('');
// Show the precision loss
const originalValue = 9007199254740993n;
const nativeValue = parsedWithNative.amount as number;
const bigIntValue = parsedWithBigInt.amount as bigint;
if (BigInt(nativeValue) !== originalValue) {
printError(`Native JSON.parse LOST PRECISION: ${nativeValue} !== ${originalValue}`);
} else {
printInfo('Native JSON.parse preserved precision (unexpected)');
}
if (bigIntValue === originalValue) {
printSuccess(`parseJson preserved precision: ${bigIntValue} === ${originalValue}`);
} else {
printInfo('parseJson did not preserve precision (unexpected)');
}
// ============================================================================
// Step 2: parseJson() - Safe Numbers as Regular Numbers
// ============================================================================
printStep(2, 'parseJson() - Safe Numbers as Regular Numbers');
printInfo('Numbers <= MAX_SAFE_INTEGER are parsed as regular numbers:');
printInfo('');
const safeJson = '{"small": 42, "medium": 1000000, "maxSafe": 9007199254740991}';
const safeParsed = parseJson(safeJson);
printInfo(` JSON: ${safeJson}`);
printInfo('');
printInfo(' Parsed values:');
printInfo(` small: ${safeParsed.small} (type: ${typeof safeParsed.small})`);
printInfo(` medium: ${safeParsed.medium} (type: ${typeof safeParsed.medium})`);
printInfo(` maxSafe: ${safeParsed.maxSafe} (type: ${typeof safeParsed.maxSafe})`);
printInfo('');
// Verify they are regular numbers
const allNumbers = [safeParsed.small, safeParsed.medium, safeParsed.maxSafe].every(
(v: unknown) => typeof v === 'number',
);
if (allNumbers) {
printSuccess('All values <= MAX_SAFE_INTEGER are regular numbers');
}
// ============================================================================
// Step 3: parseJson() - Large Numbers as BigInt
// ============================================================================
printStep(3, 'parseJson() - Large Numbers as BigInt');
printInfo('Numbers > MAX_SAFE_INTEGER are parsed as BigInt:');
printInfo('');
const bigJson =
'{"justOver": 9007199254740992, "large": 18446744073709551615, "huge": 99999999999999999999}';
const bigParsed = parseJson(bigJson);
printInfo(` JSON: ${bigJson}`);
printInfo('');
printInfo(' Parsed values:');
printInfo(` justOver: ${bigParsed.justOver} (type: ${typeof bigParsed.justOver})`);
printInfo(` large: ${bigParsed.large} (type: ${typeof bigParsed.large})`);
printInfo(` huge: ${bigParsed.huge} (type: ${typeof bigParsed.huge})`);
printInfo('');
// Verify they are BigInts
const allBigInts = [bigParsed.justOver, bigParsed.large, bigParsed.huge].every(
(v: unknown) => typeof v === 'bigint',
);
if (allBigInts) {
printSuccess('All values > MAX_SAFE_INTEGER are BigInt');
}
// ============================================================================
// Step 4: stringifyJson() - Serializing BigInt Values
// ============================================================================
printStep(4, 'stringifyJson() - Serializing BigInt Values');
printInfo('Native JSON.stringify cannot handle BigInt:');
printInfo('');
const objWithBigInt = {
name: 'Large Amount',
value: 18446744073709551615n,
};
try {
JSON.stringify(objWithBigInt);
printInfo(' Native JSON.stringify succeeded (unexpected)');
} catch (e) {
printError(` Native JSON.stringify throws: ${(e as Error).message}`);
}
printInfo('');
printInfo('stringifyJson handles BigInt correctly:');
const stringified = stringifyJson(objWithBigInt);
printInfo(` Input: { name: 'Large Amount', value: 18446744073709551615n }`);
printInfo(` Output: ${stringified}`);
printSuccess('stringifyJson serializes BigInt values without error');
// ============================================================================
// Step 5: Round-trip Preservation
// ============================================================================
printStep(5, 'Round-trip Preservation');
printInfo('Round-trip: stringifyJson(parseJson(str)) preserves large numbers');
printInfo('');
const originalJson = '{"id":1,"balance":12345678901234567890,"active":true}';
printInfo(` Original: ${originalJson}`);
const parsed = parseJson(originalJson);
printInfo(` Parsed: balance = ${parsed.balance} (${typeof parsed.balance})`);
const roundTripped = stringifyJson(parsed);
printInfo(` Round-trip: ${roundTripped}`);
// Compare (note: order might differ)
const reparsed = parseJson(roundTripped);
if (
reparsed.balance === parsed.balance &&
reparsed.id === parsed.id &&
reparsed.active === parsed.active
) {
printSuccess('Round-trip preserves all values including large numbers');
}
// ============================================================================
// Step 6: Algorand-Relevant Examples - MicroAlgo Amounts
// ============================================================================
printStep(6, 'Algorand-Relevant Examples - MicroAlgo Amounts');
printInfo('Algorand uses microAlgos (1 Algo = 1,000,000 microAlgos)');
printInfo('Large Algo balances can exceed MAX_SAFE_INTEGER in microAlgos');
printInfo('');
// Example: 10 billion Algos in microAlgos = 10^16 microAlgos
// MAX_SAFE_INTEGER ~= 9 * 10^15, so amounts over ~9 million Algos need BigInt
printInfo('Example amounts:');
const algoAmounts = {
smallWallet: 1000000000, // 1,000 Algos
mediumWallet: 100000000000000, // 100M Algos
largeWallet: 10000000000000000, // 10B Algos (exceeds MAX_SAFE_INTEGER)
};
const algoJson = stringifyJson(algoAmounts);
printInfo(` JSON: ${algoJson}`);
printInfo('');
const algoParsed = parseJson(algoJson);
printInfo(' Parsed amounts:');
printInfo(
` smallWallet: ${algoParsed.smallWallet} microAlgos (${typeof algoParsed.smallWallet})`,
);
printInfo(` = ${Number(algoParsed.smallWallet) / 1_000_000} Algos`);
printInfo(
` mediumWallet: ${algoParsed.mediumWallet} microAlgos (${typeof algoParsed.mediumWallet})`,
);
printInfo(` = ${Number(algoParsed.mediumWallet) / 1_000_000} Algos`);
printInfo(
` largeWallet: ${algoParsed.largeWallet} microAlgos (${typeof algoParsed.largeWallet})`,
);
printInfo(` = ${Number(algoParsed.largeWallet) / 1_000_000} Algos`);
printInfo('');
// Demonstrate calculation with BigInt
printInfo('Safe arithmetic with BigInt:');
const largeBalance = algoParsed.largeWallet as bigint;
const transferAmount = 5000000000000000n; // 5B Algos
const remaining = largeBalance - transferAmount;
printInfo(` Balance: ${largeBalance} microAlgos`);
printInfo(` Transfer: ${transferAmount} microAlgos`);
printInfo(` Remaining: ${remaining} microAlgos`);
printSuccess('BigInt enables safe arithmetic with large Algorand amounts');
// ============================================================================
// Step 7: Comparing Native vs BigInt JSON Parsing
// ============================================================================
printStep(7, 'Side-by-Side Comparison');
printInfo('Comparing native JSON.parse vs parseJson:');
printInfo('');
const testCases = [
{ label: 'Safe integer', json: '{"value": 123456789}' },
{ label: 'MAX_SAFE_INTEGER', json: '{"value": 9007199254740991}' },
{ label: 'MAX_SAFE + 1', json: '{"value": 9007199254740992}' },
{ label: 'MAX_SAFE + 2', json: '{"value": 9007199254740993}' },
{ label: 'uint64 max', json: '{"value": 18446744073709551615}' },
];
printInfo(' Value | Native JSON.parse | parseJson (BigInt)');
printInfo(' -----------------------|--------------------------|--------------------');
for (const { label, json } of testCases) {
const native = JSON.parse(json).value;
const bigint = parseJson(json).value;
const nativeStr = String(native).padEnd(24);
const bigintStr = String(bigint).padEnd(20);
printInfo(` ${label.padEnd(20)} | ${nativeStr} | ${bigintStr}`);
}
printInfo('');
printSuccess('parseJson preserves precision for all values');
// ============================================================================
// Step 8: Pretty Printing with stringifyJson
// ============================================================================
printStep(8, 'Pretty Printing with stringifyJson');
printInfo('stringifyJson supports optional spacing for readability:');
printInfo('');
const complexObj = {
transaction: {
type: 'pay',
sender: 'ALGORAND...',
receiver: 'RECEIVER...',
amount: 18446744073709551615n,
fee: 1000n,
},
timestamp: 1704067200,
};
printInfo('Compact output (default):');
printInfo(` ${stringifyJson(complexObj)}`);
printInfo('');
printInfo('Pretty output (2 spaces):');
const prettyJson = stringifyJson(complexObj, undefined, 2);
for (const line of prettyJson.split('\n')) {
printInfo(` ${line}`);
}
printSuccess('stringifyJson supports formatting options');
// ============================================================================
// Summary
// ============================================================================
printStep(9, 'Summary');
printInfo('parseJson() and stringifyJson() provide safe JSON handling:');
printInfo('');
printInfo(' parseJson(str):');
printInfo(' - Parses JSON strings with large number support');
printInfo(' - Numbers > MAX_SAFE_INTEGER become BigInt');
printInfo(' - Numbers <= MAX_SAFE_INTEGER remain regular numbers');
printInfo('');
printInfo(' stringifyJson(value, replacer?, space?):');
printInfo(' - Serializes objects containing BigInt values');
printInfo(' - Native JSON.stringify throws on BigInt');
printInfo(' - Supports replacer function and spacing');
printInfo('');
printInfo(' Use cases:');
printInfo(' - Algorand API responses with large amounts');
printInfo(' - Transaction data with microAlgo values');
printInfo(' - Any JSON with numbers > 9,007,199,254,740,991');
printInfo('');
printSuccess('JSON BigInt Example completed!');