← Blog

Python dict to JSON: the fastest way to convert and validate

· 4 min read

Why a Python dict isn't JSON

They look nearly identical, which is exactly why this trips people up. Print a dict in Python, or paste a boto3 response out of a terminal, and you get something that reads like JSON but no parser will accept:

{'Bucket': 'invoices-prod', 'Public': False, 'Owner': None}

Four things in there are illegal JSON:

Python JSON
'single quotes' "double quotes"
True / False true / false
None null
Trailing commas Not allowed at all

Paste that into a strict validator and you get Expecting property name enclosed in double quotes - technically correct, and no help at all when you just want to read the thing.

The fastest way to convert it

Paste it into the JSON Formatter and hit Format. There's no setting to find first: if the input isn't valid JSON, it gets repaired and then formatted in one step.

{
  "Bucket": "invoices-prod",
  "Public": false,
  "Owner": null
}

Above the box you'll see exactly what changed - "Converted single-quoted strings to double quotes", "Converted Python True/False/None to JSON true/false/null". That list matters more than it sounds like it should, which is the next section.

The part most converters get wrong

The obvious way to build this is find-and-replace: swap every ' for ", every True for true, and call it done. It works on the example above and quietly destroys real data.

Here's the same approach meeting a string that contains the word True:

{'msg': 'True story, bro'}

Replace every True and you get {"msg": "true story, bro"}. The text changed. Nothing errored, nothing warned you, and if you'd pasted a hundred records you'd never spot it. The same bug hits runs of spaces ('hello world' collapsing to 'hello world') and any apostrophe in a value - "it's fine" becomes "it"s fine", which then fails to parse for a reason that has nothing to do with your input.

The fix isn't a better regex. A regex can't tell "inside a string" from "outside a string", and that distinction is the entire problem. So the formatter walks the input character by character, tracking when it's inside a string literal, and only ever repairs structure. Your values come out the same way they went in:

{
  "msg": "True story, bro"
}

Capital T intact.

Pasting AWS output

AWS CLI output is already valid JSON, so it formats as-is. The awkward case is a printed boto3 response, which is a Python dict carrying types JSON has never heard of:

{'Name': 'invoices-prod', 'Created': datetime.datetime(2026, 9, 21, 0, 0), 'Size': Decimal('1.5')}

Those get handled specifically: datetime.datetime(...) is kept as a string so you don't lose the timestamp, and Decimal('1.5') becomes the number 1.5.

{
  "Name": "invoices-prod",
  "Created": "datetime.datetime(2026, 9, 21, 0, 0)",
  "Size": 1.5
}

And if you've pasted several objects back to back - a DynamoDB export or CloudWatch Logs output, where each line is its own JSON object - they're combined into a single array rather than rejected as "extra data".

What else it repairs

Same rule throughout: structure only, and everything it did is listed.

  • Unquoted keys - {name: "Ana"}
  • Unquoted values - {"city": Paris}
  • Trailing commas
  • // and /* */ comments
  • Curly quotes from a doc or a Slack message
  • Missing commas between values
  • Brackets left unclosed
  • NaN and Infinity, which JSON has no value for, become null

Input that's already valid JSON is never rewritten at all - it goes straight to formatting, so there's no chance of a repair touching a document that didn't need one.

Doing it in Python instead

If this is part of a script rather than a one-off, you don't need a tool:

import json
json.dumps({'Bucket': 'invoices-prod', 'Public': False}, indent=2)

json.dumps handles the quote and literal conversion for you. It will raise TypeError on datetime and Decimal values, which is where default=str earns its keep:

json.dumps(response, indent=2, default=str)

Reach for the browser tool when you've got a dict pasted from somewhere else and just want to read it - not when you're writing code that already has the object in hand.

Nothing is uploaded

The whole thing runs in your browser. Nothing you paste is sent to a server, which is the point when the dict you're debugging is a production API response with customer records in it.

Try JSON Formatter - free, and it never leaves your browser.

Open JSON Formatter