[{"data":1,"prerenderedAt":680},["ShallowReactive",2],{"guide-text-case-in-usernames":3},{"id":4,"title":5,"body":6,"date":672,"description":673,"extension":674,"meta":675,"navigation":225,"path":676,"readingTime":251,"seo":677,"stem":678,"__hash__":679},"guides\u002Fguides\u002Ftext-case-in-usernames.md","Text Case in Usernames and Display Names",{"type":7,"value":8,"toc":653},"minimark",[9,14,18,21,25,93,98,106,119,161,164,168,172,175,181,267,271,282,286,289,293,304,308,311,383,392,396,399,477,492,496,566,569,573,576,605,608,612,633,637,640,649],[10,11,13],"h2",{"id":12},"why-username-case-matters","Why Username Case Matters",[15,16,17],"p",{},"Usernames and display names seem simple — until you consider how case affects security, search, and user experience. Should usernames be case-sensitive? Can two users register \"JohnDoe\" and \"johndoe\"? What happens when someone searches for \"JANESMITH\" but the account is \"JaneSmith\"?",[15,19,20],{},"These questions have real-world consequences. Case handling errors lead to duplicate accounts, broken authentication, failed mentions, and frustrated users. Getting it right requires deliberate design decisions, not assumptions.",[10,22,24],{"id":23},"case-sensitive-vs-case-insensitive-systems","Case-Sensitive vs Case-Insensitive Systems",[26,27,28,47],"table",{},[29,30,31],"thead",{},[32,33,34,38,41,44],"tr",{},[35,36,37],"th",{},"Approach",[35,39,40],{},"Examples",[35,42,43],{},"Pros",[35,45,46],{},"Cons",[48,49,50,65,79],"tbody",{},[32,51,52,56,59,62],{},[53,54,55],"td",{},"Case-insensitive login",[53,57,58],{},"GitHub, Twitter, Gmail",[53,60,61],{},"User-friendly, prevents duplicate accounts",[53,63,64],{},"Must store canonical form",[32,66,67,70,73,76],{},[53,68,69],{},"Case-sensitive login",[53,71,72],{},"Linux, some APIs",[53,74,75],{},"Exact matching, fewer transformations",[53,77,78],{},"Users forget exact casing",[32,80,81,84,87,90],{},[53,82,83],{},"Case-insensitive login, preserved display",[53,85,86],{},"Most modern apps",[53,88,89],{},"Best UX — login forgiving, display accurate",[53,91,92],{},"More complex storage",[94,95,97],"h3",{"id":96},"the-industry-standard","The Industry Standard",[15,99,100,101,105],{},"Most modern web applications use ",[102,103,104],"strong",{},"case-insensitive authentication with preserved display names",":",[107,108,109,113,116],"ul",{},[110,111,112],"li",{},"Login: compare lowercased values",[110,114,115],{},"Display: show the user's preferred casing",[110,117,118],{},"Storage: store both canonical (lowercased) and display versions",[120,121,126],"pre",{"className":122,"code":123,"language":124,"meta":125,"style":125},"language-sql shiki shiki-themes github-light github-dark","CREATE TABLE users (\n  username_canonical VARCHAR(50) UNIQUE,  -- 'johndoe'\n  username_display   VARCHAR(50),          -- 'JohnDoe'\n  ...\n);\n","sql","",[127,128,129,137,143,149,155],"code",{"__ignoreMap":125},[130,131,134],"span",{"class":132,"line":133},"line",1,[130,135,136],{},"CREATE TABLE users (\n",[130,138,140],{"class":132,"line":139},2,[130,141,142],{},"  username_canonical VARCHAR(50) UNIQUE,  -- 'johndoe'\n",[130,144,146],{"class":132,"line":145},3,[130,147,148],{},"  username_display   VARCHAR(50),          -- 'JohnDoe'\n",[130,150,152],{"class":132,"line":151},4,[130,153,154],{},"  ...\n",[130,156,158],{"class":132,"line":157},5,[130,159,160],{},");\n",[15,162,163],{},"This prevents duplicate registrations while respecting the user's identity preference.",[10,165,167],{"id":166},"common-case-related-bugs","Common Case-Related Bugs",[94,169,171],{"id":170},"_1-duplicate-account-creation","1. Duplicate Account Creation",[15,173,174],{},"If registration checks are case-sensitive, \"JohnDoe\" and \"johndoe\" become separate accounts. Users who forget their exact casing may register again instead of logging in.",[15,176,177,180],{},[102,178,179],{},"Fix:"," Always compare usernames in a normalized form (lowercase) during registration.",[120,182,186],{"className":183,"code":184,"language":185,"meta":125,"style":125},"language-javascript shiki shiki-themes github-light github-dark","\u002F\u002F Bad\nconst existing = await db.users.findOne({ username: input })\n\n\u002F\u002F Good\nconst existing = await db.users.findOne({\n  username_canonical: input.toLowerCase()\n})\n","javascript",[127,187,188,194,221,227,232,249,261],{"__ignoreMap":125},[130,189,190],{"class":132,"line":133},[130,191,193],{"class":192},"sJ8bj","\u002F\u002F Bad\n",[130,195,196,200,204,207,210,214,218],{"class":132,"line":139},[130,197,199],{"class":198},"szBVR","const",[130,201,203],{"class":202},"sj4cs"," existing",[130,205,206],{"class":198}," =",[130,208,209],{"class":198}," await",[130,211,213],{"class":212},"sVt8B"," db.users.",[130,215,217],{"class":216},"sScJk","findOne",[130,219,220],{"class":212},"({ username: input })\n",[130,222,223],{"class":132,"line":145},[130,224,226],{"emptyLinePlaceholder":225},true,"\n",[130,228,229],{"class":132,"line":151},[130,230,231],{"class":192},"\u002F\u002F Good\n",[130,233,234,236,238,240,242,244,246],{"class":132,"line":157},[130,235,199],{"class":198},[130,237,203],{"class":202},[130,239,206],{"class":198},[130,241,209],{"class":198},[130,243,213],{"class":212},[130,245,217],{"class":216},[130,247,248],{"class":212},"({\n",[130,250,252,255,258],{"class":132,"line":251},6,[130,253,254],{"class":212},"  username_canonical: input.",[130,256,257],{"class":216},"toLowerCase",[130,259,260],{"class":212},"()\n",[130,262,264],{"class":132,"line":263},7,[130,265,266],{"class":212},"})\n",[94,268,270],{"id":269},"_2-mention-failures","2. @mention Failures",[15,272,273,274,277,278,281],{},"When ",[127,275,276],{},"@JohnDoe"," doesn't match ",[127,279,280],{},"johndoe"," in the database, mentions silently fail. Social platforms must normalize mentions before lookup.",[94,283,285],{"id":284},"_3-case-changed-login-confusion","3. Case-Changed Login Confusion",[15,287,288],{},"If a user changes their display name from \"JohnDoe\" to \"johnDoe\" but the system treats the old casing as a different account, they lose access to history, connections, or content.",[94,290,292],{"id":291},"_4-url-casing-inconsistencies","4. URL Casing Inconsistencies",[15,294,295,296,299,300,303],{},"Profile URLs like ",[127,297,298],{},"\u002FJohnDoe"," vs ",[127,301,302],{},"\u002Fjohndoe"," may route to different places or return 404s if the slug lookup is case-sensitive. Most platforms normalize URL slugs to lowercase.",[10,305,307],{"id":306},"display-name-vs-username","Display Name vs Username",[15,309,310],{},"Usernames and display names serve different purposes and should be handled differently:",[26,312,313,326],{},[29,314,315],{},[32,316,317,320,323],{},[35,318,319],{},"Property",[35,321,322],{},"Username",[35,324,325],{},"Display Name",[48,327,328,339,350,361,372],{},[32,329,330,333,336],{},[53,331,332],{},"Uniqueness",[53,334,335],{},"Must be unique",[53,337,338],{},"Can be shared",[32,340,341,344,347],{},[53,342,343],{},"Case sensitivity",[53,345,346],{},"Login: insensitive, lookup: stored canonical",[53,348,349],{},"Preserved as entered",[32,351,352,355,358],{},[53,353,354],{},"Characters",[53,356,357],{},"Restricted (alphanumeric, underscore)",[53,359,360],{},"Flexible (spaces, unicode)",[32,362,363,366,369],{},[53,364,365],{},"Change frequency",[53,367,368],{},"Rarely changed",[53,370,371],{},"Changed freely",[32,373,374,377,380],{},[53,375,376],{},"Used in URLs",[53,378,379],{},"Yes (lowercased)",[53,381,382],{},"No",[15,384,385,388,389,391],{},[102,386,387],{},"GitHub model:"," Username (",[127,390,280],{},") is case-insensitive for login, lowercased in URLs, and displayed with preferred casing. Display name (\"John Doe\") is separate and non-unique.",[10,393,395],{"id":394},"unicode-and-case-folding","Unicode and Case Folding",[15,397,398],{},"Lowercase transformation isn't just ASCII. Unicode case folding handles characters beyond a-z:",[120,400,402],{"className":183,"code":401,"language":185,"meta":125,"style":125},"\u002F\u002F ASCII only — misses Turkish İ, German ß\n'JOHN'.toLowerCase()  \u002F\u002F 'john'\n\n\u002F\u002F Proper Unicode case folding\n'İSTANBUL'.toLocaleLowerCase('tr')  \u002F\u002F 'istanbul' (Turkish locale)\n'STRAßE'.toLocaleLowerCase('de')    \u002F\u002F 'straße'\n",[127,403,404,409,426,430,435,457],{"__ignoreMap":125},[130,405,406],{"class":132,"line":133},[130,407,408],{"class":192},"\u002F\u002F ASCII only — misses Turkish İ, German ß\n",[130,410,411,415,418,420,423],{"class":132,"line":139},[130,412,414],{"class":413},"sZZnC","'JOHN'",[130,416,417],{"class":212},".",[130,419,257],{"class":216},[130,421,422],{"class":212},"()  ",[130,424,425],{"class":192},"\u002F\u002F 'john'\n",[130,427,428],{"class":132,"line":145},[130,429,226],{"emptyLinePlaceholder":225},[130,431,432],{"class":132,"line":151},[130,433,434],{"class":192},"\u002F\u002F Proper Unicode case folding\n",[130,436,437,440,442,445,448,451,454],{"class":132,"line":157},[130,438,439],{"class":413},"'İSTANBUL'",[130,441,417],{"class":212},[130,443,444],{"class":216},"toLocaleLowerCase",[130,446,447],{"class":212},"(",[130,449,450],{"class":413},"'tr'",[130,452,453],{"class":212},")  ",[130,455,456],{"class":192},"\u002F\u002F 'istanbul' (Turkish locale)\n",[130,458,459,462,464,466,468,471,474],{"class":132,"line":251},[130,460,461],{"class":413},"'STRAßE'",[130,463,417],{"class":212},[130,465,444],{"class":216},[130,467,447],{"class":212},[130,469,470],{"class":413},"'de'",[130,472,473],{"class":212},")    ",[130,475,476],{"class":192},"\u002F\u002F 'straße'\n",[15,478,479,480,483,484,487,488,491],{},"If your app serves international users, use locale-aware case conversion for both registration and login. The Turkish İ problem — where ",[127,481,482],{},"I.toLowerCase()"," returns ",[127,485,486],{},"ı"," in Turkish locale but ",[127,489,490],{},"i"," in English — is a classic source of authentication bugs.",[94,493,495],{"id":494},"best-practice-for-international-usernames","Best Practice for International Usernames",[120,497,499],{"className":183,"code":498,"language":185,"meta":125,"style":125},"function normalizeUsername(username) {\n  return username\n    .toLocaleLowerCase('en-US')  \u002F\u002F Consistent locale for canonical form\n    .normalize('NFC')            \u002F\u002F Normalize Unicode combining characters\n}\n",[127,500,501,518,526,543,561],{"__ignoreMap":125},[130,502,503,506,509,511,515],{"class":132,"line":133},[130,504,505],{"class":198},"function",[130,507,508],{"class":216}," normalizeUsername",[130,510,447],{"class":212},[130,512,514],{"class":513},"s4XuR","username",[130,516,517],{"class":212},") {\n",[130,519,520,523],{"class":132,"line":139},[130,521,522],{"class":198},"  return",[130,524,525],{"class":212}," username\n",[130,527,528,531,533,535,538,540],{"class":132,"line":145},[130,529,530],{"class":212},"    .",[130,532,444],{"class":216},[130,534,447],{"class":212},[130,536,537],{"class":413},"'en-US'",[130,539,453],{"class":212},[130,541,542],{"class":192},"\u002F\u002F Consistent locale for canonical form\n",[130,544,545,547,550,552,555,558],{"class":132,"line":151},[130,546,530],{"class":212},[130,548,549],{"class":216},"normalize",[130,551,447],{"class":212},[130,553,554],{"class":413},"'NFC'",[130,556,557],{"class":212},")            ",[130,559,560],{"class":192},"\u002F\u002F Normalize Unicode combining characters\n",[130,562,563],{"class":132,"line":157},[130,564,565],{"class":212},"}\n",[15,567,568],{},"Using a fixed locale for canonical storage avoids locale-dependent bugs while display names can use the user's locale.",[10,570,572],{"id":571},"search-and-autocomplete","Search and Autocomplete",[15,574,575],{},"When users search for other users, case-insensitive matching is expected. Most databases support this natively:",[120,577,579],{"className":122,"code":578,"language":124,"meta":125,"style":125},"-- PostgreSQL: use CITEXT or LOWER()\nSELECT * FROM users WHERE username_canonical = LOWER($1);\n\n-- MongoDB: use collation\ndb.users.find({ username: input }).collation({ locale: 'en', strength: 2 })\n",[127,580,581,586,591,595,600],{"__ignoreMap":125},[130,582,583],{"class":132,"line":133},[130,584,585],{},"-- PostgreSQL: use CITEXT or LOWER()\n",[130,587,588],{"class":132,"line":139},[130,589,590],{},"SELECT * FROM users WHERE username_canonical = LOWER($1);\n",[130,592,593],{"class":132,"line":145},[130,594,226],{"emptyLinePlaceholder":225},[130,596,597],{"class":132,"line":151},[130,598,599],{},"-- MongoDB: use collation\n",[130,601,602],{"class":132,"line":157},[130,603,604],{},"db.users.find({ username: input }).collation({ locale: 'en', strength: 2 })\n",[15,606,607],{},"For autocomplete, index the canonical form and match against the lowercased query prefix for consistent results.",[10,609,611],{"id":610},"related-guides","Related Guides",[107,613,614,621,627],{},[110,615,616],{},[617,618,620],"a",{"href":619},"\u002Fguides\u002Fnaming-conventions-guide","Naming Conventions Guide",[110,622,623],{},[617,624,626],{"href":625},"\u002Fguides\u002Fcamelcase-vs-snake-case","CamelCase vs Snake Case",[110,628,629],{},[617,630,632],{"href":631},"\u002Fguides\u002Fcode-readability-tips","Code Readability Tips",[10,634,636],{"id":635},"try-it-yourself","Try It Yourself",[15,638,639],{},"Need to normalize usernames or transform text casing? Our free case converter handles uppercase, lowercase, title case, and more — instantly.",[15,641,642,643],{},"👉 ",[617,644,646],{"href":645},"\u002Ftools\u002Fcase-converter",[102,647,648],{},"Free Case Converter",[650,651,652],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":125,"searchDepth":139,"depth":139,"links":654},[655,656,659,665,666,669,670,671],{"id":12,"depth":139,"text":13},{"id":23,"depth":139,"text":24,"children":657},[658],{"id":96,"depth":145,"text":97},{"id":166,"depth":139,"text":167,"children":660},[661,662,663,664],{"id":170,"depth":145,"text":171},{"id":269,"depth":145,"text":270},{"id":284,"depth":145,"text":285},{"id":291,"depth":145,"text":292},{"id":306,"depth":139,"text":307},{"id":394,"depth":139,"text":395,"children":667},[668],{"id":494,"depth":145,"text":495},{"id":571,"depth":139,"text":572},{"id":610,"depth":139,"text":611},{"id":635,"depth":139,"text":636},"2026-05-28","How case conversion affects usernames, display names, and searchability in web apps.","md",{"immutable":225},"\u002Fguides\u002Ftext-case-in-usernames",{"title":5,"description":673},"guides\u002Ftext-case-in-usernames","njwU_ySro0ejhXU7SsJlZjfWE5YjOJdok2pzg47A6AM",1780401337449]