To escape curly braces in Python format strings, double them: {{ prints { and }} prints }. The rule is the same for f-strings and str.format(), and single braces stay placeholders:
print(f"{{city}} is literal, {city} is the value") # {city} is literal, Austin is the value
Every snippet here was run on Python 3.12.5, plus Python 3.14 for the new template strings near the end.
We’ll cover doubled braces, putting braces around a value, the errors a lone brace causes, and when it’s easier to avoid format strings entirely, such as for JSON.
Escape curly braces in f-strings and str.format()
Python reads { as the start of a replacement field. Writing it twice tells the parser you want the character itself:
city, total = "Austin", 249.5
print(f"{{city}} is a placeholder; the real value is {city}")
print("Order total: {{ ${:.2f} }}".format(total))
print("{{}} prints {}".format("empty braces"))
Output:
{city} is a placeholder; the real value is Austin
Order total: { $249.50 }
{} prints empty braces

{{}} on its own prints {}, which trips people up when they expect an empty placeholder. If you’re new to f-strings, start with creating a string with variables in Python.
Put curly braces around a value (triple braces)
To print a value wrapped in braces, like {TX}, you need three on each side: two for the literal brace and one for the placeholder. Format specs still work inside:
state, price = "TX", 19.99
print(f"{{{state}}}") # outer pair = literal braces, inner = the value
print(f"{{price: {price:.2f}}}") # braces around a formatted number
print("{{{0}}}".format("Denver")) # same rule in str.format
Output:
{TX}
{price: 19.99}
{Denver}

:.2f still formats the price.Read it from the inside out: {state} is the value, and the extra pair on each side is the escaped brace. Number formatting like .2f is covered in printing 2 decimal places in Python.
Errors from a single curly brace
Forget to double a brace and you’ll get one of three errors, depending on the method. Here they are, caught so the script keeps going:
code = 'f"Total: {price}}"'
try:
compile(code, "<order>", "eval")
except SyntaxError as err:
print("SyntaxError:", err.msg)
try:
print("Discount }: {}".format(10))
except ValueError as err:
print("ValueError:", err)
template = '{"customer": "{name}", "state": "TX"}'
try:
print(template.format(name="Emily"))
except KeyError as err:
print("KeyError:", err)
Output:
SyntaxError: f-string: single '}' is not allowed
ValueError: Single '}' encountered in format string
KeyError: '"customer"'

str.format() raises ValueError for a stray } and KeyError when JSON braces look like placeholders.That last KeyError is the sneaky one. Python sees {"customer"...} as a field named "customer" and goes looking for it.
Reading tracebacks like these is easier once you know how escape sequences work in Python, since quotes and backslashes cause similar surprises.
Avoid brace escaping with json.dumps and string.Template
When the text is full of braces, like JSON, CSS or JavaScript, escaping every one gets unreadable. Use a tool that doesn’t treat braces as special:
import json
from string import Template
customer = {"name": "Emily Clark", "state": "TX", "balance": 249.5}
print(json.dumps(customer)) # no brace escaping needed
css = Template(".banner { color: $color; font-size: ${size}px; }")
print(css.substitute(color="navy", size=18)) # $ placeholders, braces stay literal
print("%s owes $%.2f {due Friday}" % (customer["name"], customer["balance"]))
Output:
{"name": "Emily Clark", "state": "TX", "balance": 249.5}
.banner { color: navy; font-size: 18px; }
Emily Clark owes $249.50 {due Friday}

json.dumps() handles quoting, Template uses $ placeholders, and % formatting ignores braces.I always build JSON with json.dumps(); it also escapes quotes inside values, which hand-written f-strings often get wrong. For writing the result to disk, see writing a string to a file in Python.
Curly braces in Python 3.14 template strings
Python 3.14 adds template strings, written t"...". They follow the same rule, so {{ is still a literal brace:
import sys
from string.templatelib import Template
name = "Emily"
t = t"{{literal}} and {name}" # template string (Python 3.14+)
print(type(t).__name__, t.strings, [i.value for i in t.interpolations])
print(sys.version.split()[0])
Output:
Template ('{literal} and ', '') ['Emily']
3.14.8
A t-string returns a Template object instead of a finished string, so libraries can process the values safely before joining them. For printing values next to text in older versions, see printing a string and a variable in Python.
Curly brace rules at a glance
| You want | Write |
|---|---|
A literal { or } | {{ or }} |
| A value inside braces | f"{{{value}}}" |
Literal {} | {{}} |
| JSON text | json.dumps(data) |
| Text full of braces with a few values | string.Template with $name |
These string guides go well with this one:
- Concatenate strings in Python
- Print quotes in Python
- Format a number with commas in Python
- Create a string with a newline in Python
Frequently asked questions
How do I escape curly braces in a Python f-string?
Double them: {{ prints { and }} prints }, for example f"{{name}}".
How do I escape braces in str.format()?
The same way, with doubled braces: "{{}} {}".format(x) prints {} followed by x.
How do I print a variable inside curly braces?
Use three braces on each side: f"{{{state}}}" prints {TX}.
Why do I get KeyError when formatting a JSON string?
str.format() treats the JSON braces as placeholders. Double them, or build the JSON with json.dumps().
Does % formatting need curly braces escaped?
No. Only % is special there; braces print as normal characters.
Where is the format string syntax documented?
See Format String Syntax in the Python docs.

Bijay Kumar is a 13-time Microsoft MVP with more than 18 years in software development, and the founder of Python Guides and TSinfo Technologies. He started out building .NET and SharePoint solutions at HP, TCS and KPIT before moving into Python, machine learning and AI, and he also builds web apps with TypeScript and React. He writes the tutorials here himself, and every example is run before publishing so you see the real output. More about Bijay · Microsoft MVP profile · LinkedIn