Create two fields. One for user input and other with parsed value. I do not think this will be different for any stack.

The challenge is how to show to a user how you understood entered value. This could be solved with a hint with a parsed value under the text field.

Answer from Oleksandr Bondar on Stack Overflow
🌐
Reddit
reddit.com › r/nextjs › decimal cannot be serialized
r/nextjs on Reddit: Decimal cannot be serialized
June 30, 2023 -

I have a problem with serialization, I use the next-superjson-plugin with SWC. When I try to return data that is of type Decimal (It work with all other data types) I get this error :

Reason: `object` ("[object Decimal]") cannot be serialized as JSON. Please only return JSON serializable data types.

I know that is it not supported by the plugin natively, but don't find a solution for overcoming this. Have vou an idea for solving this ?

🌐
npm
npmjs.com › package › decimal.js-extensions-serialize
decimal.js-extensions-serialize - npm
A decimal.js extension for Decimal to ArrayBuffer serialization. Latest version: 0.1.0, last published: 5 years ago. Start using decimal.js-extensions-serialize in your project by running `npm i decimal.js-extensions-serialize`. There are no other projects in the npm registry using decimal.js-extensions-serialize.
      » npm install decimal.js-extensions-serialize
    
Published   Jun 18, 2020
Version   0.1.0
Author   Michael Mclaughlin
🌐
GitHub
github.com › JamesNK › Newtonsoft.Json › issues › 1726
Serialization of decimals does not respect precision · Issue #1726 · JamesNK/Newtonsoft.Json
May 28, 2018 - The issue can be solved by keeping the necessary number of decimal digits in JSON representation of the number, e.g. serialize decimal 15 as integer "15", and decimal 15.0 as "15.0". This is exactly how Decimal.ToString() works.
Published   May 28, 2018
🌐
GitHub
github.com › flightcontrolhq › superjson
GitHub - flightcontrolhq/superjson: Safely serialize JavaScript expressions to a superset of JSON, which includes Dates, BigInts, and more. · GitHub
In a Next.js project, _app.ts would be a good spot for that. import { Decimal } from 'decimal.js'; SuperJSON.registerCustom<Decimal, string>( { isApplicable: (v): v is Decimal => Decimal.isDecimal(v), serialize: v => v.toJSON(), deserialize: ...
Author   flightcontrolhq
🌐
GitHub
github.com › prisma › prisma › issues › 9170
`object` ("[object Decimal]") cannot be serialized as JSON · Issue #9170 · prisma/prisma
July 23, 2021 - Please only return JSON serializable data types. This is pretty strange because I thought Prisma would convert DECIMAL type to JavaScript's float automatically.
Published   Sep 08, 2021
🌐
GitHub
github.com › paupino › rust-decimal › issues › 205
Why are Decimals serialized as strings in JSON? · Issue #205 · paupino/rust-decimal
November 18, 2019 - #[test] fn serialize_decimal() { let record = Record { amount: Decimal::new(1234, 3), }; let serialized = serde_json::to_string(&record).unwrap(); assert_eq!("{\"amount\":\"1.234\"}", serialized); } Due to the fact that arbitrary precision is fully supported by serde, I expected the serialization to produce: {"amount": 1.234} or at least to have an option to choose the output format.
Published   Nov 18, 2019
🌐
LinkedIn
linkedin.com › pulse › json-serialization-gone-wrong-vladimir-kocjancic
Json serialization gone wrong
February 8, 2021 - All fine and dandy, except this now serializes into {"Value":"385"} which, again, produces incorrect hash of EC53BDEEC861E050E56FDA51B48621D0452006247D1501D79CF63A4C749E513F. In order to return value as a numeric value and not string, you need to get a little bit more creative: public class DecimalFormatConverter : JsonConverter { public override bool CanConvert(Type objectType) { return (objectType == typeof(decimal) || objectType == typeof(decimal?)); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var valCasted = Convert.ToDecimal(value); if (M
🌐
Ghielectronics
forums.ghielectronics.com › tinyclr os
JSON Serialize decimal places - TinyCLR OS - GHI Electronics' Forums
June 15, 2023 - I am serializing a class that has some Doubles. Is there a way to limit the number of decimal places when it is serialized to a JSON string?
Find elsewhere
Top answer
1 of 3
46

You'll have to write your own custom JsonConverter and use it to intercept the decimal type so you can change how it gets serialized. Here's an example:

public class DecimalFormatConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(decimal));
    }

    public override void WriteJson(JsonWriter writer, object value, 
                                   JsonSerializer serializer)
    {
        writer.WriteValue(string.Format("{0:N2}", value));
    }

    public override bool CanRead
    {
        get { return false; }
    }

    public override object ReadJson(JsonReader reader, Type objectType,
                                 object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();    
    }
}   

To use it, simply pass in a new instance of this custom converter to the SerializeObject method:

var json = JsonConvert.SerializeObject(yourObject, new DecimalFormatConverter());
2 of 3
39

The accepted answer is correct, but expanding upon the comments on accepted answer:

If you want the decimals in your JSON to be numbers instead of strings, you need to use WriteRawValue and use :0.00 instead of :N2 for the string formatting (as N2 includes thousand separator commas and other culture specific number formatting that will break your JSON)

public class DecimalFormatConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(decimal);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        writer.WriteRawValue($"{value:0.00}");
    }

    public override bool CanRead => false;

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

This is the difference in output compared to the accepted answer.

# writer.WriteRawValue($"{value:0.00}");
{
    "MyDecimal": 3.50,
    "MyBiggerDecimal": 12345.50
}

# writer.WriteValue($"{value:N2}");
{
    "MyDecimal": "3.50",
    "MyBiggerDecimal": "12,345.50"
}

Note - the accepted answer is correct for the OP's specific question i.e. serialize 3.5 to "3.50", but I got here wanting to serialize 3.5 to 3.50 (without the string quotes).

Top answer
1 of 4
24

I wasn't completely satisfied with all of the techniques thus far to achieve this. JsonConverterAttribute seemed the most promising, but I couldn't live with hard-coded parameters and proliferation of converter classes for every combination of options.

So, I submitted a PR that adds the ability to pass various arguments to JsonConverter and JsonProperty. It's been accepted upstream and I expect will be in the next release (whatever's next after 6.0.5)

You can then do it like this:

public class Measurements
{
    [JsonProperty(ItemConverterType = typeof(RoundingJsonConverter))]
    public List<double> Positions { get; set; }

    [JsonProperty(ItemConverterType = typeof(RoundingJsonConverter), ItemConverterParameters = new object[] { 0, MidpointRounding.ToEven })]
    public List<double> Loads { get; set; }

    [JsonConverter(typeof(RoundingJsonConverter), 4)]
    public double Gain { get; set; }
}

Refer to the CustomDoubleRounding() test for an example.

2 of 4
10

For future reference, this can be achieved in Json.net pretty elegantly by creating a custom JsonConverter

public class DecimalFormatJsonConverter : JsonConverter
{
    private readonly int _numberOfDecimals;

    public DecimalFormatJsonConverter(int numberOfDecimals)
    {
        _numberOfDecimals = numberOfDecimals;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var d = (decimal) value;
        var rounded = Math.Round(d, _numberOfDecimals);
        writer.WriteValue((decimal)rounded);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
        JsonSerializer serializer)
    {
        throw new NotImplementedException("Unnecessary because CanRead is false. The type will skip the converter.");
    }

    public override bool CanRead
    {
        get { return false; }
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(decimal);
    }
}

If you're creating serializers in code using constructor explicitly, this will work fine but I think it's nicer to decorate the relevant properties with JsonConverterAttribute, in which case the class must have a public, parameterless constructor. I solved this by creating a subclass which is specific to the format I want.

public class SomePropertyDecimalFormatConverter : DecimalFormatJsonConverter
{
    public SomePropertyDecimalFormatConverter() : base(3)
    {
    }
}

public class Poco 
{
    [JsonConverter(typeof(SomePropertyDecimalFormatConverter))]
    public decimal SomeProperty { get;set; }
}

The custom converter has been derived from Json.NET documentation.

🌐
Turing
turing.com › kb › implementing-json-serialization-in-js
Your Guide to Implementing JSON Serialization in JavaScript
Limited support for large numbers: ... into JSON. Let's explore them one by one. In JavaScript, the JSON.stringify() method cannot serialize functions ......
🌐
GitHub
github.com › tc39 › proposal-decimal
GitHub - tc39/proposal-decimal: Built-in exact decimal numbers for JavaScript · GitHub
Serialization and deserialization in standard decimal formats, e.g., IEEE 754's multiple formats · Precision sufficient for the applications on the other side · The following is fictional, but illustrates the idea. Notice the sql_decimal configuration option and how the values returned from the DB are handled in JS as Decimal values, rather than as strings or as JS Numbers:
Author   tc39
🌐
Google Groups
groups.google.com › g › django-users › c › B3R_zHxggNI
"Decimal not JSON serializable"?
176 elif isinstance(key, float) or isinstance(key, decimal.Decimal): 177 key = floatstr(key, allow_nan) But I also think JSONEncoder is meant to be subclassed for these types of cases.
🌐
npm
npmjs.com › package › lossless-json
lossless-json - npm
import { parse, stringify } from 'lossless-json' import Decimal from 'decimal.js' const parseDecimal = (value) => new Decimal(value) const decimalStringifier = { test: (value) => Decimal.isDecimal(value), stringify: (value) => value.toString() } // parse JSON, operate on a Decimal value, then stringify again const text = '{"value":2.3e500}' const json = parse(text, undefined, { parseNumber: parseDecimal }) // {value: new Decimal('2.3e500')} const output = { result: json.value.times(2) } // {result: new Decimal('4.6e500')} const str = stringify(output, undefined, undefined, [decimalStringifier]) // '{"result":4.6e500}' The library is compatible with the native JSON.parse and JSON.stringify, and also comes with the optional reviver and replacer arguments that allow you to serialize for example data classes in a custom way.
      » npm install lossless-json
    
Published   Oct 03, 2025
Version   4.3.0
Author   Jos de Jong
🌐
Stack Overflow
stackoverflow.com › questions › 30196620 › decimal-serialization-json-to-web-api
angularjs - Decimal serialization JSON to Web API - Stack Overflow
Why do you need that 10.0 notation? Generally speaking JavaScript engines regard 10.0 as equal to 10, and strip that "unneeded decimal" away eg. in JSON.stringify() and in JSON.parse().
🌐
MDN Web Docs
developer.mozilla.org › en-US › docs › Web › JavaScript › Reference › Global_Objects › Number
Number - JavaScript | MDN
Number.parseFloat() and Number.parseInt() are similar to Number() but only convert strings, and have slightly different parsing rules. For example, parseInt() doesn't recognize the decimal point, and parseFloat() doesn't recognize the 0x prefix.
🌐
GitHub
github.com › prisma › prisma-examples › issues › 3047
Trouble with `getServerSideProps` and `Decimal` type in Next.js + Typescript · Issue #3047 · prisma/prisma-examples
June 14, 2021 - Trouble with getServerSideProps and Decimal type in Next.js + Typescript#3047 · Copy link · FMGordillo · opened · on Aug 4, 2021 · Issue body actions · export const getServerSideProps: GetServerSideProps<{ actions: Action[]; }> = async () => { const actions = await prisma.action.findMany(); return { props: { actions, }, }; }; My schema.prisma has · model Action { // ... objective Decimal @db.Decimal(12,2) // ... } And the code throws · Error: Error serializing `.actions[0].objective` returned from `getServerSideProps` in "/".
Published   Aug 04, 2021
Top answer
1 of 5
139

The main reason to transfer numeric values in JSON as strings is to eliminate any loss of precision or ambiguity in transfer.

It's true that the JSON spec does not specify a precision for numeric values. This does not mean that JSON numbers have infinite precision. It means that numeric precision is not specified, which means JSON implementations are free to choose whatever numeric precision is convenient to their implementation or goals. It is this variability that can be a pain if your application has specific precision requirements.

Loss of precision generally isn't apparent in the JSON encoding of the numeric value (1.7 is nice and succinct) but manifests in the JSON parsing and intermediate representations on the receiving end. A JSON parsing function would quite reasonably parse 1.7 into an IEEE double precision floating point number. However, finite length / finite precision decimal representations will always run into numbers whose decimal expansions cannot be represented as a finite sequence of digits:

  1. Irrational numbers (like pi and e)

  2. 1.7 has a finite representation in base 10 notation, but in binary (base 2) notation, 1.7 cannot be encoded exactly. Even with a near infinite number of binary digits, you'll only get closer to 1.7, but you'll never get to 1.7 exactly.

So, parsing 1.7 into an in-memory floating point number, then printing out the number will likely return something like 1.69 - not 1.7.

Consumers of the JSON 1.7 value could use more sophisticated techniques to parse and retain the value in memory, such as using a fixed-point data type or a "string int" data type with arbitrary precision, but this will not entirely eliminate the specter of loss of precision in conversion for some numbers. And the reality is, very few JSON parsers bother with such extreme measures, as the benefits for most situations are low and the memory and CPU costs are high.

So if you are wanting to send a precise numeric value to a consumer and you don't want automatic conversion of the value into the typical internal numeric representation, your best bet is to ship the numeric value out as a string and tell the consumer exactly how that string should be processed if and when numeric operations need to be performed on it.

For example: In some JSON producers (JRuby, for one), BigInteger values automatically output to JSON as strings, largely because the range and precision of BigInteger is so much larger than the IEEE double precision float. Reducing the BigInteger value to double in order to output as a JSON numeric will often lose significant digits.

Also, the JSON spec (http://www.json.org/) explicitly states that NaNs and Infinities (INFs) are invalid for JSON numeric values. If you need to express these fringe elements, you cannot use JSON number. You have to use a string or object structure.

Finally, there is another aspect which can lead to choosing to send numeric data as strings: control of display formatting. Leading zeros and trailing zeros are insignificant to the numeric value. If you send JSON number value 2.10 or 004, after conversion to internal numeric form they will be displayed as 2.1 and 4.

If you are sending data that will be directly displayed to the user, you probably want your money figures to line up nicely on the screen, decimal aligned. One way to do that is to make the client responsible for formatting the data for display. Another way to do it is to have the server format the data for display. Simpler for the client to display stuff on screen perhaps, but this can make extracting the numeric value from the string difficult if the client also needs to make computations on the values.

2 of 5
33

I'll be a bit contrarian and say that 7.47 is perfectly safe in JSON, even for financial amounts, and that "7.47" isn't any safer.


First, let me address some misconceptions from this thread:

So, parsing 1.7 into an in-memory floating point number, then printing out the number will likely return something like 1.69 - not 1.7.

That is not true, especially in the context of IEEE 754 double precision format that was mentioned in that answer. 1.7 converts into an exact double 1.6999999999999999555910790149937383830547332763671875 and when that value is "printed" for display, it will always be 1.7, and never 1.69, 1.699999999999 or 1.70000000001. It is 1.7 "exactly".

Learn more here.

7.47 may actually be 7.4699999923423423423 when converted to float

7.47 already is a float, with an exact double value 7.46999999999999975131004248396493494510650634765625. It will not be "converted" to any other float.

a simple system that simply truncates the extra digits off will result in 7.46 and now you've lost a penny somewhere

IEEE rounds, not truncates. And it would not convert to any other number than 7.47 in the first place.

is the JSON number actually a float? As I understand it's a language independent number, and you could parse a JSON number straight into a java BigDecimal or other arbitrary precision format in any language if so inclined.

It is recommended that JSON numbers are interpreted as doubles (IEEE 754 double-precision format). I haven't seen a parser that wouldn't be doing that.

And no, BigDecimal(7.47) is not the right way to do it – it will actually create a BigDecimal representing the exact double of 7.47, which is 7.46999999999999975131004248396493494510650634765625. To get the expected behavior, BigDecimal("7.47") should be used.


Overall, I don't see any fundamental issue with {"price": 7.47}. It will be converted into a double on virtually all platforms, and the semantics of IEEE 754 guarantee that it will be "printed" as 7.47 exactly and always.

Of course floating point rounding errors can happen on further calculations with that value, see e.g. 0.1 + 0.2 == 0.30000000000000004, but I don't see how strings in JSON make this better. If "7.47" arrives as a string and should be part of some calculation, it will need to be converted to some numeric data type anyway, probably float :).

It's worth noting that strings also have disadvantages, e.g., they cannot be passed to Intl.NumberFormat, they are not a "pure" data type, e.g., the dot is a formatting decision.

I'm not strongly against strings, they seem fine to me as well but I don't see anything wrong on {"price": 7.47} either.

🌐
Stack Overflow
stackoverflow.com › questions › 77520208 › nextjs-response-json-converts-decimal-to-string
next.js - NextJS response.json converts decimal to string - Stack Overflow
Api handler in NextJS converts decimal to string. import { PrismaClient } from "@prisma/client"; const handler = async (req, res) => { const prisma = new PrismaClient(); const result = await prisma.Test.findMany({}); console.log(result); res.status(200).json(result); //res.status(200).json({ name: "John Doe", age: 34, salary: 12345.75 }); }; export default handler;