TL;DR

  • Converting to Lowercase -> lower()
  • Caseless String matching/comparison -> casefold()

casefold() is a text normalization function like lower() that is specifically designed to remove upper- or lower-case distinctions for the purposes of comparison. It is another form of normalizing text that may initially appear to be very similar to lower() because generally, the results are the same. As of Unicode 13.0.0, only ~300 of ~150,000 characters produced differing results when passed through lower() and casefold(). @dlukes' answer has the code to identify the characters that generate those differing results.

To answer your other two questions:

  • use lower() when you specifically want to ensure a character is lowercase, like for presenting to users or persisting data
  • use casefold() when you want to compare that result to another casefold-ed value.

Other Material

I suggest you take a closer look into what case folding actually is, so here's a good start: W3 Case Folding Wiki

Another source: Elastic.co Case Folding

Edit: I just recently found another very good related answer to a slightly different question here on SO (doing a case-insensitive string comparison)


Performance

Using this snippet, you can get a sense for the performance between the two:

import sys
from timeit import timeit

unicode_codepoints = tuple(map(chr, range(sys.maxunicode)))

def compute_lower():
    return tuple(codepoint.lower() for codepoint in unicode_codepoints)

def compute_casefold():
    return tuple(codepoint.casefold() for codepoint in unicode_codepoints)

timer_repeat = 1000

print(f"time to compute lower on unicode namespace: {timeit(compute_lower, number = timer_repeat) / timer_repeat} seconds")
print(f"time to compute casefold on unicode namespace: {timeit(compute_casefold, number = timer_repeat) / timer_repeat} seconds")

print(f"number of distinct characters from lower: {len(set(compute_lower()))}")
print(f"number of distinct characters from casefold: {len(set(compute_casefold()))}")

Running this, you'll get the results that the two are overwhelmingly the same in both performance and the number of distinct characters returned

time to compute lower on unicode namespace: 0.137255663 seconds
time to compute casefold on unicode namespace: 0.136321374 seconds
number of distinct characters from lower: 1112719
number of distinct characters from casefold: 1112694

If you run the numbers, that means it takes about 1.6e-07 seconds to run the computation on a single character for either function, so there isn't a performance benefit either way.

Answer from David Culbreth on Stack Overflow
🌐
Reddit
reddit.com › r/learnpython › casefold() vs lower()
r/learnpython on Reddit: casefold() vs lower()
October 12, 2024 -

I just learnt about casefold() and decided to google it to see what it did. Here is w3schools definition:

Definition and Usage The casefold() method returns a string where all the characters are lower case.

This method is similar to the lower() method, but the casefold() method is stronger, more aggressive, meaning that it will convert more characters into lower case, and will find more matches when comparing two strings and both are converted using the casefold() method.

How does one “more aggressively” convert strings to lower case? Meaning, what more can/does it do than lower()?

string.lower() versus string.lower May 26, 2015
r/learnpython
11y ago
How does key=str.casefold work ? Oct 18, 2021
r/learnpython
4y ago
Turn input into lower case Oct 15, 2022
r/learnpython
3y ago
What is Unicode case folding and how to achieve it? Sep 22, 2019
r/learnprogramming
6y ago
More results from reddit.com
🌐
W3Schools
w3schools.com › python › ref_string_casefold.asp
Python String casefold() Method
This method is similar to the lower() method, but the casefold() method is stronger, more aggressive, meaning that it will convert more characters into lower case, and will find more matches when comparing two strings and both are converted ...
Discussions

Should I use Python casefold? - Stack Overflow
Been recently reading on casefold and string comparisons when ignoring case. I've read that the MSDN standard is to use InvariantCulture and definitely avoid toLowercase. However, casefold from wha... More on stackoverflow.com
🌐 stackoverflow.com
How do I accept both lowercase and uppercase as input?
Thank you so much for all your replies! I've now understood how .capitalize() (and .lower() / .upper() for that matter!) works, and I think I can implement it into my code. Again, thank you for all your help :) More on reddit.com
🌐 r/learnpython
16
24
November 20, 2021
casefold() vs lower()
lower is used for converting strings into lowercase, typically for display purposes. casefold is "stronger" because it will use additional rules for other characters. It's useful for comparing strings leniently. Look: >>> x = "ẞ ß" # Capital and lowercase sharp s >>> x.lower() 'ß ß' >>> x.casefold() 'ss ss' More on reddit.com
🌐 r/learnpython
19
30
October 12, 2024
Which string to lower case method to you use?
Latter. Reason: Did not even know the former existed till right now More on reddit.com
🌐 r/Python
30
0
May 22, 2022
Top answer
1 of 5
111

TL;DR

  • Converting to Lowercase -> lower()
  • Caseless String matching/comparison -> casefold()

casefold() is a text normalization function like lower() that is specifically designed to remove upper- or lower-case distinctions for the purposes of comparison. It is another form of normalizing text that may initially appear to be very similar to lower() because generally, the results are the same. As of Unicode 13.0.0, only ~300 of ~150,000 characters produced differing results when passed through lower() and casefold(). @dlukes' answer has the code to identify the characters that generate those differing results.

To answer your other two questions:

  • use lower() when you specifically want to ensure a character is lowercase, like for presenting to users or persisting data
  • use casefold() when you want to compare that result to another casefold-ed value.

Other Material

I suggest you take a closer look into what case folding actually is, so here's a good start: W3 Case Folding Wiki

Another source: Elastic.co Case Folding

Edit: I just recently found another very good related answer to a slightly different question here on SO (doing a case-insensitive string comparison)


Performance

Using this snippet, you can get a sense for the performance between the two:

import sys
from timeit import timeit

unicode_codepoints = tuple(map(chr, range(sys.maxunicode)))

def compute_lower():
    return tuple(codepoint.lower() for codepoint in unicode_codepoints)

def compute_casefold():
    return tuple(codepoint.casefold() for codepoint in unicode_codepoints)

timer_repeat = 1000

print(f"time to compute lower on unicode namespace: {timeit(compute_lower, number = timer_repeat) / timer_repeat} seconds")
print(f"time to compute casefold on unicode namespace: {timeit(compute_casefold, number = timer_repeat) / timer_repeat} seconds")

print(f"number of distinct characters from lower: {len(set(compute_lower()))}")
print(f"number of distinct characters from casefold: {len(set(compute_casefold()))}")

Running this, you'll get the results that the two are overwhelmingly the same in both performance and the number of distinct characters returned

time to compute lower on unicode namespace: 0.137255663 seconds
time to compute casefold on unicode namespace: 0.136321374 seconds
number of distinct characters from lower: 1112719
number of distinct characters from casefold: 1112694

If you run the numbers, that means it takes about 1.6e-07 seconds to run the computation on a single character for either function, so there isn't a performance benefit either way.

2 of 5
42

Both .lower() and .casefold() act on the full range of Unicode codepoints

There's some confusion in the existing answers, even the accepted one (EDIT: I was referring to this currently outdated version; the current one is fine). The distinction between .lower() and .casefold() has nothing to do with ASCII vs. Unicode, both act on the whole Unicode range of codepoints, just in slightly different ways. But both perform relatively complex mappings which they need to look up in the Unicode database, for instance:

>>> "Ť".lower()
'ť'

Both can involve single-to-multiple codepoint mappings, like we saw with "ß".casefold(). Look what happens to ß when you apply .lower()'s counterpart .upper():

>>> "ß".upper()
'SS'

And the one example I found where .lower() also does this:

>>> list("İ".lower())
['i', '̇']

So the performance claims, like "lower() will require less memory or less time because there are no lookups, and it's only dealing with 26 characters it has to transform", are simply not true.

The vast majority of the time, both operations yield the same thing, but there are a few cases (297 as of Unicode 13.0.0) where they don't. You can identify them like this:

import sys
import unicodedata as ud

print("Unicode version:", ud.unidata_version, "\n")
total = 0
for codepoint in map(chr, range(sys.maxunicode)):
    lower, casefold = codepoint.lower(), codepoint.casefold()
    if lower != casefold:
        total += 1
        for conversion, converted in zip(
            ("orig", "lower", "casefold"),
            (codepoint, lower, casefold)
        ):
            print(conversion, [ud.name(cp) for cp in converted], converted)
        print()
print("Total differences:", total)

When to use which

The Unicode standard covers lowercasing as part of Default Case Conversion in Section 3.13, and Default Case Folding is described right below that. The first paragraph says:

Case folding is related to case conversion. However, the main purpose of case folding is to contribute to caseless matching of strings, whereas the main purpose of case conversion is to put strings into a particular cased form.

My rule of thumb based on this:

  • Want to display a lowercased version of a string to users? Use .lower().
  • Want to do case-insensitive string comparison? Use .casefold().

(As a sidenote, I routinely break this rule of thumb and use .lower() across the board, just because it's shorter to type, the output is overwhelmingly the same, and what differences there are don't affect the languages I typically come across and work with. Don't be like me though ;) )

Just to hammer home that in terms of complexity, both operations are basically the same, they just use slightly different mappings -- this is Unicode's abstract definition of lowercasing:

R2 toLowercase(X): Map each character C in X to Lowercase_Mapping(C).

And this is its abstract definition of case folding:

R4 toCasefold(X): Map each character C in X to Case_Folding(C).

In Python's official documentation

The Python docs are quite clear that this is what the respective methods do, they even point the user to the aforementioned Section 3.13.

They describe .lower() as converting cased characters to lowercase, where cased characters are "those with general category property being one of “Lu” (Letter, uppercase), “Ll” (Letter, lowercase), or “Lt” (Letter, titlecase)". Same with .upper() and uppercase.

With .casefold(), the docs explicitly state that it's meant for "caseless matching", and that it's "similar to lowercasing but more aggressive because it is intended to remove all case distinctions in a string".

Top answer
1 of 2
19

1) In Python 3, casefold() should be used to implement caseless string matching.

Starting with Python 3.0, strings are stored as Unicode. The Unicode Standard Chapter 3.13 defines the default caseless matching as follows:

A string X is a caseless match for a string Y if and only if:
toCasefold(X) = toCasefold(Y)

Python's casefold() implements the Unicode's toCasefold(). So, it should be used to implement caseless string matching. Although, casefolding alone is not enough to cover some corner cases and to pass the Turkey Test (see Point 3).

2) As of Python 3.6, casefold() cannot pass the Turkey Test.

For two characters, uppercase I and dotted uppercase I, the Unicode Standard defines two different casefolding mappings.

The default (for non-Turkic languages):
I → i (U+0049 → U+0069)
İ → i̇ (U+0130 → U+0069 U+0307)

The alternative (for Turkic languages):
I → ı (U+0049 → U+0131)
İ → i (U+0130 → U+0069)

Pythons casefold() can apply only the default mapping and fails the Turkey Test. For example, the Turkish words "LİMANI" and "limanı" are caseless equivalents, but "LİMANI".casefold() == "limanı".casefold() returns False. There is no option to enable the alternative mapping.

3) How to do caseless string matching in Python 3.

The Unicode Standard Chapter 3.13 describes several caseless matching algorithms. The canonical casless matching would probably suit most use cases. This algorithm already takes into account all corner cases. We only need to add an option to switch between non-Turkic and Turkic casefolding.

import unicodedata

def normalize_NFD(string):
    return unicodedata.normalize('NFD', string)

def casefold_(string, include_special_i=False):
    if include_special_i:
        string = unicodedata.normalize('NFC', string)
        string = string.replace('\u0049', '\u0131')
        string = string.replace('\u0130', '\u0069')
    return string.casefold()

def casefold_NFD(string, include_special_i=False):
    return normalize_NFD(casefold_(normalize_NFD(string), include_special_i))

def caseless_match(string1, string2, include_special_i=False):
    return  casefold_NFD(string1, include_special_i) == casefold_NFD(string2, include_special_i)

casefold_() is a wrapper for Python's casefold(). If its parameter include_special_i is set to True, then it applies the Turkic mapping, and if it is set to False the default mapping is used.

caseless_match() does the canonical casless matching for string1 and string2. If the strings are Turkic words, include_special_i parameter must be set to True.

Examples:

>>> caseless_match('LİMANI', 'limanı', include_special_i=True)
True
>>> caseless_match('LİMANI', 'limanı')
False
>>> caseless_match('INTENSIVE', 'intensive', include_special_i=True)
False
>>> caseless_match('INTENSIVE', 'intensive')
True
2 of 2
0

I'll flesh out the discussion of case folding and insensitive matching in Python and Unicode.

Unicode defines two sets of operations, the first is case-mapping. For case mapping, Unicode defines three cases: lowercase, uppercase, and titlecase. These are string transformations changing text from one case to another.

Likewise, Unicode defines case folding operations. Case folding is designed to remove case distinctions before comparing strings or matching strings. This is different from the comparison operations between two strings defined in collation.

If you need to match or compare strings case insensitively, use case folding.

If you want to transform text or to do case sensitive string comparison use case mapping operations.

The key source of data on case folding is the CaseFolding.txt file in the UCD.

Three types methodologies are defined for case folding:

  1. Simple casefolding. This is used when you want to minimise the size of the data you need to work with. It can be found in embedded systems, and is used in some regex engines. It involves folding single characters to single characters. Simple casefolding uses the mappings with status C and S.
  2. Full casefolding. This is what str.casefold uses. Individual characters could be mapped to a sequence of characters. Full casefolding uses the mappings with status C and F.
  3. Turkic tailoring for Turkish, Azerbaijani, Uzbek, Tatar and Kazakh. This is an optional folding that by default isn't used, but is an available option to casefolding in Unicode.

Casefolding is not a string operation that is sensitive to locales or languages, except for the option to use Turkic exceptions. It is also important to note that case insensitivity using str.casefold differs from case insensitivity in the re module.

Casefolding is a building block to other matching algorithms, including canonical caseless matching, compatibility caseless matching, and identifier matching.

As has been noted in other answers , Python doesn't provide access to the Turkish tailorings when casefolding.

There are two approaches:

  1. Build a custom function to class to handle casefolding while using str.casefold, or
  2. Make use of PyICU, a wrapper around icu4c

I'll use PyICU using icu.Char and icu.CaseMap classes:

def toCasefold(text:str, full:bool = True, turkic:bool = False) -> str:
    # Enumerated consonants to use with icu.CaseMap:
    # icu.U_FOLD_CASE_DEFAULT : 0
    # icu.U_FOLD_CASE_EXCLUDE_SPECIAL_I : 1
    # 
    # Enumerated consonants in icu.Char:
    # icu.Char.FOLD_CASE_DEFAULT : 0
    # icu.Char.FOLD_CASE_EXCLUDE_SPECIAL_I : 1

    option:int = 1 if turkic else 0
    if not full:
        return "".join([icu.Char.foldCase(char, option) for char in text])
    return icu.CaseMap.fold(option, text)

city = 'DİYARBAKIR'

# Default casefold of string in Python,
print(city.casefold())
# di̇yarbakir

# Full case folding in PyICU, using a wrapper:
# Could also use icu.UnicodeString.foldCase
print(toCasefold(city))
# di̇yarbakir

# Full case folding in PyICU, using a wrapper, with Turkic rules in Casefolding.txt
# Could also use icu.UnicodeString.foldCase
print(toCasefold(city, turkic=True))
# diyarbakır

# Simple case folding in PyICU, using a wrapper
print(toCasefold(city, full=False))
# dİyarbakir

# Simple case folding in PyICU, using a wrapper, with Turkic rules in Casefolding.txt
# Could also use icu.UnicodeString.foldCase
print(toCasefold(city, full=False, turkic=True))
# diyarbakır

So DİYARBAKIR can be casefolded according to Unicode rules to di̇yarbakir, diyarbakır, or dİyarbakir, depending on the type of case folding and the options applied.

🌐
Python Morsels
pythonmorsels.com › uppercasing-and-lowercasing-in-python
Uppercasing and lowercasing in Python - Python Morsels
July 18, 2026 - Some folks prefer to use casefold when normalizing cases, simply for the sake of comparison with another string: >>> line1 = "I like Python" >>> line2 = "I like python" >>> line1.casefold() == line2.casefold() True
🌐
Toppr
toppr.com › guides › python-guide › references › methods-and-functions › methods › string › casefold › python-string-casefold
Python casefold() function | Why do we use Python string casefold()? |
August 26, 2021 - Consider an example of the German lowercase letter ‘ß’, which is equal to ‘ss’. However, because ‘ß’ is already in lowercase, the lower() function has no effect on it. Python’s string casefold() function, on the other hand, turns it to ‘ss’.
Find elsewhere
🌐
Tutorial Gateway
tutorialgateway.org › python-casefold
Python casefold
May 14, 2019 - The Python casefold function converts all the characters in a given string into lowercase letters. Although casefold() is the same as the lower function, it is more aggressive and stronger than the lower.
🌐
TutorialsPoint
tutorialspoint.com › difference-between-casefold-and-lower-in-python
Difference between casefold() and lower() in Python
October 23, 2023 - The casefold() method performs aggressive case folding by converting characters to lowercase and normalizing special Unicode characters.
🌐
Sololearn
sololearn.com › en › Discuss › 2455515 › what-the-difference-between-lower-and-casefold
What the difference between .lower() and .casefold()?
Sololearn is the world's largest community of people learning to code. With over 25 programming courses, choose from thousands of topics to learn how to code, brush up your programming knowledge, upskill your technical ability, or stay informed about the latest trends.
🌐
Codingdeeply
codingdeeply.com › home › python casefold vs. lower: what’s better for string manipulation
Python Casefold vs. Lower: What's Better for String Manipulation - Codingdeeply
February 23, 2024 - Think of .casefold() as .lower()’s big sibling. It’s more aggressive regarding case conversion, especially for non-English characters.
🌐
GeeksforGeeks
geeksforgeeks.org › python › python-string-casefold-method
Python String casefold() Method - GeeksforGeeks
April 11, 2023 - Python String casefold() Method is more aggressive in conversion to lowercase characters because it tends to remove all case distinctions in a String.
🌐
Python Tutorial
pythontutorial.net › home › python string methods › python string casefold()
Python String casefold(): Return a Casedfolded Copy of a String
December 28, 2020 - However, casefolding is more aggressive because it’s intended to remove all case distinctions in a string.
🌐
GeeksforGeeks
geeksforgeeks.org › python › difference-between-casefold-and-lower-in-python
Difference between casefold() and lower() in Python - GeeksforGeeks
July 23, 2025 - In this example, we have stored ... and we can see in the output that casefold() converts it to lowercase whereas using lower(), the letter is printed as it is after conversion....
🌐
GoLinuxCloud
golinuxcloud.com › home › programming › python › python casefold() string method
Python casefold(): String casefold() Method, Examples, and casefold vs lower (2026)
June 20, 2026 - Use casefold() when normalizing both sides of a case-insensitive string comparison or lookup, especially with international text; use lower() for user-visible lowercasing where case folding would look wrong.
🌐
Learn By Example
learnbyexample.org › python-string-casefold-method
Python String casefold() Method - Learn By Example
April 20, 2020 - Casefolding is similar to lowercasing but more aggressive because it is intended to remove all case distinctions in a string.
🌐
Codecademy
codecademy.com › docs › python › strings › .casefold()
Python | Strings | .casefold() | Codecademy
December 21, 2021 - The .casefold() method returns a copy of a string with all characters in lowercase. It is similar to .lower(), but whereas that method deals purely with ASCII text, .casefold() can also convert Unicode characters.
🌐
AskPython
askpython.com › python › string › python-string-casefold
Python String casefold() - AskPython
August 6, 2022 - my_str = "Hello from AskPython" casefolded_str = my_str.casefold() print(casefolded_str) ... This converts all uppercase letters to lowercase ones for the English alphabet. But what if the string has characters from another language, and in another encoding? The Python string casefold() method solves this problem.
🌐
Educative
educative.io › answers › what-is-casefold-in-python
What is casefold() in Python?
The casefold() method in Python converts all the uppercase letters in a string to lowercase letters.
🌐
Python Pool
pythonpool.com › home › tutorials › python casefold(): case-insensitive and unicode-safe matching
Python casefold(): Case-Insensitive and Unicode-Safe Matching
July 13, 2026 - Use casefold() when comparing user-facing text, usernames, search terms, tags, labels, or identifiers where capitalization should not matter. The official str.casefold documentation defines the method, the Python Unicode HOWTO explains Unicode ...