[{"data":1,"prerenderedAt":8446},["ShallowReactive",2],{"blog-list":3},[4,663,1201,2545,3643,4207,4618,5120,5988,6767,7294,7759,8117],{"id":5,"title":6,"body":7,"category":652,"date":653,"description":654,"extension":655,"meta":656,"navigation":407,"path":657,"readingTime":422,"seo":658,"stem":659,"tool":660,"updated":661,"__hash__":662},"blog\u002Fblog\u002Fbase64-encoding-when-and-why.md","Base64 Encoding: When and Why",{"type":8,"value":9,"toc":630},"minimark",[10,14,17,22,25,64,75,85,91,95,176,190,194,199,202,235,270,274,284,290,293,297,300,304,307,350,354,358,361,365,368,372,379,383,387,443,447,501,505,558,562,614,618,626],[11,12,13],"p",{},"Base64 encoding converts binary data into a text representation using 64 printable ASCII characters. It is one of the most commonly used encoding schemes in web development — appearing in data URIs, email attachments, API authentication headers, and JWT tokens. Yet many developers confuse encoding with encryption, or use Base64 in situations where it adds overhead without benefit.",[11,15,16],{},"This guide explains how Base64 works, when to use it, and when not to.",[18,19,21],"h2",{"id":20},"how-base64-works","How Base64 Works",[11,23,24],{},"Base64 takes every 3 bytes (24 bits) of input and splits them into 4 groups of 6 bits each. Each 6-bit group maps to one of 64 characters:",[26,27,28,36,42,48,58],"ul",{},[29,30,31,35],"li",{},[32,33,34],"code",{},"A-Z"," (0-25)",[29,37,38,41],{},[32,39,40],{},"a-z"," (26-51)",[29,43,44,47],{},[32,45,46],{},"0-9"," (52-61)",[29,49,50,53,54,57],{},[32,51,52],{},"+"," (62) and ",[32,55,56],{},"\u002F"," (63)",[29,59,60,63],{},[32,61,62],{},"="," for padding when the input length is not a multiple of 3",[11,65,66,67,70,71,74],{},"For example, the text ",[32,68,69],{},"\"Hi\""," (2 bytes: ",[32,72,73],{},"0x48 0x69","):",[76,77,82],"pre",{"className":78,"code":80,"language":81},[79],"language-text","Binary:    01001000 01101001\n6-bit:     010010 000110 1001xx\nPadded:    010010 000110 100100\nBase64:    S      G      k      =\nResult:    \"SGk=\"\n","text",[32,83,80],{"__ignoreMap":84},"",[11,86,87,88,90],{},"The ",[32,89,62],{}," padding ensures the encoded output length is always a multiple of 4.",[18,92,94],{"id":93},"base64-variants","Base64 Variants",[96,97,98,117],"table",{},[99,100,101],"thead",{},[102,103,104,108,111,114],"tr",{},[105,106,107],"th",{},"Variant",[105,109,110],{},"Characters 62-63",[105,112,113],{},"Padding",[105,115,116],{},"Use case",[118,119,120,140,159],"tbody",{},[102,121,122,126,133,137],{},[123,124,125],"td",{},"Standard (RFC 4648)",[123,127,128,130,131],{},[32,129,52],{}," ",[32,132,56],{},[123,134,135],{},[32,136,62],{},[123,138,139],{},"Email (MIME), PEM certificates",[102,141,142,145,153,156],{},[123,143,144],{},"URL-safe (RFC 4648 §5)",[123,146,147,130,150],{},[32,148,149],{},"-",[32,151,152],{},"_",[123,154,155],{},"Optional",[123,157,158],{},"URLs, filenames, JWTs",[102,160,161,164,170,173],{},[123,162,163],{},"Base64url (no pad)",[123,165,166,130,168],{},[32,167,149],{},[32,169,152],{},[123,171,172],{},"None",[123,174,175],{},"JWTs, compact tokens",[11,177,178,179,181,182,184,185,181,187,189],{},"The URL-safe variant replaces ",[32,180,52],{}," with ",[32,183,149],{}," and ",[32,186,56],{},[32,188,152],{}," because the standard characters have special meaning in URLs and filenames.",[18,191,193],{"id":192},"when-to-use-base64","When to Use Base64",[195,196,198],"h3",{"id":197},"_1-embedding-binary-data-in-text-formats","1. Embedding binary data in text formats",[11,200,201],{},"HTML, CSS, JSON, and XML are text formats. To include an image, font, or other binary data inline, Base64 encode it:",[76,203,207],{"className":204,"code":205,"language":206,"meta":84,"style":84},"language-html shiki shiki-themes github-light github-dark","\u003Cimg src=\"data:image\u002Fpng;base64,iVBORw0KGgoAAAANS...\" \u002F>\n","html",[32,208,209],{"__ignoreMap":84},[210,211,214,218,222,226,228,232],"span",{"class":212,"line":213},"line",1,[210,215,217],{"class":216},"sVt8B","\u003C",[210,219,221],{"class":220},"s9eBZ","img",[210,223,225],{"class":224},"sScJk"," src",[210,227,62],{"class":216},[210,229,231],{"class":230},"sZZnC","\"data:image\u002Fpng;base64,iVBORw0KGgoAAAANS...\"",[210,233,234],{"class":216}," \u002F>\n",[76,236,240],{"className":237,"code":238,"language":239,"meta":84,"style":84},"language-css shiki shiki-themes github-light github-dark",".icon { background-image: url(data:image\u002Fsvg+xml;base64,PHN2Zy...); }\n","css",[32,241,242],{"__ignoreMap":84},[210,243,244,247,250,254,257,260,263,267],{"class":212,"line":213},[210,245,246],{"class":224},".icon",[210,248,249],{"class":216}," { ",[210,251,253],{"class":252},"sj4cs","background-image",[210,255,256],{"class":216},": ",[210,258,259],{"class":252},"url",[210,261,262],{"class":216},"(",[210,264,266],{"class":265},"s4XuR","data:image\u002Fsvg+xml;base64,PHN2Zy...",[210,268,269],{"class":216},"); }\n",[195,271,273],{"id":272},"_2-http-basic-authentication","2. HTTP Basic Authentication",[11,275,87,276,279,280,283],{},[32,277,278],{},"Authorization: Basic"," header encodes ",[32,281,282],{},"username:password"," in Base64:",[76,285,288],{"className":286,"code":287,"language":81},[79],"Authorization: Basic YWxpY2U6cGFzc3dvcmQ=\n",[32,289,287],{"__ignoreMap":84},[11,291,292],{},"This is encoding, not encryption — the credentials are readable by anyone who sees the header. Always use HTTPS.",[195,294,296],{"id":295},"_3-email-attachments-mime","3. Email attachments (MIME)",[11,298,299],{},"Email was designed for 7-bit ASCII text. Binary attachments are Base64-encoded within MIME (Multipurpose Internet Mail Extensions) parts so they survive transit through mail servers.",[195,301,303],{"id":302},"_4-storing-binary-data-in-json","4. Storing binary data in JSON",[11,305,306],{},"JSON has no binary type. Binary values like cryptographic keys, hashes, or file content are commonly Base64-encoded as strings:",[76,308,312],{"className":309,"code":310,"language":311,"meta":84,"style":84},"language-json shiki shiki-themes github-light github-dark","{\n  \"publicKey\": \"MIIBIjANBgkqhki...\",\n  \"signature\": \"MEUCIQC7...\"\n}\n","json",[32,313,314,319,333,344],{"__ignoreMap":84},[210,315,316],{"class":212,"line":213},[210,317,318],{"class":216},"{\n",[210,320,322,325,327,330],{"class":212,"line":321},2,[210,323,324],{"class":252},"  \"publicKey\"",[210,326,256],{"class":216},[210,328,329],{"class":230},"\"MIIBIjANBgkqhki...\"",[210,331,332],{"class":216},",\n",[210,334,336,339,341],{"class":212,"line":335},3,[210,337,338],{"class":252},"  \"signature\"",[210,340,256],{"class":216},[210,342,343],{"class":230},"\"MEUCIQC7...\"\n",[210,345,347],{"class":212,"line":346},4,[210,348,349],{"class":216},"}\n",[18,351,353],{"id":352},"when-not-to-use-base64","When NOT to Use Base64",[195,355,357],{"id":356},"not-for-security","Not for security",[11,359,360],{},"Base64 is not encryption. It is a reversible encoding with no key — anyone can decode it. Never Base64-encode passwords, tokens, or secrets and consider them \"hidden.\"",[195,362,364],{"id":363},"not-for-large-files","Not for large files",[11,366,367],{},"Base64 increases data size by approximately 33% (3 bytes become 4 characters). A 1 MB image becomes ~1.37 MB when Base64-encoded. For large assets, use direct binary transfer (multipart upload, binary HTTP body) instead.",[195,369,371],{"id":370},"not-for-url-parameters-usually","Not for URL parameters (usually)",[11,373,374,375,378],{},"While Base64url exists, URL-encoding the original data is often simpler. Base64 is warranted when the data is binary; for text data, URL encoding (",[32,376,377],{},"encodeURIComponent",") is more appropriate.",[18,380,382],{"id":381},"base64-in-code","Base64 in Code",[195,384,386],{"id":385},"javascript","JavaScript",[76,388,391],{"className":389,"code":390,"language":385,"meta":84,"style":84},"language-javascript shiki shiki-themes github-light github-dark","\u002F\u002F Encode\nbtoa('Hello World')           \u002F\u002F \"SGVsbG8gV29ybGQ=\"\n\n\u002F\u002F Decode\natob('SGVsbG8gV29ybGQ=')     \u002F\u002F \"Hello World\"\n\n\u002F\u002F For Unicode text (btoa only handles Latin-1)\nconst encode = (str) => btoa(new TextEncoder().encode(str).reduce((s, b) => s + String.fromCharCode(b), ''));\nconst decode = (b64) => new TextDecoder().decode(Uint8Array.from(atob(b64), c => c.charCodeAt(0)));\n",[32,392,393,398,403,409,414,420,425,431,437],{"__ignoreMap":84},[210,394,395],{"class":212,"line":213},[210,396,397],{},"\u002F\u002F Encode\n",[210,399,400],{"class":212,"line":321},[210,401,402],{},"btoa('Hello World')           \u002F\u002F \"SGVsbG8gV29ybGQ=\"\n",[210,404,405],{"class":212,"line":335},[210,406,408],{"emptyLinePlaceholder":407},true,"\n",[210,410,411],{"class":212,"line":346},[210,412,413],{},"\u002F\u002F Decode\n",[210,415,417],{"class":212,"line":416},5,[210,418,419],{},"atob('SGVsbG8gV29ybGQ=')     \u002F\u002F \"Hello World\"\n",[210,421,423],{"class":212,"line":422},6,[210,424,408],{"emptyLinePlaceholder":407},[210,426,428],{"class":212,"line":427},7,[210,429,430],{},"\u002F\u002F For Unicode text (btoa only handles Latin-1)\n",[210,432,434],{"class":212,"line":433},8,[210,435,436],{},"const encode = (str) => btoa(new TextEncoder().encode(str).reduce((s, b) => s + String.fromCharCode(b), ''));\n",[210,438,440],{"class":212,"line":439},9,[210,441,442],{},"const decode = (b64) => new TextDecoder().decode(Uint8Array.from(atob(b64), c => c.charCodeAt(0)));\n",[195,444,446],{"id":445},"python","Python",[76,448,451],{"className":449,"code":450,"language":445,"meta":84,"style":84},"language-python shiki shiki-themes github-light github-dark","import base64\n\n# Encode\nbase64.b64encode(b'Hello World')        # b'SGVsbG8gV29ybGQ='\n\n# Decode\nbase64.b64decode('SGVsbG8gV29ybGQ=')    # b'Hello World'\n\n# URL-safe\nbase64.urlsafe_b64encode(b'data')       # b'ZGF0YQ=='\n",[32,452,453,458,462,467,472,476,481,486,490,495],{"__ignoreMap":84},[210,454,455],{"class":212,"line":213},[210,456,457],{},"import base64\n",[210,459,460],{"class":212,"line":321},[210,461,408],{"emptyLinePlaceholder":407},[210,463,464],{"class":212,"line":335},[210,465,466],{},"# Encode\n",[210,468,469],{"class":212,"line":346},[210,470,471],{},"base64.b64encode(b'Hello World')        # b'SGVsbG8gV29ybGQ='\n",[210,473,474],{"class":212,"line":416},[210,475,408],{"emptyLinePlaceholder":407},[210,477,478],{"class":212,"line":422},[210,479,480],{},"# Decode\n",[210,482,483],{"class":212,"line":427},[210,484,485],{},"base64.b64decode('SGVsbG8gV29ybGQ=')    # b'Hello World'\n",[210,487,488],{"class":212,"line":433},[210,489,408],{"emptyLinePlaceholder":407},[210,491,492],{"class":212,"line":439},[210,493,494],{},"# URL-safe\n",[210,496,498],{"class":212,"line":497},10,[210,499,500],{},"base64.urlsafe_b64encode(b'data')       # b'ZGF0YQ=='\n",[195,502,504],{"id":503},"command-line","Command Line",[76,506,510],{"className":507,"code":508,"language":509,"meta":84,"style":84},"language-bash shiki shiki-themes github-light github-dark","# Encode\necho -n 'Hello World' | base64\n\n# Decode\necho 'SGVsbG8gV29ybGQ=' | base64 -d\n","bash",[32,511,512,517,535,539,543],{"__ignoreMap":84},[210,513,514],{"class":212,"line":213},[210,515,466],{"class":516},"sJ8bj",[210,518,519,522,525,528,532],{"class":212,"line":321},[210,520,521],{"class":252},"echo",[210,523,524],{"class":252}," -n",[210,526,527],{"class":230}," 'Hello World'",[210,529,531],{"class":530},"szBVR"," |",[210,533,534],{"class":224}," base64\n",[210,536,537],{"class":212,"line":335},[210,538,408],{"emptyLinePlaceholder":407},[210,540,541],{"class":212,"line":346},[210,542,480],{"class":516},[210,544,545,547,550,552,555],{"class":212,"line":416},[210,546,521],{"class":252},[210,548,549],{"class":230}," 'SGVsbG8gV29ybGQ='",[210,551,531],{"class":530},[210,553,554],{"class":224}," base64",[210,556,557],{"class":252}," -d\n",[18,559,561],{"id":560},"common-mistakes","Common Mistakes",[563,564,565,583,589,598],"ol",{},[29,566,567,575,576,578,579,582],{},[568,569,570,571,574],"strong",{},"Using ",[32,572,573],{},"btoa()"," with Unicode"," — ",[32,577,573],{}," only handles Latin-1 characters. Encoding emoji or non-Latin text throws an error. Use ",[32,580,581],{},"TextEncoder"," first.",[29,584,585,588],{},[568,586,587],{},"Double encoding"," — encoding data that is already Base64-encoded. The output is valid Base64 but decoding once gives you Base64 text, not the original data.",[29,590,591,594,595,597],{},[568,592,593],{},"Missing padding"," — some systems strip ",[32,596,62],{}," padding. Most decoders handle this, but some strict parsers reject unpadded input.",[29,599,600,603,604,184,606,608,609,184,611,613],{},[568,601,602],{},"Standard vs URL-safe confusion"," — using ",[32,605,52],{},[32,607,56],{}," in URLs causes parsing errors. Use Base64url (",[32,610,149],{},[32,612,152],{},") for anything that goes in a URL or filename.",[18,615,617],{"id":616},"try-it","Try It",[11,619,620,625],{},[621,622,624],"a",{"href":623},"\u002Ftools\u002Fencoder-decoder","StackCache Base64 Encoder & Decoder"," converts between text and Base64 (standard and URL-safe), URL encoding, and HTML entities — all locally in your browser with no upload.",[627,628,629],"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 .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}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 .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}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}",{"title":84,"searchDepth":321,"depth":321,"links":631},[632,633,634,640,645,650,651],{"id":20,"depth":321,"text":21},{"id":93,"depth":321,"text":94},{"id":192,"depth":321,"text":193,"children":635},[636,637,638,639],{"id":197,"depth":335,"text":198},{"id":272,"depth":335,"text":273},{"id":295,"depth":335,"text":296},{"id":302,"depth":335,"text":303},{"id":352,"depth":321,"text":353,"children":641},[642,643,644],{"id":356,"depth":335,"text":357},{"id":363,"depth":335,"text":364},{"id":370,"depth":335,"text":371},{"id":381,"depth":321,"text":382,"children":646},[647,648,649],{"id":385,"depth":335,"text":386},{"id":445,"depth":335,"text":446},{"id":503,"depth":335,"text":504},{"id":560,"depth":321,"text":561},{"id":616,"depth":321,"text":617},"Guides","2026-09-08","Learn what Base64 encoding is, how it works, when to use it, and common misconceptions. Includes examples in JavaScript, Python, and the command line.","md",{},"\u002Fblog\u002Fbase64-encoding-when-and-why",{"title":6,"description":654},"blog\u002Fbase64-encoding-when-and-why","encoder-decoder",null,"otS6m68e5moQQ2tRw31iYs-UML6OEgTNAiXhmoLTzX4",{"id":664,"title":665,"body":666,"category":652,"date":653,"description":1194,"extension":655,"meta":1195,"navigation":407,"path":1196,"readingTime":422,"seo":1197,"stem":1198,"tool":1199,"updated":661,"__hash__":1200},"blog\u002Fblog\u002Fcron-expression-syntax-for-beginners.md","Cron Expression Syntax for Beginners",{"type":8,"value":667,"toc":1171},[668,671,674,678,681,687,690,723,727,841,845,849,855,859,874,880,884,890,893,897,903,907,923,929,937,943,962,969,973,977,983,987,993,997,1003,1007,1013,1017,1023,1025,1074,1078,1081,1161,1163],[11,669,670],{},"Cron is the standard job scheduler on Unix and Linux systems. It runs commands on a schedule defined by a five-field expression. Whether you are scheduling database backups, log rotation, CI\u002FCD pipelines, or Kubernetes CronJobs, understanding cron syntax is an essential skill.",[11,672,673],{},"This guide teaches the five-field format from scratch with practical examples you can use today.",[18,675,677],{"id":676},"the-five-fields","The Five Fields",[11,679,680],{},"A cron expression has five fields separated by spaces:",[76,682,685],{"className":683,"code":684,"language":81},[79],"┌───────────── minute (0-59)\n│ ┌───────────── hour (0-23)\n│ │ ┌───────────── day of month (1-31)\n│ │ │ ┌───────────── month (1-12)\n│ │ │ │ ┌───────────── day of week (0-6, Sun=0)\n│ │ │ │ │\n* * * * *\n",[32,686,684],{"__ignoreMap":84},[11,688,689],{},"Each field accepts:",[26,691,692,698,704,710,716],{},[29,693,694,695],{},"A specific value: ",[32,696,697],{},"5",[29,699,700,701],{},"A wildcard (any value): ",[32,702,703],{},"*",[29,705,706,707],{},"A range: ",[32,708,709],{},"1-5",[29,711,712,713],{},"A list: ",[32,714,715],{},"1,3,5",[29,717,718,719,722],{},"A step: ",[32,720,721],{},"*\u002F15"," (every 15th value)",[18,724,726],{"id":725},"common-examples","Common Examples",[96,728,729,739],{},[99,730,731],{},[102,732,733,736],{},[105,734,735],{},"Expression",[105,737,738],{},"Schedule",[118,740,741,751,761,771,781,791,801,811,821,831],{},[102,742,743,748],{},[123,744,745],{},[32,746,747],{},"* * * * *",[123,749,750],{},"Every minute",[102,752,753,758],{},[123,754,755],{},[32,756,757],{},"0 * * * *",[123,759,760],{},"Every hour (at minute 0)",[102,762,763,768],{},[123,764,765],{},[32,766,767],{},"0 0 * * *",[123,769,770],{},"Daily at midnight",[102,772,773,778],{},[123,774,775],{},[32,776,777],{},"0 9 * * 1-5",[123,779,780],{},"Weekdays at 9:00 AM",[102,782,783,788],{},[123,784,785],{},[32,786,787],{},"0 0 1 * *",[123,789,790],{},"First of every month at midnight",[102,792,793,798],{},[123,794,795],{},[32,796,797],{},"*\u002F15 * * * *",[123,799,800],{},"Every 15 minutes",[102,802,803,808],{},[123,804,805],{},[32,806,807],{},"0 *\u002F6 * * *",[123,809,810],{},"Every 6 hours",[102,812,813,818],{},[123,814,815],{},[32,816,817],{},"30 2 * * 0",[123,819,820],{},"Sundays at 2:30 AM",[102,822,823,828],{},[123,824,825],{},[32,826,827],{},"0 9,17 * * *",[123,829,830],{},"At 9:00 AM and 5:00 PM daily",[102,832,833,838],{},[123,834,835],{},[32,836,837],{},"0 0 * * 1",[123,839,840],{},"Every Monday at midnight",[18,842,844],{"id":843},"field-details","Field Details",[195,846,848],{"id":847},"minute-0-59","Minute (0-59)",[76,850,853],{"className":851,"code":852,"language":81},[79],"0      → at the top of the hour\n30     → at half past\n*\u002F5    → every 5 minutes (0, 5, 10, 15, ...)\n5,35   → at minutes 5 and 35\n",[32,854,852],{"__ignoreMap":84},[195,856,858],{"id":857},"hour-0-23","Hour (0-23)",[11,860,861,862,865,866,869,870,873],{},"Uses 24-hour format. ",[32,863,864],{},"0"," is midnight, ",[32,867,868],{},"12"," is noon, ",[32,871,872],{},"23"," is 11 PM.",[76,875,878],{"className":876,"code":877,"language":81},[79],"9      → 9:00 AM\n*\u002F2    → every 2 hours (0, 2, 4, 6, ...)\n9-17   → every hour from 9 AM to 5 PM\n",[32,879,877],{"__ignoreMap":84},[195,881,883],{"id":882},"day-of-month-1-31","Day of Month (1-31)",[76,885,888],{"className":886,"code":887,"language":81},[79],"1      → first of the month\n15     → fifteenth\n1,15   → first and fifteenth\n",[32,889,887],{"__ignoreMap":84},[11,891,892],{},"Not all months have 31 days. If you schedule day 31, the job skips months with fewer days.",[195,894,896],{"id":895},"month-1-12","Month (1-12)",[76,898,901],{"className":899,"code":900,"language":81},[79],"1      → January\n6      → June\n1-3    → January through March\n*\u002F3    → every 3 months (Jan, Apr, Jul, Oct)\n",[32,902,900],{"__ignoreMap":84},[195,904,906],{"id":905},"day-of-week-0-6","Day of Week (0-6)",[11,908,909,184,911,914,915,918,919,922],{},[32,910,864],{},[32,912,913],{},"7"," both mean Sunday. ",[32,916,917],{},"1"," = Monday through ",[32,920,921],{},"6"," = Saturday.",[76,924,927],{"className":925,"code":926,"language":81},[79],"0      → Sunday\n1-5    → Monday through Friday (weekdays)\n6,0    → weekends\n",[32,928,926],{"__ignoreMap":84},[18,930,932,933,936],{"id":931},"step-syntax-n","Step Syntax (",[32,934,935],{},"*\u002Fn",")",[11,938,939,940,942],{},"The step syntax ",[32,941,935],{}," means \"every nth value starting from the field minimum\":",[26,944,945,950,956],{},[29,946,947,949],{},[32,948,721],{}," in the minute field → 0, 15, 30, 45",[29,951,952,955],{},[32,953,954],{},"*\u002F6"," in the hour field → 0, 6, 12, 18",[29,957,958,961],{},[32,959,960],{},"*\u002F2"," in the day-of-week field → 0, 2, 4, 6",[11,963,964,965,968],{},"You can combine steps with ranges: ",[32,966,967],{},"1-30\u002F5"," means every 5th value from 1 to 30 (1, 6, 11, 16, 21, 26).",[18,970,972],{"id":971},"real-world-examples","Real-World Examples",[195,974,976],{"id":975},"database-backup-every-night-at-2-am","Database backup every night at 2 AM",[76,978,981],{"className":979,"code":980,"language":81},[79],"0 2 * * *\n",[32,982,980],{"__ignoreMap":84},[195,984,986],{"id":985},"log-rotation-every-sunday-at-330-am","Log rotation every Sunday at 3:30 AM",[76,988,991],{"className":989,"code":990,"language":81},[79],"30 3 * * 0\n",[32,992,990],{"__ignoreMap":84},[195,994,996],{"id":995},"health-check-every-5-minutes-during-business-hours","Health check every 5 minutes during business hours",[76,998,1001],{"className":999,"code":1000,"language":81},[79],"*\u002F5 9-17 * * 1-5\n",[32,1002,1000],{"__ignoreMap":84},[195,1004,1006],{"id":1005},"monthly-report-on-the-1st-at-8-am","Monthly report on the 1st at 8 AM",[76,1008,1011],{"className":1009,"code":1010,"language":81},[79],"0 8 1 * *\n",[32,1012,1010],{"__ignoreMap":84},[195,1014,1016],{"id":1015},"deploy-to-staging-every-weekday-at-6-pm","Deploy to staging every weekday at 6 PM",[76,1018,1021],{"className":1019,"code":1020,"language":81},[79],"0 18 * * 1-5\n",[32,1022,1020],{"__ignoreMap":84},[18,1024,561],{"id":560},[563,1026,1027,1038,1044,1053,1065],{},[29,1028,1029,1032,1033,1037],{},[568,1030,1031],{},"Confusing day-of-month and day-of-week"," — if both are set to non-wildcard values, most cron implementations run when ",[1034,1035,1036],"em",{},"either"," matches (OR logic), not when both match (AND logic). This catches many people.",[29,1039,1040,1043],{},[568,1041,1042],{},"Timezone confusion"," — system cron uses the server's timezone. Kubernetes CronJobs default to UTC. Always specify which timezone your schedule targets.",[29,1045,1046,575,1049,1052],{},[568,1047,1048],{},"Running at boot, not by schedule",[32,1050,1051],{},"@reboot"," is a special string, not a cron expression. It runs once when the cron daemon starts.",[29,1054,1055,575,1061,1064],{},[568,1056,1057,1058,1060],{},"Forgetting that ",[32,1059,935],{}," starts at 0",[32,1062,1063],{},"*\u002F10"," in the hour field runs at 0:00, 10:00, 20:00 — not at the current time plus 10 hours.",[29,1066,1067,1070,1071],{},[568,1068,1069],{},"Output accumulation"," — cron emails stdout and stderr to the user. Redirect output to avoid filling the mailbox: ",[32,1072,1073],{},"0 * * * * \u002Fpath\u002Fto\u002Fscript > \u002Fdev\u002Fnull 2>&1",[18,1075,1077],{"id":1076},"special-strings","Special Strings",[11,1079,1080],{},"Most cron implementations support these shortcuts:",[96,1082,1083,1093],{},[99,1084,1085],{},[102,1086,1087,1090],{},[105,1088,1089],{},"String",[105,1091,1092],{},"Equivalent",[118,1094,1095,1107,1118,1130,1141,1152],{},[102,1096,1097,1102],{},[123,1098,1099],{},[32,1100,1101],{},"@yearly",[123,1103,1104],{},[32,1105,1106],{},"0 0 1 1 *",[102,1108,1109,1114],{},[123,1110,1111],{},[32,1112,1113],{},"@monthly",[123,1115,1116],{},[32,1117,787],{},[102,1119,1120,1125],{},[123,1121,1122],{},[32,1123,1124],{},"@weekly",[123,1126,1127],{},[32,1128,1129],{},"0 0 * * 0",[102,1131,1132,1137],{},[123,1133,1134],{},[32,1135,1136],{},"@daily",[123,1138,1139],{},[32,1140,767],{},[102,1142,1143,1148],{},[123,1144,1145],{},[32,1146,1147],{},"@hourly",[123,1149,1150],{},[32,1151,757],{},[102,1153,1154,1158],{},[123,1155,1156],{},[32,1157,1051],{},[123,1159,1160],{},"Run once at startup",[18,1162,617],{"id":616},[11,1164,1165,1166,1170],{},"Build and validate cron expressions interactively with ",[621,1167,1169],{"href":1168},"\u002Ftools\u002Fcron-builder","StackCache Cron Schedule Builder",". It shows the next execution times and translates expressions into plain English — all in your browser with no account needed.",{"title":84,"searchDepth":321,"depth":321,"links":1172},[1173,1174,1175,1182,1184,1191,1192,1193],{"id":676,"depth":321,"text":677},{"id":725,"depth":321,"text":726},{"id":843,"depth":321,"text":844,"children":1176},[1177,1178,1179,1180,1181],{"id":847,"depth":335,"text":848},{"id":857,"depth":335,"text":858},{"id":882,"depth":335,"text":883},{"id":895,"depth":335,"text":896},{"id":905,"depth":335,"text":906},{"id":931,"depth":321,"text":1183},"Step Syntax (*\u002Fn)",{"id":971,"depth":321,"text":972,"children":1185},[1186,1187,1188,1189,1190],{"id":975,"depth":335,"text":976},{"id":985,"depth":335,"text":986},{"id":995,"depth":335,"text":996},{"id":1005,"depth":335,"text":1006},{"id":1015,"depth":335,"text":1016},{"id":560,"depth":321,"text":561},{"id":1076,"depth":321,"text":1077},{"id":616,"depth":321,"text":617},"Learn the five-field Unix cron expression format with practical examples. Covers minutes, hours, days, months, weekdays, and common scheduling patterns.",{},"\u002Fblog\u002Fcron-expression-syntax-for-beginners",{"title":665,"description":1194},"blog\u002Fcron-expression-syntax-for-beginners","cron-builder","KxhoNyTFaunqdcAL5A9Of43C0VGfnKMmb9tI-g2ukZw",{"id":1202,"title":1203,"body":1204,"category":2537,"date":653,"description":2538,"extension":655,"meta":2539,"navigation":407,"path":2540,"readingTime":433,"seo":2541,"stem":2542,"tool":2543,"updated":661,"__hash__":2544},"blog\u002Fblog\u002Fdocker-compose-file-reference.md","Docker Compose File Reference",{"type":8,"value":1205,"toc":2517},[1206,1221,1224,1228,1405,1418,1421,1425,1514,1518,1560,1570,1588,1592,1646,1649,1690,1693,1720,1724,1806,1810,1853,1859,1863,1886,1890,1961,1964,2062,2065,2069,2073,2340,2344,2350,2439,2445,2447,2503,2507,2514],[11,1207,1208,1209,1212,1213,1216,1217,1220],{},"Docker Compose defines multi-container applications in a single YAML file. Instead of running multiple ",[32,1210,1211],{},"docker run"," commands with complex flags, you declare your entire stack — web servers, databases, caches, workers — in ",[32,1214,1215],{},"compose.yaml"," and bring it up with ",[32,1218,1219],{},"docker compose up",".",[11,1222,1223],{},"This reference covers the most commonly used Compose directives with practical examples.",[18,1225,1227],{"id":1226},"basic-structure","Basic Structure",[76,1229,1233],{"className":1230,"code":1231,"language":1232,"meta":84,"style":84},"language-yaml shiki shiki-themes github-light github-dark","services:\n  web:\n    image: nginx:alpine\n    ports:\n      - \"8080:80\"\n  \n  api:\n    build: .\u002Fapi\n    ports:\n      - \"3000:3000\"\n    depends_on:\n      - db\n  \n  db:\n    image: postgres:16\n    environment:\n      POSTGRES_PASSWORD: secret\n    volumes:\n      - pgdata:\u002Fvar\u002Flib\u002Fpostgresql\u002Fdata\n\nvolumes:\n  pgdata:\n","yaml",[32,1234,1235,1243,1250,1260,1267,1275,1280,1287,1297,1303,1310,1318,1326,1331,1339,1349,1357,1368,1376,1384,1389,1397],{"__ignoreMap":84},[210,1236,1237,1240],{"class":212,"line":213},[210,1238,1239],{"class":220},"services",[210,1241,1242],{"class":216},":\n",[210,1244,1245,1248],{"class":212,"line":321},[210,1246,1247],{"class":220},"  web",[210,1249,1242],{"class":216},[210,1251,1252,1255,1257],{"class":212,"line":335},[210,1253,1254],{"class":220},"    image",[210,1256,256],{"class":216},[210,1258,1259],{"class":230},"nginx:alpine\n",[210,1261,1262,1265],{"class":212,"line":346},[210,1263,1264],{"class":220},"    ports",[210,1266,1242],{"class":216},[210,1268,1269,1272],{"class":212,"line":416},[210,1270,1271],{"class":216},"      - ",[210,1273,1274],{"class":230},"\"8080:80\"\n",[210,1276,1277],{"class":212,"line":422},[210,1278,1279],{"class":216},"  \n",[210,1281,1282,1285],{"class":212,"line":427},[210,1283,1284],{"class":220},"  api",[210,1286,1242],{"class":216},[210,1288,1289,1292,1294],{"class":212,"line":433},[210,1290,1291],{"class":220},"    build",[210,1293,256],{"class":216},[210,1295,1296],{"class":230},".\u002Fapi\n",[210,1298,1299,1301],{"class":212,"line":439},[210,1300,1264],{"class":220},[210,1302,1242],{"class":216},[210,1304,1305,1307],{"class":212,"line":497},[210,1306,1271],{"class":216},[210,1308,1309],{"class":230},"\"3000:3000\"\n",[210,1311,1313,1316],{"class":212,"line":1312},11,[210,1314,1315],{"class":220},"    depends_on",[210,1317,1242],{"class":216},[210,1319,1321,1323],{"class":212,"line":1320},12,[210,1322,1271],{"class":216},[210,1324,1325],{"class":230},"db\n",[210,1327,1329],{"class":212,"line":1328},13,[210,1330,1279],{"class":216},[210,1332,1334,1337],{"class":212,"line":1333},14,[210,1335,1336],{"class":220},"  db",[210,1338,1242],{"class":216},[210,1340,1342,1344,1346],{"class":212,"line":1341},15,[210,1343,1254],{"class":220},[210,1345,256],{"class":216},[210,1347,1348],{"class":230},"postgres:16\n",[210,1350,1352,1355],{"class":212,"line":1351},16,[210,1353,1354],{"class":220},"    environment",[210,1356,1242],{"class":216},[210,1358,1360,1363,1365],{"class":212,"line":1359},17,[210,1361,1362],{"class":220},"      POSTGRES_PASSWORD",[210,1364,256],{"class":216},[210,1366,1367],{"class":230},"secret\n",[210,1369,1371,1374],{"class":212,"line":1370},18,[210,1372,1373],{"class":220},"    volumes",[210,1375,1242],{"class":216},[210,1377,1379,1381],{"class":212,"line":1378},19,[210,1380,1271],{"class":216},[210,1382,1383],{"class":230},"pgdata:\u002Fvar\u002Flib\u002Fpostgresql\u002Fdata\n",[210,1385,1387],{"class":212,"line":1386},20,[210,1388,408],{"emptyLinePlaceholder":407},[210,1390,1392,1395],{"class":212,"line":1391},21,[210,1393,1394],{"class":220},"volumes",[210,1396,1242],{"class":216},[210,1398,1400,1403],{"class":212,"line":1399},22,[210,1401,1402],{"class":220},"  pgdata",[210,1404,1242],{"class":216},[11,1406,1407,1408,1410,1411,1413,1414,1417],{},"A Compose file has three top-level keys: ",[32,1409,1239],{}," (required), ",[32,1412,1394],{}," (optional), and ",[32,1415,1416],{},"networks"," (optional).",[18,1419,1420],{"id":1239},"Services",[195,1422,1424],{"id":1423},"image-vs-build","Image vs Build",[76,1426,1428],{"className":1230,"code":1427,"language":1232,"meta":84,"style":84},"services:\n  # Use a pre-built image\n  redis:\n    image: redis:7-alpine\n\n  # Build from a Dockerfile\n  api:\n    build:\n      context: .\u002Fapi\n      dockerfile: Dockerfile\n      args:\n        NODE_ENV: production\n",[32,1429,1430,1436,1441,1448,1457,1461,1466,1472,1478,1487,1497,1504],{"__ignoreMap":84},[210,1431,1432,1434],{"class":212,"line":213},[210,1433,1239],{"class":220},[210,1435,1242],{"class":216},[210,1437,1438],{"class":212,"line":321},[210,1439,1440],{"class":516},"  # Use a pre-built image\n",[210,1442,1443,1446],{"class":212,"line":335},[210,1444,1445],{"class":220},"  redis",[210,1447,1242],{"class":216},[210,1449,1450,1452,1454],{"class":212,"line":346},[210,1451,1254],{"class":220},[210,1453,256],{"class":216},[210,1455,1456],{"class":230},"redis:7-alpine\n",[210,1458,1459],{"class":212,"line":416},[210,1460,408],{"emptyLinePlaceholder":407},[210,1462,1463],{"class":212,"line":422},[210,1464,1465],{"class":516},"  # Build from a Dockerfile\n",[210,1467,1468,1470],{"class":212,"line":427},[210,1469,1284],{"class":220},[210,1471,1242],{"class":216},[210,1473,1474,1476],{"class":212,"line":433},[210,1475,1291],{"class":220},[210,1477,1242],{"class":216},[210,1479,1480,1483,1485],{"class":212,"line":439},[210,1481,1482],{"class":220},"      context",[210,1484,256],{"class":216},[210,1486,1296],{"class":230},[210,1488,1489,1492,1494],{"class":212,"line":497},[210,1490,1491],{"class":220},"      dockerfile",[210,1493,256],{"class":216},[210,1495,1496],{"class":230},"Dockerfile\n",[210,1498,1499,1502],{"class":212,"line":1312},[210,1500,1501],{"class":220},"      args",[210,1503,1242],{"class":216},[210,1505,1506,1509,1511],{"class":212,"line":1320},[210,1507,1508],{"class":220},"        NODE_ENV",[210,1510,256],{"class":216},[210,1512,1513],{"class":230},"production\n",[195,1515,1517],{"id":1516},"ports","Ports",[76,1519,1521],{"className":1230,"code":1520,"language":1232,"meta":84,"style":84},"ports:\n  - \"8080:80\"          # host:container\n  - \"3000:3000\"        # same port\n  - \"127.0.0.1:9090:9090\"  # bind to localhost only\n",[32,1522,1523,1529,1540,1550],{"__ignoreMap":84},[210,1524,1525,1527],{"class":212,"line":213},[210,1526,1516],{"class":220},[210,1528,1242],{"class":216},[210,1530,1531,1534,1537],{"class":212,"line":321},[210,1532,1533],{"class":216},"  - ",[210,1535,1536],{"class":230},"\"8080:80\"",[210,1538,1539],{"class":516},"          # host:container\n",[210,1541,1542,1544,1547],{"class":212,"line":335},[210,1543,1533],{"class":216},[210,1545,1546],{"class":230},"\"3000:3000\"",[210,1548,1549],{"class":516},"        # same port\n",[210,1551,1552,1554,1557],{"class":212,"line":346},[210,1553,1533],{"class":216},[210,1555,1556],{"class":230},"\"127.0.0.1:9090:9090\"",[210,1558,1559],{"class":516},"  # bind to localhost only\n",[11,1561,1562,1563,1566,1567,1569],{},"Use ",[32,1564,1565],{},"expose"," instead of ",[32,1568,1516],{}," for container-to-container communication without host binding:",[76,1571,1573],{"className":1230,"code":1572,"language":1232,"meta":84,"style":84},"expose:\n  - \"6379\"\n",[32,1574,1575,1581],{"__ignoreMap":84},[210,1576,1577,1579],{"class":212,"line":213},[210,1578,1565],{"class":220},[210,1580,1242],{"class":216},[210,1582,1583,1585],{"class":212,"line":321},[210,1584,1533],{"class":216},[210,1586,1587],{"class":230},"\"6379\"\n",[195,1589,1591],{"id":1590},"environment-variables","Environment Variables",[76,1593,1595],{"className":1230,"code":1594,"language":1232,"meta":84,"style":84},"environment:\n  DATABASE_URL: postgres:\u002F\u002Fuser:pass@db:5432\u002Fmyapp\n  NODE_ENV: production\n\n# Or from a file\nenv_file:\n  - .env\n",[32,1596,1597,1604,1614,1623,1627,1632,1639],{"__ignoreMap":84},[210,1598,1599,1602],{"class":212,"line":213},[210,1600,1601],{"class":220},"environment",[210,1603,1242],{"class":216},[210,1605,1606,1609,1611],{"class":212,"line":321},[210,1607,1608],{"class":220},"  DATABASE_URL",[210,1610,256],{"class":216},[210,1612,1613],{"class":230},"postgres:\u002F\u002Fuser:pass@db:5432\u002Fmyapp\n",[210,1615,1616,1619,1621],{"class":212,"line":335},[210,1617,1618],{"class":220},"  NODE_ENV",[210,1620,256],{"class":216},[210,1622,1513],{"class":230},[210,1624,1625],{"class":212,"line":346},[210,1626,408],{"emptyLinePlaceholder":407},[210,1628,1629],{"class":212,"line":416},[210,1630,1631],{"class":516},"# Or from a file\n",[210,1633,1634,1637],{"class":212,"line":422},[210,1635,1636],{"class":220},"env_file",[210,1638,1242],{"class":216},[210,1640,1641,1643],{"class":212,"line":427},[210,1642,1533],{"class":216},[210,1644,1645],{"class":230},".env\n",[195,1647,1648],{"id":1394},"Volumes",[76,1650,1652],{"className":1230,"code":1651,"language":1232,"meta":84,"style":84},"volumes:\n  - .\u002Fsrc:\u002Fapp\u002Fsrc          # bind mount (host path)\n  - node_modules:\u002Fapp\u002Fnode_modules  # named volume\n  - \u002Fapp\u002Fdist               # anonymous volume\n",[32,1653,1654,1660,1670,1680],{"__ignoreMap":84},[210,1655,1656,1658],{"class":212,"line":213},[210,1657,1394],{"class":220},[210,1659,1242],{"class":216},[210,1661,1662,1664,1667],{"class":212,"line":321},[210,1663,1533],{"class":216},[210,1665,1666],{"class":230},".\u002Fsrc:\u002Fapp\u002Fsrc",[210,1668,1669],{"class":516},"          # bind mount (host path)\n",[210,1671,1672,1674,1677],{"class":212,"line":335},[210,1673,1533],{"class":216},[210,1675,1676],{"class":230},"node_modules:\u002Fapp\u002Fnode_modules",[210,1678,1679],{"class":516},"  # named volume\n",[210,1681,1682,1684,1687],{"class":212,"line":346},[210,1683,1533],{"class":216},[210,1685,1686],{"class":230},"\u002Fapp\u002Fdist",[210,1688,1689],{"class":516},"               # anonymous volume\n",[11,1691,1692],{},"Named volumes persist data across container restarts and recreations:",[76,1694,1696],{"className":1230,"code":1695,"language":1232,"meta":84,"style":84},"volumes:\n  pgdata:\n    driver: local\n",[32,1697,1698,1704,1710],{"__ignoreMap":84},[210,1699,1700,1702],{"class":212,"line":213},[210,1701,1394],{"class":220},[210,1703,1242],{"class":216},[210,1705,1706,1708],{"class":212,"line":321},[210,1707,1402],{"class":220},[210,1709,1242],{"class":216},[210,1711,1712,1715,1717],{"class":212,"line":335},[210,1713,1714],{"class":220},"    driver",[210,1716,256],{"class":216},[210,1718,1719],{"class":230},"local\n",[195,1721,1723],{"id":1722},"health-checks","Health Checks",[76,1725,1727],{"className":1230,"code":1726,"language":1232,"meta":84,"style":84},"healthcheck:\n  test: [\"CMD\", \"curl\", \"-f\", \"http:\u002F\u002Flocalhost:3000\u002Fhealth\"]\n  interval: 30s\n  timeout: 10s\n  retries: 3\n  start_period: 40s\n",[32,1728,1729,1736,1766,1776,1786,1796],{"__ignoreMap":84},[210,1730,1731,1734],{"class":212,"line":213},[210,1732,1733],{"class":220},"healthcheck",[210,1735,1242],{"class":216},[210,1737,1738,1741,1744,1747,1750,1753,1755,1758,1760,1763],{"class":212,"line":321},[210,1739,1740],{"class":220},"  test",[210,1742,1743],{"class":216},": [",[210,1745,1746],{"class":230},"\"CMD\"",[210,1748,1749],{"class":216},", ",[210,1751,1752],{"class":230},"\"curl\"",[210,1754,1749],{"class":216},[210,1756,1757],{"class":230},"\"-f\"",[210,1759,1749],{"class":216},[210,1761,1762],{"class":230},"\"http:\u002F\u002Flocalhost:3000\u002Fhealth\"",[210,1764,1765],{"class":216},"]\n",[210,1767,1768,1771,1773],{"class":212,"line":335},[210,1769,1770],{"class":220},"  interval",[210,1772,256],{"class":216},[210,1774,1775],{"class":230},"30s\n",[210,1777,1778,1781,1783],{"class":212,"line":346},[210,1779,1780],{"class":220},"  timeout",[210,1782,256],{"class":216},[210,1784,1785],{"class":230},"10s\n",[210,1787,1788,1791,1793],{"class":212,"line":416},[210,1789,1790],{"class":220},"  retries",[210,1792,256],{"class":216},[210,1794,1795],{"class":252},"3\n",[210,1797,1798,1801,1803],{"class":212,"line":422},[210,1799,1800],{"class":220},"  start_period",[210,1802,256],{"class":216},[210,1804,1805],{"class":230},"40s\n",[195,1807,1809],{"id":1808},"dependencies","Dependencies",[76,1811,1813],{"className":1230,"code":1812,"language":1232,"meta":84,"style":84},"depends_on:\n  db:\n    condition: service_healthy\n  redis:\n    condition: service_started\n",[32,1814,1815,1822,1828,1838,1844],{"__ignoreMap":84},[210,1816,1817,1820],{"class":212,"line":213},[210,1818,1819],{"class":220},"depends_on",[210,1821,1242],{"class":216},[210,1823,1824,1826],{"class":212,"line":321},[210,1825,1336],{"class":220},[210,1827,1242],{"class":216},[210,1829,1830,1833,1835],{"class":212,"line":335},[210,1831,1832],{"class":220},"    condition",[210,1834,256],{"class":216},[210,1836,1837],{"class":230},"service_healthy\n",[210,1839,1840,1842],{"class":212,"line":346},[210,1841,1445],{"class":220},[210,1843,1242],{"class":216},[210,1845,1846,1848,1850],{"class":212,"line":416},[210,1847,1832],{"class":220},[210,1849,256],{"class":216},[210,1851,1852],{"class":230},"service_started\n",[11,1854,570,1855,1858],{},[32,1856,1857],{},"condition: service_healthy"," waits for the dependency's health check to pass before starting.",[195,1860,1862],{"id":1861},"restart-policy","Restart Policy",[76,1864,1866],{"className":1230,"code":1865,"language":1232,"meta":84,"style":84},"restart: unless-stopped  # restart on failure and on daemon restart, but not if manually stopped\n# Other options: \"no\", \"always\", \"on-failure\"\n",[32,1867,1868,1881],{"__ignoreMap":84},[210,1869,1870,1873,1875,1878],{"class":212,"line":213},[210,1871,1872],{"class":220},"restart",[210,1874,256],{"class":216},[210,1876,1877],{"class":230},"unless-stopped",[210,1879,1880],{"class":516},"  # restart on failure and on daemon restart, but not if manually stopped\n",[210,1882,1883],{"class":212,"line":321},[210,1884,1885],{"class":516},"# Other options: \"no\", \"always\", \"on-failure\"\n",[195,1887,1889],{"id":1888},"resource-limits","Resource Limits",[76,1891,1893],{"className":1230,"code":1892,"language":1232,"meta":84,"style":84},"deploy:\n  resources:\n    limits:\n      cpus: \"0.5\"\n      memory: 512M\n    reservations:\n      cpus: \"0.25\"\n      memory: 256M\n",[32,1894,1895,1902,1909,1916,1926,1936,1943,1952],{"__ignoreMap":84},[210,1896,1897,1900],{"class":212,"line":213},[210,1898,1899],{"class":220},"deploy",[210,1901,1242],{"class":216},[210,1903,1904,1907],{"class":212,"line":321},[210,1905,1906],{"class":220},"  resources",[210,1908,1242],{"class":216},[210,1910,1911,1914],{"class":212,"line":335},[210,1912,1913],{"class":220},"    limits",[210,1915,1242],{"class":216},[210,1917,1918,1921,1923],{"class":212,"line":346},[210,1919,1920],{"class":220},"      cpus",[210,1922,256],{"class":216},[210,1924,1925],{"class":230},"\"0.5\"\n",[210,1927,1928,1931,1933],{"class":212,"line":416},[210,1929,1930],{"class":220},"      memory",[210,1932,256],{"class":216},[210,1934,1935],{"class":230},"512M\n",[210,1937,1938,1941],{"class":212,"line":422},[210,1939,1940],{"class":220},"    reservations",[210,1942,1242],{"class":216},[210,1944,1945,1947,1949],{"class":212,"line":427},[210,1946,1920],{"class":220},[210,1948,256],{"class":216},[210,1950,1951],{"class":230},"\"0.25\"\n",[210,1953,1954,1956,1958],{"class":212,"line":433},[210,1955,1930],{"class":220},[210,1957,256],{"class":216},[210,1959,1960],{"class":230},"256M\n",[18,1962,1963],{"id":1416},"Networks",[76,1965,1967],{"className":1230,"code":1966,"language":1232,"meta":84,"style":84},"services:\n  web:\n    networks:\n      - frontend\n  api:\n    networks:\n      - frontend\n      - backend\n  db:\n    networks:\n      - backend\n\nnetworks:\n  frontend:\n  backend:\n",[32,1968,1969,1975,1981,1988,1995,2001,2007,2013,2020,2026,2032,2038,2042,2048,2055],{"__ignoreMap":84},[210,1970,1971,1973],{"class":212,"line":213},[210,1972,1239],{"class":220},[210,1974,1242],{"class":216},[210,1976,1977,1979],{"class":212,"line":321},[210,1978,1247],{"class":220},[210,1980,1242],{"class":216},[210,1982,1983,1986],{"class":212,"line":335},[210,1984,1985],{"class":220},"    networks",[210,1987,1242],{"class":216},[210,1989,1990,1992],{"class":212,"line":346},[210,1991,1271],{"class":216},[210,1993,1994],{"class":230},"frontend\n",[210,1996,1997,1999],{"class":212,"line":416},[210,1998,1284],{"class":220},[210,2000,1242],{"class":216},[210,2002,2003,2005],{"class":212,"line":422},[210,2004,1985],{"class":220},[210,2006,1242],{"class":216},[210,2008,2009,2011],{"class":212,"line":427},[210,2010,1271],{"class":216},[210,2012,1994],{"class":230},[210,2014,2015,2017],{"class":212,"line":433},[210,2016,1271],{"class":216},[210,2018,2019],{"class":230},"backend\n",[210,2021,2022,2024],{"class":212,"line":439},[210,2023,1336],{"class":220},[210,2025,1242],{"class":216},[210,2027,2028,2030],{"class":212,"line":497},[210,2029,1985],{"class":220},[210,2031,1242],{"class":216},[210,2033,2034,2036],{"class":212,"line":1312},[210,2035,1271],{"class":216},[210,2037,2019],{"class":230},[210,2039,2040],{"class":212,"line":1320},[210,2041,408],{"emptyLinePlaceholder":407},[210,2043,2044,2046],{"class":212,"line":1328},[210,2045,1416],{"class":220},[210,2047,1242],{"class":216},[210,2049,2050,2053],{"class":212,"line":1333},[210,2051,2052],{"class":220},"  frontend",[210,2054,1242],{"class":216},[210,2056,2057,2060],{"class":212,"line":1341},[210,2058,2059],{"class":220},"  backend",[210,2061,1242],{"class":216},[11,2063,2064],{},"Services on the same network can reach each other by service name. Separate networks isolate traffic.",[18,2066,2068],{"id":2067},"common-patterns","Common Patterns",[195,2070,2072],{"id":2071},"web-app-database-cache","Web App + Database + Cache",[76,2074,2076],{"className":1230,"code":2075,"language":1232,"meta":84,"style":84},"services:\n  app:\n    build: .\n    ports:\n      - \"3000:3000\"\n    environment:\n      DATABASE_URL: postgres:\u002F\u002Fuser:pass@db:5432\u002Fapp\n      REDIS_URL: redis:\u002F\u002Fcache:6379\n    depends_on:\n      db:\n        condition: service_healthy\n      cache:\n        condition: service_started\n\n  db:\n    image: postgres:16-alpine\n    environment:\n      POSTGRES_USER: user\n      POSTGRES_PASSWORD: pass\n      POSTGRES_DB: app\n    volumes:\n      - pgdata:\u002Fvar\u002Flib\u002Fpostgresql\u002Fdata\n    healthcheck:\n      test: [\"CMD-SHELL\", \"pg_isready -U user\"]\n      interval: 10s\n      timeout: 5s\n      retries: 5\n\n  cache:\n    image: redis:7-alpine\n\nvolumes:\n  pgdata:\n",[32,2077,2078,2084,2091,2100,2106,2112,2118,2128,2138,2144,2151,2160,2167,2175,2179,2185,2194,2200,2210,2219,2229,2235,2241,2249,2267,2277,2288,2299,2304,2312,2321,2326,2333],{"__ignoreMap":84},[210,2079,2080,2082],{"class":212,"line":213},[210,2081,1239],{"class":220},[210,2083,1242],{"class":216},[210,2085,2086,2089],{"class":212,"line":321},[210,2087,2088],{"class":220},"  app",[210,2090,1242],{"class":216},[210,2092,2093,2095,2097],{"class":212,"line":335},[210,2094,1291],{"class":220},[210,2096,256],{"class":216},[210,2098,2099],{"class":252},".\n",[210,2101,2102,2104],{"class":212,"line":346},[210,2103,1264],{"class":220},[210,2105,1242],{"class":216},[210,2107,2108,2110],{"class":212,"line":416},[210,2109,1271],{"class":216},[210,2111,1309],{"class":230},[210,2113,2114,2116],{"class":212,"line":422},[210,2115,1354],{"class":220},[210,2117,1242],{"class":216},[210,2119,2120,2123,2125],{"class":212,"line":427},[210,2121,2122],{"class":220},"      DATABASE_URL",[210,2124,256],{"class":216},[210,2126,2127],{"class":230},"postgres:\u002F\u002Fuser:pass@db:5432\u002Fapp\n",[210,2129,2130,2133,2135],{"class":212,"line":433},[210,2131,2132],{"class":220},"      REDIS_URL",[210,2134,256],{"class":216},[210,2136,2137],{"class":230},"redis:\u002F\u002Fcache:6379\n",[210,2139,2140,2142],{"class":212,"line":439},[210,2141,1315],{"class":220},[210,2143,1242],{"class":216},[210,2145,2146,2149],{"class":212,"line":497},[210,2147,2148],{"class":220},"      db",[210,2150,1242],{"class":216},[210,2152,2153,2156,2158],{"class":212,"line":1312},[210,2154,2155],{"class":220},"        condition",[210,2157,256],{"class":216},[210,2159,1837],{"class":230},[210,2161,2162,2165],{"class":212,"line":1320},[210,2163,2164],{"class":220},"      cache",[210,2166,1242],{"class":216},[210,2168,2169,2171,2173],{"class":212,"line":1328},[210,2170,2155],{"class":220},[210,2172,256],{"class":216},[210,2174,1852],{"class":230},[210,2176,2177],{"class":212,"line":1333},[210,2178,408],{"emptyLinePlaceholder":407},[210,2180,2181,2183],{"class":212,"line":1341},[210,2182,1336],{"class":220},[210,2184,1242],{"class":216},[210,2186,2187,2189,2191],{"class":212,"line":1351},[210,2188,1254],{"class":220},[210,2190,256],{"class":216},[210,2192,2193],{"class":230},"postgres:16-alpine\n",[210,2195,2196,2198],{"class":212,"line":1359},[210,2197,1354],{"class":220},[210,2199,1242],{"class":216},[210,2201,2202,2205,2207],{"class":212,"line":1370},[210,2203,2204],{"class":220},"      POSTGRES_USER",[210,2206,256],{"class":216},[210,2208,2209],{"class":230},"user\n",[210,2211,2212,2214,2216],{"class":212,"line":1378},[210,2213,1362],{"class":220},[210,2215,256],{"class":216},[210,2217,2218],{"class":230},"pass\n",[210,2220,2221,2224,2226],{"class":212,"line":1386},[210,2222,2223],{"class":220},"      POSTGRES_DB",[210,2225,256],{"class":216},[210,2227,2228],{"class":230},"app\n",[210,2230,2231,2233],{"class":212,"line":1391},[210,2232,1373],{"class":220},[210,2234,1242],{"class":216},[210,2236,2237,2239],{"class":212,"line":1399},[210,2238,1271],{"class":216},[210,2240,1383],{"class":230},[210,2242,2244,2247],{"class":212,"line":2243},23,[210,2245,2246],{"class":220},"    healthcheck",[210,2248,1242],{"class":216},[210,2250,2252,2255,2257,2260,2262,2265],{"class":212,"line":2251},24,[210,2253,2254],{"class":220},"      test",[210,2256,1743],{"class":216},[210,2258,2259],{"class":230},"\"CMD-SHELL\"",[210,2261,1749],{"class":216},[210,2263,2264],{"class":230},"\"pg_isready -U user\"",[210,2266,1765],{"class":216},[210,2268,2270,2273,2275],{"class":212,"line":2269},25,[210,2271,2272],{"class":220},"      interval",[210,2274,256],{"class":216},[210,2276,1785],{"class":230},[210,2278,2280,2283,2285],{"class":212,"line":2279},26,[210,2281,2282],{"class":220},"      timeout",[210,2284,256],{"class":216},[210,2286,2287],{"class":230},"5s\n",[210,2289,2291,2294,2296],{"class":212,"line":2290},27,[210,2292,2293],{"class":220},"      retries",[210,2295,256],{"class":216},[210,2297,2298],{"class":252},"5\n",[210,2300,2302],{"class":212,"line":2301},28,[210,2303,408],{"emptyLinePlaceholder":407},[210,2305,2307,2310],{"class":212,"line":2306},29,[210,2308,2309],{"class":220},"  cache",[210,2311,1242],{"class":216},[210,2313,2315,2317,2319],{"class":212,"line":2314},30,[210,2316,1254],{"class":220},[210,2318,256],{"class":216},[210,2320,1456],{"class":230},[210,2322,2324],{"class":212,"line":2323},31,[210,2325,408],{"emptyLinePlaceholder":407},[210,2327,2329,2331],{"class":212,"line":2328},32,[210,2330,1394],{"class":220},[210,2332,1242],{"class":216},[210,2334,2336,2338],{"class":212,"line":2335},33,[210,2337,1402],{"class":220},[210,2339,1242],{"class":216},[195,2341,2343],{"id":2342},"development-vs-production","Development vs Production",[11,2345,1562,2346,2349],{},[32,2347,2348],{},"compose.override.yaml"," for development-specific settings (auto-loaded by Docker Compose):",[76,2351,2353],{"className":1230,"code":2352,"language":1232,"meta":84,"style":84},"# compose.yaml (base)\nservices:\n  api:\n    image: myapp:latest\n\n# compose.override.yaml (development)\nservices:\n  api:\n    build: .\n    volumes:\n      - .\u002Fsrc:\u002Fapp\u002Fsrc\n    environment:\n      DEBUG: \"true\"\n",[32,2354,2355,2360,2366,2372,2381,2385,2390,2396,2402,2410,2416,2423,2429],{"__ignoreMap":84},[210,2356,2357],{"class":212,"line":213},[210,2358,2359],{"class":516},"# compose.yaml (base)\n",[210,2361,2362,2364],{"class":212,"line":321},[210,2363,1239],{"class":220},[210,2365,1242],{"class":216},[210,2367,2368,2370],{"class":212,"line":335},[210,2369,1284],{"class":220},[210,2371,1242],{"class":216},[210,2373,2374,2376,2378],{"class":212,"line":346},[210,2375,1254],{"class":220},[210,2377,256],{"class":216},[210,2379,2380],{"class":230},"myapp:latest\n",[210,2382,2383],{"class":212,"line":416},[210,2384,408],{"emptyLinePlaceholder":407},[210,2386,2387],{"class":212,"line":422},[210,2388,2389],{"class":516},"# compose.override.yaml (development)\n",[210,2391,2392,2394],{"class":212,"line":427},[210,2393,1239],{"class":220},[210,2395,1242],{"class":216},[210,2397,2398,2400],{"class":212,"line":433},[210,2399,1284],{"class":220},[210,2401,1242],{"class":216},[210,2403,2404,2406,2408],{"class":212,"line":439},[210,2405,1291],{"class":220},[210,2407,256],{"class":216},[210,2409,2099],{"class":252},[210,2411,2412,2414],{"class":212,"line":497},[210,2413,1373],{"class":220},[210,2415,1242],{"class":216},[210,2417,2418,2420],{"class":212,"line":1312},[210,2419,1271],{"class":216},[210,2421,2422],{"class":230},".\u002Fsrc:\u002Fapp\u002Fsrc\n",[210,2424,2425,2427],{"class":212,"line":1320},[210,2426,1354],{"class":220},[210,2428,1242],{"class":216},[210,2430,2431,2434,2436],{"class":212,"line":1328},[210,2432,2433],{"class":220},"      DEBUG",[210,2435,256],{"class":216},[210,2437,2438],{"class":230},"\"true\"\n",[11,2440,2441,2442],{},"For production, use a separate file: ",[32,2443,2444],{},"docker compose -f compose.yaml -f compose.prod.yaml up",[18,2446,561],{"id":560},[563,2448,2449,2464,2470,2481,2497],{},[29,2450,2451,575,2457,2460,2461,1220],{},[568,2452,570,2453,2456],{},[32,2454,2455],{},"latest"," tag in production",[32,2458,2459],{},"image: postgres:latest"," can change at any time. Pin specific versions: ",[32,2462,2463],{},"postgres:16.2-alpine",[29,2465,2466,2469],{},[568,2467,2468],{},"Storing secrets in compose.yaml"," — environment variables in the file are visible in version control. Use Docker secrets or external secret management.",[29,2471,2472,575,2475,2477,2478,2480],{},[568,2473,2474],{},"Not using health checks with depends_on",[32,2476,1819],{}," without ",[32,2479,1857],{}," only waits for the container to start, not for the service to be ready.",[29,2482,2483,2486,2487,2490,2491,2494,2495,1220],{},[568,2484,2485],{},"Bind mounts overwriting node_modules"," — mounting ",[32,2488,2489],{},".\u002F:\u002Fapp"," overwrites the container's ",[32,2492,2493],{},"node_modules",". Use a named volume for ",[32,2496,2493],{},[29,2498,2499,2502],{},[568,2500,2501],{},"Not declaring volumes"," — data in containers is ephemeral. If the container is recreated, any data not in a volume is lost.",[18,2504,2506],{"id":2505},"generate-templates","Generate Templates",[11,2508,2509,2513],{},[621,2510,2512],{"href":2511},"\u002Ftools\u002Finfrastructure-template","StackCache Docker & Kubernetes Templates"," generates validated Dockerfile, Compose, and Kubernetes YAML starting points for common stacks — all locally in your browser.",[627,2515,2516],{},"html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}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 .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":84,"searchDepth":321,"depth":321,"links":2518},[2519,2520,2530,2531,2535,2536],{"id":1226,"depth":321,"text":1227},{"id":1239,"depth":321,"text":1420,"children":2521},[2522,2523,2524,2525,2526,2527,2528,2529],{"id":1423,"depth":335,"text":1424},{"id":1516,"depth":335,"text":1517},{"id":1590,"depth":335,"text":1591},{"id":1394,"depth":335,"text":1648},{"id":1722,"depth":335,"text":1723},{"id":1808,"depth":335,"text":1809},{"id":1861,"depth":335,"text":1862},{"id":1888,"depth":335,"text":1889},{"id":1416,"depth":321,"text":1963},{"id":2067,"depth":321,"text":2068,"children":2532},[2533,2534],{"id":2071,"depth":335,"text":2072},{"id":2342,"depth":335,"text":2343},{"id":560,"depth":321,"text":561},{"id":2505,"depth":321,"text":2506},"DevOps","A practical guide to writing Docker Compose files. Covers services, networks, volumes, environment variables, health checks, and common patterns.",{},"\u002Fblog\u002Fdocker-compose-file-reference",{"title":1203,"description":2538},"blog\u002Fdocker-compose-file-reference","infrastructure-template","Jx86pjgHV7mZEFcEOHoDRaWlB_0EsGv9Y-PXkWh6nOM",{"id":2546,"title":2547,"body":2548,"category":652,"date":653,"description":3636,"extension":655,"meta":3637,"navigation":407,"path":3638,"readingTime":433,"seo":3639,"stem":3640,"tool":3641,"updated":661,"__hash__":3642},"blog\u002Fblog\u002Fhow-to-format-json.md","How to Format JSON: The Complete Guide",{"type":8,"value":2549,"toc":3610},[2550,2553,2556,2560,2570,2602,2628,2698,2702,2705,2711,2714,2831,2836,2850,2855,2866,2870,2877,2881,2884,2890,2893,2897,2900,2906,2910,2913,2919,2923,2933,2939,2942,2946,2949,2980,2984,2987,2994,3026,3030,3036,3041,3116,3120,3127,3177,3181,3205,3209,3213,3323,3325,3376,3380,3409,3413,3547,3550,3554,3594,3598,3601,3607],[11,2551,2552],{},"JSON (JavaScript Object Notation) is the most widely used data interchange format on the web. Every REST API, configuration file, and NoSQL database speaks JSON. Yet formatting it correctly — with consistent indentation, valid syntax, and minimal size for production — remains a daily task that trips up developers at every level.",[11,2554,2555],{},"This guide covers everything you need to know about JSON formatting: what makes JSON valid, how to pretty-print it for readability, how to minify it for performance, and how to catch the syntax errors that waste your debugging time.",[18,2557,2559],{"id":2558},"what-is-json","What is JSON?",[11,2561,2562,2563,2569],{},"JSON is a lightweight text format for structured data. It was derived from JavaScript object literal syntax but is language-independent — every modern programming language has a JSON parser. JSON is defined by ",[621,2564,2568],{"href":2565,"rel":2566},"https:\u002F\u002Fdatatracker.ietf.org\u002Fdoc\u002Fhtml\u002Frfc8259",[2567],"nofollow","RFC 8259"," and uses six structural characters:",[26,2571,2572,2581,2590,2596],{},[29,2573,2574,184,2577,2580],{},[32,2575,2576],{},"{",[32,2578,2579],{},"}"," for objects (key-value pairs)",[29,2582,2583,184,2586,2589],{},[32,2584,2585],{},"[",[32,2587,2588],{},"]"," for arrays (ordered lists)",[29,2591,2592,2595],{},[32,2593,2594],{},":"," separates keys from values",[29,2597,2598,2601],{},[32,2599,2600],{},","," separates elements",[11,2603,2604,2605,2608,2609,2612,2613,2616,2617,2620,2621,2624,2625,1220],{},"JSON supports four primitive types: ",[568,2606,2607],{},"strings"," (double-quoted), ",[568,2610,2611],{},"numbers"," (integer or floating-point), ",[568,2614,2615],{},"booleans"," (",[32,2618,2619],{},"true"," \u002F ",[32,2622,2623],{},"false","), and ",[568,2626,2627],{},"null",[76,2629,2631],{"className":309,"code":2630,"language":311,"meta":84,"style":84},"{\n  \"name\": \"StackCache\",\n  \"version\": 2,\n  \"tools\": 42,\n  \"openSource\": false,\n  \"description\": null\n}\n",[32,2632,2633,2637,2649,2661,2673,2684,2694],{"__ignoreMap":84},[210,2634,2635],{"class":212,"line":213},[210,2636,318],{"class":216},[210,2638,2639,2642,2644,2647],{"class":212,"line":321},[210,2640,2641],{"class":252},"  \"name\"",[210,2643,256],{"class":216},[210,2645,2646],{"class":230},"\"StackCache\"",[210,2648,332],{"class":216},[210,2650,2651,2654,2656,2659],{"class":212,"line":335},[210,2652,2653],{"class":252},"  \"version\"",[210,2655,256],{"class":216},[210,2657,2658],{"class":252},"2",[210,2660,332],{"class":216},[210,2662,2663,2666,2668,2671],{"class":212,"line":346},[210,2664,2665],{"class":252},"  \"tools\"",[210,2667,256],{"class":216},[210,2669,2670],{"class":252},"42",[210,2672,332],{"class":216},[210,2674,2675,2678,2680,2682],{"class":212,"line":416},[210,2676,2677],{"class":252},"  \"openSource\"",[210,2679,256],{"class":216},[210,2681,2623],{"class":252},[210,2683,332],{"class":216},[210,2685,2686,2689,2691],{"class":212,"line":422},[210,2687,2688],{"class":252},"  \"description\"",[210,2690,256],{"class":216},[210,2692,2693],{"class":252},"null\n",[210,2695,2696],{"class":212,"line":427},[210,2697,349],{"class":216},[18,2699,2701],{"id":2700},"why-format-json","Why Format JSON?",[11,2703,2704],{},"Unformatted JSON is a single line of text. This is efficient for machines but unreadable for humans:",[76,2706,2709],{"className":2707,"code":2708,"language":81},[79],"{\"users\":[{\"id\":1,\"name\":\"Alice\",\"roles\":[\"admin\",\"editor\"]},{\"id\":2,\"name\":\"Bob\",\"roles\":[\"viewer\"]}]}\n",[32,2710,2708],{"__ignoreMap":84},[11,2712,2713],{},"Formatted (pretty-printed) JSON adds indentation and line breaks so you can see the structure:",[76,2715,2717],{"className":309,"code":2716,"language":311,"meta":84,"style":84},"{\n  \"users\": [\n    {\n      \"id\": 1,\n      \"name\": \"Alice\",\n      \"roles\": [\"admin\", \"editor\"]\n    },\n    {\n      \"id\": 2,\n      \"name\": \"Bob\",\n      \"roles\": [\"viewer\"]\n    }\n  ]\n}\n",[32,2718,2719,2723,2731,2736,2747,2759,2776,2781,2785,2795,2806,2817,2822,2827],{"__ignoreMap":84},[210,2720,2721],{"class":212,"line":213},[210,2722,318],{"class":216},[210,2724,2725,2728],{"class":212,"line":321},[210,2726,2727],{"class":252},"  \"users\"",[210,2729,2730],{"class":216},": [\n",[210,2732,2733],{"class":212,"line":335},[210,2734,2735],{"class":216},"    {\n",[210,2737,2738,2741,2743,2745],{"class":212,"line":346},[210,2739,2740],{"class":252},"      \"id\"",[210,2742,256],{"class":216},[210,2744,917],{"class":252},[210,2746,332],{"class":216},[210,2748,2749,2752,2754,2757],{"class":212,"line":416},[210,2750,2751],{"class":252},"      \"name\"",[210,2753,256],{"class":216},[210,2755,2756],{"class":230},"\"Alice\"",[210,2758,332],{"class":216},[210,2760,2761,2764,2766,2769,2771,2774],{"class":212,"line":422},[210,2762,2763],{"class":252},"      \"roles\"",[210,2765,1743],{"class":216},[210,2767,2768],{"class":230},"\"admin\"",[210,2770,1749],{"class":216},[210,2772,2773],{"class":230},"\"editor\"",[210,2775,1765],{"class":216},[210,2777,2778],{"class":212,"line":427},[210,2779,2780],{"class":216},"    },\n",[210,2782,2783],{"class":212,"line":433},[210,2784,2735],{"class":216},[210,2786,2787,2789,2791,2793],{"class":212,"line":439},[210,2788,2740],{"class":252},[210,2790,256],{"class":216},[210,2792,2658],{"class":252},[210,2794,332],{"class":216},[210,2796,2797,2799,2801,2804],{"class":212,"line":497},[210,2798,2751],{"class":252},[210,2800,256],{"class":216},[210,2802,2803],{"class":230},"\"Bob\"",[210,2805,332],{"class":216},[210,2807,2808,2810,2812,2815],{"class":212,"line":1312},[210,2809,2763],{"class":252},[210,2811,1743],{"class":216},[210,2813,2814],{"class":230},"\"viewer\"",[210,2816,1765],{"class":216},[210,2818,2819],{"class":212,"line":1320},[210,2820,2821],{"class":216},"    }\n",[210,2823,2824],{"class":212,"line":1328},[210,2825,2826],{"class":216},"  ]\n",[210,2828,2829],{"class":212,"line":1333},[210,2830,349],{"class":216},[11,2832,2833],{},[568,2834,2835],{},"When to pretty-print:",[26,2837,2838,2841,2844,2847],{},[29,2839,2840],{},"Debugging API responses",[29,2842,2843],{},"Reading configuration files",[29,2845,2846],{},"Code reviews and documentation",[29,2848,2849],{},"Comparing two JSON payloads",[11,2851,2852],{},[568,2853,2854],{},"When to minify:",[26,2856,2857,2860,2863],{},[29,2858,2859],{},"Sending data over the network (API responses, webhooks)",[29,2861,2862],{},"Storing in databases or caches",[29,2864,2865],{},"Embedding in HTML or JavaScript bundles",[18,2867,2869],{"id":2868},"common-json-syntax-errors","Common JSON Syntax Errors",[11,2871,2872,2873,2876],{},"These are the mistakes that cause ",[32,2874,2875],{},"JSON.parse()"," to throw and APIs to return 400 errors:",[195,2878,2880],{"id":2879},"_1-trailing-commas","1. Trailing commas",[11,2882,2883],{},"JSON does not allow trailing commas. JavaScript does, which is why this catches people:",[76,2885,2888],{"className":2886,"code":2887,"language":81},[79],"\u002F\u002F INVALID JSON\n{\n  \"name\": \"Alice\",\n  \"role\": \"admin\",  ← trailing comma\n}\n",[32,2889,2887],{"__ignoreMap":84},[11,2891,2892],{},"Remove the comma after the last property or array element.",[195,2894,2896],{"id":2895},"_2-single-quotes","2. Single quotes",[11,2898,2899],{},"JSON requires double quotes for strings. Single quotes are not valid:",[76,2901,2904],{"className":2902,"code":2903,"language":81},[79],"\u002F\u002F INVALID JSON\n{'name': 'Alice'}\n\n\u002F\u002F VALID JSON\n{\"name\": \"Alice\"}\n",[32,2905,2903],{"__ignoreMap":84},[195,2907,2909],{"id":2908},"_3-unquoted-keys","3. Unquoted keys",[11,2911,2912],{},"JavaScript allows unquoted object keys, but JSON does not:",[76,2914,2917],{"className":2915,"code":2916,"language":81},[79],"\u002F\u002F INVALID JSON\n{name: \"Alice\"}\n\n\u002F\u002F VALID JSON\n{\"name\": \"Alice\"}\n",[32,2918,2916],{"__ignoreMap":84},[195,2920,2922],{"id":2921},"_4-comments","4. Comments",[11,2924,2925,2926,184,2929,2932],{},"JSON has no comment syntax. ",[32,2927,2928],{},"\u002F\u002F",[32,2930,2931],{},"\u002F* *\u002F"," are not valid:",[76,2934,2937],{"className":2935,"code":2936,"language":81},[79],"\u002F\u002F INVALID JSON\n{\n  \"debug\": true  \u002F\u002F enable debug mode\n}\n",[32,2938,2936],{"__ignoreMap":84},[11,2940,2941],{},"If you need comments in configuration, consider JSONC (JSON with Comments) or YAML, which support them natively.",[195,2943,2945],{"id":2944},"_5-wrong-value-types","5. Wrong value types",[11,2947,2948],{},"These JavaScript values are not valid in JSON:",[26,2950,2951,2960,2971,2974],{},[29,2952,2953,2956,2957,2959],{},[32,2954,2955],{},"undefined"," — use ",[32,2958,2627],{}," instead",[29,2961,2962,184,2965,2968,2969],{},[32,2963,2964],{},"NaN",[32,2966,2967],{},"Infinity"," — use strings or ",[32,2970,2627],{},[29,2972,2973],{},"Functions — not representable in JSON",[29,2975,2976,2979],{},[32,2977,2978],{},"Date"," objects — serialize as ISO 8601 strings",[18,2981,2983],{"id":2982},"how-to-format-json-in-your-browser","How to Format JSON in Your Browser",[11,2985,2986],{},"The fastest way to format JSON is with a browser-based tool. Paste your JSON, and it instantly validates the syntax, highlights errors with line numbers, and formats the output with your chosen indentation.",[11,2988,2989,2993],{},[621,2990,2992],{"href":2991},"\u002Ftools\u002Fjson-formatter","StackCache JSON Formatter"," runs entirely in your browser — your data never leaves your device. It supports:",[26,2995,2996,3002,3008,3014,3020],{},[29,2997,2998,3001],{},[568,2999,3000],{},"Pretty-print"," with 2-space or 4-space indentation",[29,3003,3004,3007],{},[568,3005,3006],{},"Minify"," to remove all whitespace",[29,3009,3010,3013],{},[568,3011,3012],{},"Validate"," with precise error messages pointing to the exact character",[29,3015,3016,3019],{},[568,3017,3018],{},"Tree view"," for navigating large payloads",[29,3021,3022,3025],{},[568,3023,3024],{},"Copy"," formatted output to clipboard",[18,3027,3029],{"id":3028},"how-to-format-json-from-the-command-line","How to Format JSON from the Command Line",[195,3031,570,3033],{"id":3032},"using-jq",[32,3034,3035],{},"jq",[11,3037,3038,3040],{},[32,3039,3035],{}," is the standard command-line JSON processor:",[76,3042,3044],{"className":507,"code":3043,"language":509,"meta":84,"style":84},"# Pretty-print\necho '{\"name\":\"Alice\"}' | jq .\n\n# Minify\necho '{\"name\": \"Alice\"}' | jq -c .\n\n# Format a file\njq . input.json > formatted.json\n",[32,3045,3046,3051,3066,3070,3075,3091,3095,3100],{"__ignoreMap":84},[210,3047,3048],{"class":212,"line":213},[210,3049,3050],{"class":516},"# Pretty-print\n",[210,3052,3053,3055,3058,3060,3063],{"class":212,"line":321},[210,3054,521],{"class":252},[210,3056,3057],{"class":230}," '{\"name\":\"Alice\"}'",[210,3059,531],{"class":530},[210,3061,3062],{"class":224}," jq",[210,3064,3065],{"class":230}," .\n",[210,3067,3068],{"class":212,"line":335},[210,3069,408],{"emptyLinePlaceholder":407},[210,3071,3072],{"class":212,"line":346},[210,3073,3074],{"class":516},"# Minify\n",[210,3076,3077,3079,3082,3084,3086,3089],{"class":212,"line":416},[210,3078,521],{"class":252},[210,3080,3081],{"class":230}," '{\"name\": \"Alice\"}'",[210,3083,531],{"class":530},[210,3085,3062],{"class":224},[210,3087,3088],{"class":252}," -c",[210,3090,3065],{"class":230},[210,3092,3093],{"class":212,"line":422},[210,3094,408],{"emptyLinePlaceholder":407},[210,3096,3097],{"class":212,"line":427},[210,3098,3099],{"class":516},"# Format a file\n",[210,3101,3102,3104,3107,3110,3113],{"class":212,"line":433},[210,3103,3035],{"class":224},[210,3105,3106],{"class":230}," .",[210,3108,3109],{"class":230}," input.json",[210,3111,3112],{"class":530}," >",[210,3114,3115],{"class":230}," formatted.json\n",[195,3117,3119],{"id":3118},"using-python","Using Python",[11,3121,3122,3123,3126],{},"Python's ",[32,3124,3125],{},"json.tool"," module formats JSON from the command line:",[76,3128,3130],{"className":507,"code":3129,"language":509,"meta":84,"style":84},"# Pretty-print\necho '{\"name\":\"Alice\"}' | python -m json.tool\n\n# With custom indentation\npython -c \"import json,sys; print(json.dumps(json.load(sys.stdin), indent=4))\" \u003C input.json\n",[32,3131,3132,3136,3153,3157,3162],{"__ignoreMap":84},[210,3133,3134],{"class":212,"line":213},[210,3135,3050],{"class":516},[210,3137,3138,3140,3142,3144,3147,3150],{"class":212,"line":321},[210,3139,521],{"class":252},[210,3141,3057],{"class":230},[210,3143,531],{"class":530},[210,3145,3146],{"class":224}," python",[210,3148,3149],{"class":252}," -m",[210,3151,3152],{"class":230}," json.tool\n",[210,3154,3155],{"class":212,"line":335},[210,3156,408],{"emptyLinePlaceholder":407},[210,3158,3159],{"class":212,"line":346},[210,3160,3161],{"class":516},"# With custom indentation\n",[210,3163,3164,3166,3168,3171,3174],{"class":212,"line":416},[210,3165,445],{"class":224},[210,3167,3088],{"class":252},[210,3169,3170],{"class":230}," \"import json,sys; print(json.dumps(json.load(sys.stdin), indent=4))\"",[210,3172,3173],{"class":530}," \u003C",[210,3175,3176],{"class":230}," input.json\n",[195,3178,3180],{"id":3179},"using-nodejs","Using Node.js",[76,3182,3184],{"className":507,"code":3183,"language":509,"meta":84,"style":84},"# Pretty-print\nnode -e \"process.stdin.resume(); let d=''; process.stdin.on('data',c=>d+=c); process.stdin.on('end',()=>console.log(JSON.stringify(JSON.parse(d),null,2)))\" \u003C input.json\n",[32,3185,3186,3190],{"__ignoreMap":84},[210,3187,3188],{"class":212,"line":213},[210,3189,3050],{"class":516},[210,3191,3192,3195,3198,3201,3203],{"class":212,"line":321},[210,3193,3194],{"class":224},"node",[210,3196,3197],{"class":252}," -e",[210,3199,3200],{"class":230}," \"process.stdin.resume(); let d=''; process.stdin.on('data',c=>d+=c); process.stdin.on('end',()=>console.log(JSON.stringify(JSON.parse(d),null,2)))\"",[210,3202,3173],{"class":530},[210,3204,3176],{"class":230},[18,3206,3208],{"id":3207},"json-formatting-in-code","JSON Formatting in Code",[195,3210,3212],{"id":3211},"javascript-typescript","JavaScript \u002F TypeScript",[76,3214,3216],{"className":389,"code":3215,"language":385,"meta":84,"style":84},"\u002F\u002F Pretty-print with 2-space indent\nconst formatted = JSON.stringify(data, null, 2);\n\n\u002F\u002F Minify\nconst minified = JSON.stringify(data);\n\n\u002F\u002F Custom replacer to filter keys\nconst filtered = JSON.stringify(data, ['name', 'email'], 2);\n",[32,3217,3218,3223,3254,3258,3263,3281,3285,3290],{"__ignoreMap":84},[210,3219,3220],{"class":212,"line":213},[210,3221,3222],{"class":516},"\u002F\u002F Pretty-print with 2-space indent\n",[210,3224,3225,3228,3231,3234,3237,3239,3242,3245,3247,3249,3251],{"class":212,"line":321},[210,3226,3227],{"class":530},"const",[210,3229,3230],{"class":252}," formatted",[210,3232,3233],{"class":530}," =",[210,3235,3236],{"class":252}," JSON",[210,3238,1220],{"class":216},[210,3240,3241],{"class":224},"stringify",[210,3243,3244],{"class":216},"(data, ",[210,3246,2627],{"class":252},[210,3248,1749],{"class":216},[210,3250,2658],{"class":252},[210,3252,3253],{"class":216},");\n",[210,3255,3256],{"class":212,"line":335},[210,3257,408],{"emptyLinePlaceholder":407},[210,3259,3260],{"class":212,"line":346},[210,3261,3262],{"class":516},"\u002F\u002F Minify\n",[210,3264,3265,3267,3270,3272,3274,3276,3278],{"class":212,"line":416},[210,3266,3227],{"class":530},[210,3268,3269],{"class":252}," minified",[210,3271,3233],{"class":530},[210,3273,3236],{"class":252},[210,3275,1220],{"class":216},[210,3277,3241],{"class":224},[210,3279,3280],{"class":216},"(data);\n",[210,3282,3283],{"class":212,"line":422},[210,3284,408],{"emptyLinePlaceholder":407},[210,3286,3287],{"class":212,"line":427},[210,3288,3289],{"class":516},"\u002F\u002F Custom replacer to filter keys\n",[210,3291,3292,3294,3297,3299,3301,3303,3305,3308,3311,3313,3316,3319,3321],{"class":212,"line":433},[210,3293,3227],{"class":530},[210,3295,3296],{"class":252}," filtered",[210,3298,3233],{"class":530},[210,3300,3236],{"class":252},[210,3302,1220],{"class":216},[210,3304,3241],{"class":224},[210,3306,3307],{"class":216},"(data, [",[210,3309,3310],{"class":230},"'name'",[210,3312,1749],{"class":216},[210,3314,3315],{"class":230},"'email'",[210,3317,3318],{"class":216},"], ",[210,3320,2658],{"class":252},[210,3322,3253],{"class":216},[195,3324,446],{"id":445},[76,3326,3328],{"className":449,"code":3327,"language":445,"meta":84,"style":84},"import json\n\n# Pretty-print\nformatted = json.dumps(data, indent=2, ensure_ascii=False)\n\n# Minify (remove extra whitespace)\nminified = json.dumps(data, separators=(',', ':'))\n\n# Sort keys for deterministic output\nsorted_json = json.dumps(data, indent=2, sort_keys=True)\n",[32,3329,3330,3335,3339,3343,3348,3352,3357,3362,3366,3371],{"__ignoreMap":84},[210,3331,3332],{"class":212,"line":213},[210,3333,3334],{},"import json\n",[210,3336,3337],{"class":212,"line":321},[210,3338,408],{"emptyLinePlaceholder":407},[210,3340,3341],{"class":212,"line":335},[210,3342,3050],{},[210,3344,3345],{"class":212,"line":346},[210,3346,3347],{},"formatted = json.dumps(data, indent=2, ensure_ascii=False)\n",[210,3349,3350],{"class":212,"line":416},[210,3351,408],{"emptyLinePlaceholder":407},[210,3353,3354],{"class":212,"line":422},[210,3355,3356],{},"# Minify (remove extra whitespace)\n",[210,3358,3359],{"class":212,"line":427},[210,3360,3361],{},"minified = json.dumps(data, separators=(',', ':'))\n",[210,3363,3364],{"class":212,"line":433},[210,3365,408],{"emptyLinePlaceholder":407},[210,3367,3368],{"class":212,"line":439},[210,3369,3370],{},"# Sort keys for deterministic output\n",[210,3372,3373],{"class":212,"line":497},[210,3374,3375],{},"sorted_json = json.dumps(data, indent=2, sort_keys=True)\n",[195,3377,3379],{"id":3378},"go","Go",[76,3381,3384],{"className":3382,"code":3383,"language":3378,"meta":84,"style":84},"language-go shiki shiki-themes github-light github-dark","\u002F\u002F Pretty-print\nformatted, _ := json.MarshalIndent(data, \"\", \"  \")\n\n\u002F\u002F Minify\nminified, _ := json.Marshal(data)\n",[32,3385,3386,3391,3396,3400,3404],{"__ignoreMap":84},[210,3387,3388],{"class":212,"line":213},[210,3389,3390],{},"\u002F\u002F Pretty-print\n",[210,3392,3393],{"class":212,"line":321},[210,3394,3395],{},"formatted, _ := json.MarshalIndent(data, \"\", \"  \")\n",[210,3397,3398],{"class":212,"line":335},[210,3399,408],{"emptyLinePlaceholder":407},[210,3401,3402],{"class":212,"line":346},[210,3403,3262],{},[210,3405,3406],{"class":212,"line":416},[210,3407,3408],{},"minified, _ := json.Marshal(data)\n",[18,3410,3412],{"id":3411},"json-vs-other-formats","JSON vs Other Formats",[96,3414,3415,3434],{},[99,3416,3417],{},[102,3418,3419,3422,3425,3428,3431],{},[105,3420,3421],{},"Feature",[105,3423,3424],{},"JSON",[105,3426,3427],{},"YAML",[105,3429,3430],{},"XML",[105,3432,3433],{},"TOML",[118,3435,3436,3452,3467,3484,3498,3514,3529],{},[102,3437,3438,3441,3444,3447,3450],{},[123,3439,3440],{},"Human readable",[123,3442,3443],{},"Good",[123,3445,3446],{},"Excellent",[123,3448,3449],{},"Fair",[123,3451,3446],{},[102,3453,3454,3457,3460,3463,3465],{},[123,3455,3456],{},"Comments",[123,3458,3459],{},"No",[123,3461,3462],{},"Yes",[123,3464,3462],{},[123,3466,3462],{},[102,3468,3469,3472,3475,3478,3481],{},[123,3470,3471],{},"Data types",[123,3473,3474],{},"4 primitives",[123,3476,3477],{},"Rich (dates, etc.)",[123,3479,3480],{},"Text only",[123,3482,3483],{},"Rich",[102,3485,3486,3489,3491,3494,3496],{},[123,3487,3488],{},"Trailing commas",[123,3490,3459],{},[123,3492,3493],{},"N\u002FA",[123,3495,3493],{},[123,3497,3462],{},[102,3499,3500,3503,3506,3509,3512],{},[123,3501,3502],{},"File size",[123,3504,3505],{},"Medium",[123,3507,3508],{},"Small",[123,3510,3511],{},"Large",[123,3513,3508],{},[102,3515,3516,3519,3522,3525,3527],{},[123,3517,3518],{},"Parse speed",[123,3520,3521],{},"Fast",[123,3523,3524],{},"Slow",[123,3526,3505],{},[123,3528,3521],{},[102,3530,3531,3534,3540,3542,3545],{},[123,3532,3533],{},"Browser native",[123,3535,3536,3537,936],{},"Yes (",[32,3538,3539],{},"JSON.parse",[123,3541,3459],{},[123,3543,3544],{},"Via DOM",[123,3546,3459],{},[11,3548,3549],{},"JSON wins for API communication because every language and browser can parse it natively. YAML wins for configuration files because it supports comments and is more readable. XML wins for document markup and legacy enterprise systems. TOML wins for simple configuration with strict typing.",[18,3551,3553],{"id":3552},"best-practices","Best Practices",[563,3555,3556,3562,3576,3582,3588],{},[29,3557,3558,3561],{},[568,3559,3560],{},"Use 2-space indentation"," — it is the most common convention in JavaScript, TypeScript, and web development. 4-space is standard in Python.",[29,3563,3564,3567,3568,3571,3572,3575],{},[568,3565,3566],{},"Sort keys in version-controlled files"," — deterministic key ordering produces clean diffs. ",[32,3569,3570],{},"JSON.stringify(data, null, 2)"," preserves insertion order; use ",[32,3573,3574],{},"sort_keys=True"," (Python) or a custom replacer to sort.",[29,3577,3578,3581],{},[568,3579,3580],{},"Validate before deploying"," — a single syntax error in a JSON config file can take down a service. Always validate in CI.",[29,3583,3584,3587],{},[568,3585,3586],{},"Minify for production APIs"," — removing whitespace from a typical API response reduces size by 15-30%, which matters at scale.",[29,3589,3590,3593],{},[568,3591,3592],{},"Use a schema"," — JSON Schema validates structure, not just syntax. Define required fields, types, and constraints so errors are caught before runtime.",[18,3595,3597],{"id":3596},"summary","Summary",[11,3599,3600],{},"JSON formatting is a simple task with real consequences: unformatted JSON wastes debugging time, invalid JSON breaks APIs, and unminified JSON wastes bandwidth. Use pretty-print for reading, minify for sending, and always validate before deploying.",[11,3602,3603,3606],{},[621,3604,3605],{"href":2991},"Try the JSON Formatter"," — it runs locally in your browser, handles files up to 10 MB, and gives you precise error messages when something is wrong.",[627,3608,3609],{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}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 .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}",{"title":84,"searchDepth":321,"depth":321,"links":3611},[3612,3613,3614,3621,3622,3628,3633,3634,3635],{"id":2558,"depth":321,"text":2559},{"id":2700,"depth":321,"text":2701},{"id":2868,"depth":321,"text":2869,"children":3615},[3616,3617,3618,3619,3620],{"id":2879,"depth":335,"text":2880},{"id":2895,"depth":335,"text":2896},{"id":2908,"depth":335,"text":2909},{"id":2921,"depth":335,"text":2922},{"id":2944,"depth":335,"text":2945},{"id":2982,"depth":321,"text":2983},{"id":3028,"depth":321,"text":3029,"children":3623},[3624,3626,3627],{"id":3032,"depth":335,"text":3625},"Using jq",{"id":3118,"depth":335,"text":3119},{"id":3179,"depth":335,"text":3180},{"id":3207,"depth":321,"text":3208,"children":3629},[3630,3631,3632],{"id":3211,"depth":335,"text":3212},{"id":445,"depth":335,"text":446},{"id":3378,"depth":335,"text":3379},{"id":3411,"depth":321,"text":3412},{"id":3552,"depth":321,"text":3553},{"id":3596,"depth":321,"text":3597},"Learn how to format, validate, and minify JSON with examples. Covers syntax rules, common errors, and when to use each format.",{},"\u002Fblog\u002Fhow-to-format-json",{"title":2547,"description":3636},"blog\u002Fhow-to-format-json","json-formatter","3Ue8cD25tQQkLh8WWp7qAz127cy79aTa4sT1U9jpn-s",{"id":3644,"title":3645,"body":3646,"category":4199,"date":653,"description":4200,"extension":655,"meta":4201,"navigation":407,"path":4202,"readingTime":427,"seo":4203,"stem":4204,"tool":4205,"updated":661,"__hash__":4206},"blog\u002Fblog\u002Fjwt-token-structure-explained.md","JWT Token Structure Explained",{"type":8,"value":3647,"toc":4177},[3648,3651,3654,3658,3667,3670,3676,3688,3692,3695,3730,3765,3768,3772,3775,3779,3900,3904,3907,3958,3962,3965,3972,3976,3979,3985,3988,3991,3995,4019,4022,4026,4030,4045,4049,4058,4062,4072,4076,4079,4093,4101,4104,4121,4125,4130,4141,4146,4157,4161,4169,4171,4174],[11,3649,3650],{},"JSON Web Tokens (JWTs) are the standard way to pass authentication and authorization data between services. If you work with APIs, single sign-on, or microservices, you encounter JWTs daily. Yet many developers treat them as opaque strings without understanding their structure — which leads to security vulnerabilities and debugging frustration.",[11,3652,3653],{},"This guide explains exactly what is inside a JWT, how the three parts work together, and the mistakes that cause real-world security incidents.",[18,3655,3657],{"id":3656},"what-is-a-jwt","What is a JWT?",[11,3659,3660,3661,3666],{},"A JWT (pronounced \"jot\") is a compact, URL-safe token defined by ",[621,3662,3665],{"href":3663,"rel":3664},"https:\u002F\u002Fdatatracker.ietf.org\u002Fdoc\u002Fhtml\u002Frfc7519",[2567],"RFC 7519",". It carries a set of claims (key-value pairs) that are digitally signed so the recipient can verify their authenticity without contacting the issuer.",[11,3668,3669],{},"A JWT looks like this:",[76,3671,3674],{"className":3672,"code":3673,"language":81},[79],"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFsaWNlIiwiaWF0IjoxNjE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c\n",[32,3675,3673],{"__ignoreMap":84},[11,3677,3678,3679,1220,3682,1220,3685,1220],{},"It is three Base64url-encoded segments separated by dots: ",[568,3680,3681],{},"Header",[568,3683,3684],{},"Payload",[568,3686,3687],{},"Signature",[18,3689,3691],{"id":3690},"part-1-the-header","Part 1: The Header",[11,3693,3694],{},"The header is a JSON object that identifies the token type and the signing algorithm:",[76,3696,3698],{"className":309,"code":3697,"language":311,"meta":84,"style":84},"{\n  \"alg\": \"HS256\",\n  \"typ\": \"JWT\"\n}\n",[32,3699,3700,3704,3716,3726],{"__ignoreMap":84},[210,3701,3702],{"class":212,"line":213},[210,3703,318],{"class":216},[210,3705,3706,3709,3711,3714],{"class":212,"line":321},[210,3707,3708],{"class":252},"  \"alg\"",[210,3710,256],{"class":216},[210,3712,3713],{"class":230},"\"HS256\"",[210,3715,332],{"class":216},[210,3717,3718,3721,3723],{"class":212,"line":335},[210,3719,3720],{"class":252},"  \"typ\"",[210,3722,256],{"class":216},[210,3724,3725],{"class":230},"\"JWT\"\n",[210,3727,3728],{"class":212,"line":346},[210,3729,349],{"class":216},[26,3731,3732,3750,3759],{},[29,3733,3734,3737,3738,3741,3742,3745,3746,3749],{},[32,3735,3736],{},"alg"," — the algorithm used to create the signature. Common values: ",[32,3739,3740],{},"HS256"," (HMAC-SHA256, symmetric), ",[32,3743,3744],{},"RS256"," (RSA-SHA256, asymmetric), ",[32,3747,3748],{},"ES256"," (ECDSA P-256, asymmetric).",[29,3751,3752,3755,3756,1220],{},[32,3753,3754],{},"typ"," — always ",[32,3757,3758],{},"\"JWT\"",[29,3760,3761,3764],{},[32,3762,3763],{},"kid"," — (optional) key ID, used when the issuer rotates signing keys.",[11,3766,3767],{},"The header is Base64url-encoded to form the first segment.",[18,3769,3771],{"id":3770},"part-2-the-payload-claims","Part 2: The Payload (Claims)",[11,3773,3774],{},"The payload contains the claims — statements about the user or session. Claims come in three categories:",[195,3776,3778],{"id":3777},"registered-claims-rfc-7519","Registered claims (RFC 7519)",[96,3780,3781,3794],{},[99,3782,3783],{},[102,3784,3785,3788,3791],{},[105,3786,3787],{},"Claim",[105,3789,3790],{},"Name",[105,3792,3793],{},"Example",[118,3795,3796,3811,3826,3841,3856,3871,3885],{},[102,3797,3798,3803,3806],{},[123,3799,3800],{},[32,3801,3802],{},"iss",[123,3804,3805],{},"Issuer",[123,3807,3808],{},[32,3809,3810],{},"\"https:\u002F\u002Fauth.example.com\"",[102,3812,3813,3818,3821],{},[123,3814,3815],{},[32,3816,3817],{},"sub",[123,3819,3820],{},"Subject (user ID)",[123,3822,3823],{},[32,3824,3825],{},"\"user_42\"",[102,3827,3828,3833,3836],{},[123,3829,3830],{},[32,3831,3832],{},"aud",[123,3834,3835],{},"Audience",[123,3837,3838],{},[32,3839,3840],{},"\"https:\u002F\u002Fapi.example.com\"",[102,3842,3843,3848,3851],{},[123,3844,3845],{},[32,3846,3847],{},"exp",[123,3849,3850],{},"Expiration (Unix timestamp)",[123,3852,3853],{},[32,3854,3855],{},"1716239022",[102,3857,3858,3863,3866],{},[123,3859,3860],{},[32,3861,3862],{},"nbf",[123,3864,3865],{},"Not Before",[123,3867,3868],{},[32,3869,3870],{},"1716235422",[102,3872,3873,3878,3881],{},[123,3874,3875],{},[32,3876,3877],{},"iat",[123,3879,3880],{},"Issued At",[123,3882,3883],{},[32,3884,3870],{},[102,3886,3887,3892,3895],{},[123,3888,3889],{},[32,3890,3891],{},"jti",[123,3893,3894],{},"JWT ID (unique identifier)",[123,3896,3897],{},[32,3898,3899],{},"\"a1b2c3d4\"",[195,3901,3903],{"id":3902},"public-claims","Public claims",[11,3905,3906],{},"Custom claims registered with IANA or using collision-resistant names:",[76,3908,3910],{"className":309,"code":3909,"language":311,"meta":84,"style":84},"{\n  \"email\": \"alice@example.com\",\n  \"roles\": [\"admin\", \"editor\"],\n  \"org_id\": \"org_123\"\n}\n",[32,3911,3912,3916,3928,3944,3954],{"__ignoreMap":84},[210,3913,3914],{"class":212,"line":213},[210,3915,318],{"class":216},[210,3917,3918,3921,3923,3926],{"class":212,"line":321},[210,3919,3920],{"class":252},"  \"email\"",[210,3922,256],{"class":216},[210,3924,3925],{"class":230},"\"alice@example.com\"",[210,3927,332],{"class":216},[210,3929,3930,3933,3935,3937,3939,3941],{"class":212,"line":335},[210,3931,3932],{"class":252},"  \"roles\"",[210,3934,1743],{"class":216},[210,3936,2768],{"class":230},[210,3938,1749],{"class":216},[210,3940,2773],{"class":230},[210,3942,3943],{"class":216},"],\n",[210,3945,3946,3949,3951],{"class":212,"line":346},[210,3947,3948],{"class":252},"  \"org_id\"",[210,3950,256],{"class":216},[210,3952,3953],{"class":230},"\"org_123\"\n",[210,3955,3956],{"class":212,"line":416},[210,3957,349],{"class":216},[195,3959,3961],{"id":3960},"private-claims","Private claims",[11,3963,3964],{},"Agreed-upon claims between parties, not registered anywhere.",[11,3966,3967,3968,3971],{},"The payload is Base64url-encoded — ",[568,3969,3970],{},"not encrypted",". Anyone who has the token can decode and read the claims. Never put secrets, passwords, or sensitive PII in JWT claims.",[18,3973,3975],{"id":3974},"part-3-the-signature","Part 3: The Signature",[11,3977,3978],{},"The signature verifies that the token was not tampered with. For HMAC-SHA256:",[76,3980,3983],{"className":3981,"code":3982,"language":81},[79],"HMAC-SHA256(\n  base64url(header) + \".\" + base64url(payload),\n  secret\n)\n",[32,3984,3982],{"__ignoreMap":84},[11,3986,3987],{},"For RSA-SHA256, the issuer signs with a private key, and the recipient verifies with the corresponding public key.",[11,3989,3990],{},"The signature prevents modification: if an attacker changes a claim in the payload, the signature will not match when the recipient recalculates it.",[18,3992,3994],{"id":3993},"how-jwt-authentication-works","How JWT Authentication Works",[563,3996,3997,4000,4003,4006,4013],{},[29,3998,3999],{},"The user logs in with credentials.",[29,4001,4002],{},"The auth server validates credentials and creates a JWT with the user's claims.",[29,4004,4005],{},"The auth server signs the JWT and returns it to the client.",[29,4007,4008,4009,4012],{},"The client sends the JWT in the ",[32,4010,4011],{},"Authorization: Bearer \u003Ctoken>"," header on subsequent requests.",[29,4014,4015,4016,4018],{},"The API server validates the signature, checks ",[32,4017,3847],{},", and uses the claims for authorization.",[11,4020,4021],{},"This is stateless: the API server does not need to query a database or session store on every request. The JWT carries all the information needed.",[18,4023,4025],{"id":4024},"common-jwt-security-mistakes","Common JWT Security Mistakes",[195,4027,4029],{"id":4028},"_1-not-validating-the-signature","1. Not validating the signature",[11,4031,4032,4033,4036,4037,4040,4041,4044],{},"Decoding a JWT is not the same as verifying it. Always validate the signature before trusting the claims. Libraries like ",[32,4034,4035],{},"jsonwebtoken"," (Node.js), ",[32,4038,4039],{},"PyJWT"," (Python), and ",[32,4042,4043],{},"golang-jwt"," (Go) do this automatically — but only if you pass the correct secret or public key.",[195,4046,4048],{"id":4047},"_2-using-the-none-algorithm","2. Using the \"none\" algorithm",[11,4050,87,4051,4054,4055,4057],{},[32,4052,4053],{},"alg: \"none\""," attack exploits servers that accept unsigned tokens. Always reject tokens with ",[32,4056,4053],{}," and validate that the algorithm matches what you expect.",[195,4059,4061],{"id":4060},"_3-storing-jwts-in-localstorage","3. Storing JWTs in localStorage",[11,4063,4064,4067,4068,4071],{},[32,4065,4066],{},"localStorage"," is accessible to any JavaScript on the page, including XSS-injected scripts. For browser-based apps, store JWTs in ",[32,4069,4070],{},"httpOnly"," cookies (not accessible to JavaScript) or use short-lived tokens with refresh token rotation.",[195,4073,4075],{"id":4074},"_4-long-lived-tokens-without-revocation","4. Long-lived tokens without revocation",[11,4077,4078],{},"JWTs cannot be revoked once issued — the server has no session to invalidate. Mitigations:",[26,4080,4081,4087,4090],{},[29,4082,4083,4084,4086],{},"Keep ",[32,4085,3847],{}," short (5-15 minutes for access tokens)",[29,4088,4089],{},"Use refresh tokens (stored securely, revocable in database)",[29,4091,4092],{},"Maintain a token blocklist for critical revocations",[195,4094,4096,4097,184,4099],{"id":4095},"_5-not-checking-exp-and-aud","5. Not checking ",[32,4098,3847],{},[32,4100,3832],{},[11,4102,4103],{},"Always validate:",[26,4105,4106,4111,4116],{},[29,4107,4108,4110],{},[32,4109,3847],{}," — reject expired tokens",[29,4112,4113,4115],{},[32,4114,3832],{}," — reject tokens intended for a different service",[29,4117,4118,4120],{},[32,4119,3802],{}," — reject tokens from unexpected issuers",[18,4122,4124],{"id":4123},"when-to-use-jwts-and-when-not-to","When to Use JWTs (and When Not To)",[11,4126,4127],{},[568,4128,4129],{},"Good use cases:",[26,4131,4132,4135,4138],{},[29,4133,4134],{},"Stateless API authentication between microservices",[29,4136,4137],{},"Single sign-on (SSO) across multiple applications",[29,4139,4140],{},"Short-lived authorization tokens",[11,4142,4143],{},[568,4144,4145],{},"Bad use cases:",[26,4147,4148,4151,4154],{},[29,4149,4150],{},"Session management for a single web app (server-side sessions are simpler and revocable)",[29,4152,4153],{},"Storing large amounts of data (JWTs are sent on every request — keep them small)",[29,4155,4156],{},"Situations where immediate revocation is required",[18,4158,4160],{"id":4159},"inspecting-jwts","Inspecting JWTs",[11,4162,4163,4164,4168],{},"When debugging authentication issues, you need to see what is inside a token. ",[621,4165,4167],{"href":4166},"\u002Ftools\u002Fjwt-decoder","StackCache JWT Inspector"," decodes the header and payload, displays the claims in a readable format, shows expiration status, and highlights potential issues — all locally in your browser. Your token never leaves your device.",[18,4170,3597],{"id":3596},[11,4172,4173],{},"A JWT is three Base64url-encoded parts: a header (algorithm), a payload (claims), and a signature (integrity proof). Understanding this structure helps you debug authentication failures, avoid security mistakes, and make informed decisions about when JWTs are the right choice for your architecture.",[627,4175,4176],{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}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);}",{"title":84,"searchDepth":321,"depth":321,"links":4178},[4179,4180,4181,4186,4187,4188,4196,4197,4198],{"id":3656,"depth":321,"text":3657},{"id":3690,"depth":321,"text":3691},{"id":3770,"depth":321,"text":3771,"children":4182},[4183,4184,4185],{"id":3777,"depth":335,"text":3778},{"id":3902,"depth":335,"text":3903},{"id":3960,"depth":335,"text":3961},{"id":3974,"depth":321,"text":3975},{"id":3993,"depth":321,"text":3994},{"id":4024,"depth":321,"text":4025,"children":4189},[4190,4191,4192,4193,4194],{"id":4028,"depth":335,"text":4029},{"id":4047,"depth":335,"text":4048},{"id":4060,"depth":335,"text":4061},{"id":4074,"depth":335,"text":4075},{"id":4095,"depth":335,"text":4195},"5. Not checking exp and aud",{"id":4123,"depth":321,"text":4124},{"id":4159,"depth":321,"text":4160},{"id":3596,"depth":321,"text":3597},"Security","Understand the three parts of a JWT token — header, payload, and signature. Learn how JWTs work, when to use them, and common security mistakes.",{},"\u002Fblog\u002Fjwt-token-structure-explained",{"title":3645,"description":4200},"blog\u002Fjwt-token-structure-explained","jwt-decoder","w-yZxxJ7zibtyR8nYc_myUmzmaP0mFMk-jBxN9EPqYA",{"id":4208,"title":4209,"body":4210,"category":4610,"date":653,"description":4611,"extension":655,"meta":4612,"navigation":407,"path":4613,"readingTime":433,"seo":4614,"stem":4615,"tool":4616,"updated":661,"__hash__":4617},"blog\u002Fblog\u002Fmqtt-protocol-guide-for-iot.md","MQTT Protocol Guide for IoT",{"type":8,"value":4211,"toc":4592},[4212,4215,4218,4222,4225,4257,4261,4267,4293,4296,4307,4310,4315,4321,4325,4358,4362,4365,4369,4372,4378,4382,4385,4390,4394,4397,4402,4409,4413,4416,4422,4425,4429,4432,4438,4445,4449,4463,4467,4470,4508,4512,4582,4584],[11,4213,4214],{},"MQTT (Message Queuing Telemetry Transport) is the dominant messaging protocol for IoT (Internet of Things). It connects billions of devices — from industrial sensors and smart home devices to fleet tracking systems and medical monitors. If you are building anything that involves devices communicating over a network, you need to understand MQTT.",[11,4216,4217],{},"This guide covers the protocol fundamentals, quality of service levels, and practical patterns.",[18,4219,4221],{"id":4220},"why-mqtt","Why MQTT?",[11,4223,4224],{},"MQTT was designed in 1999 for oil pipeline telemetry over satellite links — a scenario with low bandwidth, unreliable connections, and constrained devices. These design constraints produced a protocol that is:",[26,4226,4227,4233,4239,4245,4251],{},[29,4228,4229,4232],{},[568,4230,4231],{},"Lightweight"," — minimal packet overhead (as little as 2 bytes for a header)",[29,4234,4235,4238],{},[568,4236,4237],{},"Publish\u002Fsubscribe"," — decouples senders and receivers",[29,4240,4241,4244],{},[568,4242,4243],{},"Reliable"," — three QoS levels for different reliability needs",[29,4246,4247,4250],{},[568,4248,4249],{},"Bidirectional"," — both devices and servers can publish and subscribe",[29,4252,4253,4256],{},[568,4254,4255],{},"Battery-friendly"," — supports long idle periods with keepalive pings",[18,4258,4260],{"id":4259},"publishsubscribe-model","Publish\u002FSubscribe Model",[11,4262,4263,4264,2594],{},"Unlike HTTP (request\u002Fresponse), MQTT uses a publish\u002Fsubscribe model with a central ",[568,4265,4266],{},"broker",[563,4268,4269,4282,4287],{},[29,4270,4271,4274,4275,4278,4279,936],{},[568,4272,4273],{},"Publishers"," send messages to ",[568,4276,4277],{},"topics"," (e.g., ",[32,4280,4281],{},"sensors\u002Ftemperature\u002Froom1",[29,4283,87,4284,4286],{},[568,4285,4266],{}," receives messages and routes them to subscribers",[29,4288,4289,4292],{},[568,4290,4291],{},"Subscribers"," register interest in topics (with optional wildcards)",[11,4294,4295],{},"Publishers and subscribers never communicate directly. The broker handles all routing, which means:",[26,4297,4298,4301,4304],{},[29,4299,4300],{},"Publishers do not need to know who is listening",[29,4302,4303],{},"Subscribers do not need to know who is sending",[29,4305,4306],{},"Devices can go offline and reconnect without breaking the system",[18,4308,4309],{"id":4277},"Topics",[11,4311,4312,4313,2594],{},"MQTT topics are hierarchical strings separated by ",[32,4314,56],{},[76,4316,4319],{"className":4317,"code":4318,"language":81},[79],"home\u002Flivingroom\u002Ftemperature\nhome\u002Flivingroom\u002Fhumidity\nhome\u002Fbedroom\u002Ftemperature\nfactory\u002Fline1\u002Fmachine3\u002Fstatus\n",[32,4320,4318],{"__ignoreMap":84},[195,4322,4324],{"id":4323},"wildcards-for-subscribers-only","Wildcards (for subscribers only)",[26,4326,4327,4342,4355],{},[29,4328,4329,4331,4332,4335,4336,184,4339],{},[32,4330,52],{}," matches exactly one level: ",[32,4333,4334],{},"home\u002F+\u002Ftemperature"," matches ",[32,4337,4338],{},"home\u002Flivingroom\u002Ftemperature",[32,4340,4341],{},"home\u002Fbedroom\u002Ftemperature",[29,4343,4344,4347,4348,4351,4352],{},[32,4345,4346],{},"#"," matches any number of levels: ",[32,4349,4350],{},"home\u002F#"," matches everything under ",[32,4353,4354],{},"home\u002F",[29,4356,4357],{},"You cannot publish to a wildcard topic — only subscribe",[18,4359,4361],{"id":4360},"quality-of-service-qos","Quality of Service (QoS)",[11,4363,4364],{},"MQTT defines three QoS levels:",[195,4366,4368],{"id":4367},"qos-0-at-most-once","QoS 0: At Most Once",[11,4370,4371],{},"Fire and forget. The message is delivered once with no confirmation. It may be lost if the connection drops.",[11,4373,4374,4377],{},[568,4375,4376],{},"Use for:"," High-frequency sensor data where individual lost readings are acceptable (temperature every second).",[195,4379,4381],{"id":4380},"qos-1-at-least-once","QoS 1: At Least Once",[11,4383,4384],{},"The broker acknowledges receipt. If no acknowledgment arrives, the publisher resends. This may cause duplicates.",[11,4386,4387,4389],{},[568,4388,4376],{}," Important events that must be delivered, where duplicates can be handled idempotently (door opened, alarm triggered).",[195,4391,4393],{"id":4392},"qos-2-exactly-once","QoS 2: Exactly Once",[11,4395,4396],{},"A four-step handshake ensures the message is delivered exactly once. Highest overhead but no duplicates and no loss.",[11,4398,4399,4401],{},[568,4400,4376],{}," Critical commands where duplicates would cause problems (billing events, actuator commands).",[11,4403,4404,4405,4408],{},"The effective QoS is the ",[568,4406,4407],{},"minimum"," of the publisher's QoS and the subscriber's QoS. If you publish at QoS 2 but the subscriber subscribed at QoS 0, the delivery is QoS 0.",[18,4410,4412],{"id":4411},"retained-messages","Retained Messages",[11,4414,4415],{},"A retained message is stored by the broker and sent immediately to any new subscriber on that topic. This is useful for \"last known value\" patterns:",[76,4417,4420],{"className":4418,"code":4419,"language":81},[79],"Topic: sensors\u002Fbattery\u002Flevel\nPayload: \"87\"\nRetained: true\n",[32,4421,4419],{"__ignoreMap":84},[11,4423,4424],{},"When a new subscriber connects, it immediately receives the last battery level without waiting for the next publish. Only one retained message is stored per topic — a new retained message replaces the old one.",[18,4426,4428],{"id":4427},"last-will-and-testament-lwt","Last Will and Testament (LWT)",[11,4430,4431],{},"When a client connects, it can register a \"last will\" message — a message the broker publishes if the client disconnects unexpectedly (without a proper DISCONNECT packet):",[76,4433,4436],{"className":4434,"code":4435,"language":81},[79],"Will Topic: devices\u002Fsensor42\u002Fstatus\nWill Payload: \"offline\"\nWill QoS: 1\nWill Retain: true\n",[32,4437,4435],{"__ignoreMap":84},[11,4439,4440,4441,4444],{},"Combined with a regular retained message on connect (",[32,4442,4443],{},"\"online\"","), this creates a reliable online\u002Foffline status indicator.",[18,4446,4448],{"id":4447},"clean-session-vs-persistent-session","Clean Session vs Persistent Session",[26,4450,4451,4457],{},[29,4452,4453,4456],{},[568,4454,4455],{},"Clean session (true):"," The broker discards any previous session state. Subscriptions must be re-established on each connect. Default for most clients.",[29,4458,4459,4462],{},[568,4460,4461],{},"Persistent session (false):"," The broker stores subscriptions and queued messages (QoS 1+) while the client is offline, delivering them on reconnect.",[18,4464,4466],{"id":4465},"mqtt-50-features","MQTT 5.0 Features",[11,4468,4469],{},"MQTT 5.0 (released 2019) adds:",[26,4471,4472,4478,4484,4490,4496,4502],{},[29,4473,4474,4477],{},[568,4475,4476],{},"Reason codes"," on every acknowledgment",[29,4479,4480,4483],{},[568,4481,4482],{},"Message expiry"," — messages can have a TTL",[29,4485,4486,4489],{},[568,4487,4488],{},"Topic aliases"," — reduce per-message overhead for repeated topics",[29,4491,4492,4495],{},[568,4493,4494],{},"Request\u002Fresponse"," pattern with response topics",[29,4497,4498,4501],{},[568,4499,4500],{},"User properties"," — custom key-value metadata on messages",[29,4503,4504,4507],{},[568,4505,4506],{},"Shared subscriptions"," — load balance messages across multiple subscribers",[18,4509,4511],{"id":4510},"common-brokers","Common Brokers",[96,4513,4514,4527],{},[99,4515,4516],{},[102,4517,4518,4521,4524],{},[105,4519,4520],{},"Broker",[105,4522,4523],{},"Type",[105,4525,4526],{},"Notes",[118,4528,4529,4540,4551,4561,4572],{},[102,4530,4531,4534,4537],{},[123,4532,4533],{},"Mosquitto",[123,4535,4536],{},"Open source",[123,4538,4539],{},"Lightweight, standard reference implementation",[102,4541,4542,4545,4548],{},[123,4543,4544],{},"HiveMQ",[123,4546,4547],{},"Commercial",[123,4549,4550],{},"Enterprise features, clustering",[102,4552,4553,4556,4558],{},[123,4554,4555],{},"EMQX",[123,4557,4536],{},[123,4559,4560],{},"High performance, Erlang-based",[102,4562,4563,4566,4569],{},[123,4564,4565],{},"AWS IoT Core",[123,4567,4568],{},"Cloud",[123,4570,4571],{},"Managed, integrates with AWS services",[102,4573,4574,4577,4579],{},[123,4575,4576],{},"Azure IoT Hub",[123,4578,4568],{},[123,4580,4581],{},"Managed, integrates with Azure services",[18,4583,617],{"id":616},[11,4585,4586,4587,4591],{},"Connect to any MQTT broker over secure WebSockets with ",[621,4588,4590],{"href":4589},"\u002Ftools\u002Fmqtt-client","StackCache MQTT Client",". Subscribe to topics, publish messages, and inspect payloads in real time — directly from your browser with no install.",{"title":84,"searchDepth":321,"depth":321,"links":4593},[4594,4595,4596,4599,4604,4605,4606,4607,4608,4609],{"id":4220,"depth":321,"text":4221},{"id":4259,"depth":321,"text":4260},{"id":4277,"depth":321,"text":4309,"children":4597},[4598],{"id":4323,"depth":335,"text":4324},{"id":4360,"depth":321,"text":4361,"children":4600},[4601,4602,4603],{"id":4367,"depth":335,"text":4368},{"id":4380,"depth":335,"text":4381},{"id":4392,"depth":335,"text":4393},{"id":4411,"depth":321,"text":4412},{"id":4427,"depth":321,"text":4428},{"id":4447,"depth":321,"text":4448},{"id":4465,"depth":321,"text":4466},{"id":4510,"depth":321,"text":4511},{"id":616,"depth":321,"text":617},"IoT","Learn the MQTT protocol for IoT: publish\u002Fsubscribe messaging, QoS levels, retained messages, and last will. Includes broker setup and practical examples.",{},"\u002Fblog\u002Fmqtt-protocol-guide-for-iot",{"title":4209,"description":4611},"blog\u002Fmqtt-protocol-guide-for-iot","mqtt-client","bk27r9fK0V5WiF5mtDDCH07iTSlp1Ie_BhPizQEV8xE",{"id":4619,"title":4620,"body":4621,"category":4199,"date":653,"description":5113,"extension":655,"meta":5114,"navigation":407,"path":5115,"readingTime":427,"seo":5116,"stem":5117,"tool":5118,"updated":661,"__hash__":5119},"blog\u002Fblog\u002Fpassword-security-best-practices.md","Password Security Best Practices for Developers",{"type":8,"value":4622,"toc":5093},[4623,4626,4629,4633,4636,4642,4754,4760,4764,4768,4787,4791,4798,4802,4805,4831,4838,4842,4846,4849,4853,4856,4943,4947,4950,4956,4959,4973,4976,4980,4986,4992,4998,5002,5006,5020,5024,5038,5045,5047,5082,5086],[11,4624,4625],{},"Passwords remain the most common authentication mechanism on the internet. Despite decades of alternatives — biometrics, hardware keys, passkeys — most systems still rely on passwords as their primary or fallback authentication method. Getting password security right protects your users; getting it wrong makes headlines.",[11,4627,4628],{},"This guide covers password generation, storage, and validation from a developer's perspective.",[18,4630,4632],{"id":4631},"password-entropy","Password Entropy",[11,4634,4635],{},"Entropy measures how unpredictable a password is. Higher entropy means more guesses required to crack it. Entropy is measured in bits:",[76,4637,4640],{"className":4638,"code":4639,"language":81},[79],"Entropy = log2(possible_characters ^ length)\n",[32,4641,4639],{"__ignoreMap":84},[96,4643,4644,4660],{},[99,4645,4646],{},[102,4647,4648,4651,4654,4657],{},[105,4649,4650],{},"Password type",[105,4652,4653],{},"Characters",[105,4655,4656],{},"Length",[105,4658,4659],{},"Entropy",[118,4661,4662,4676,4690,4703,4716,4729,4742],{},[102,4663,4664,4667,4670,4673],{},[123,4665,4666],{},"4-digit PIN",[123,4668,4669],{},"10",[123,4671,4672],{},"4",[123,4674,4675],{},"13 bits",[102,4677,4678,4681,4684,4687],{},[123,4679,4680],{},"8 lowercase letters",[123,4682,4683],{},"26",[123,4685,4686],{},"8",[123,4688,4689],{},"38 bits",[102,4691,4692,4695,4698,4700],{},[123,4693,4694],{},"8 mixed case + digits",[123,4696,4697],{},"62",[123,4699,4686],{},[123,4701,4702],{},"48 bits",[102,4704,4705,4708,4711,4713],{},[123,4706,4707],{},"12 mixed + symbols",[123,4709,4710],{},"95",[123,4712,868],{},[123,4714,4715],{},"79 bits",[102,4717,4718,4721,4723,4726],{},[123,4719,4720],{},"16 mixed + symbols",[123,4722,4710],{},[123,4724,4725],{},"16",[123,4727,4728],{},"105 bits",[102,4730,4731,4734,4737,4739],{},[123,4732,4733],{},"4 random words (diceware)",[123,4735,4736],{},"7,776",[123,4738,4672],{},[123,4740,4741],{},"51 bits",[102,4743,4744,4747,4749,4751],{},[123,4745,4746],{},"6 random words (diceware)",[123,4748,4736],{},[123,4750,921],{},[123,4752,4753],{},"78 bits",[11,4755,4756,4759],{},[568,4757,4758],{},"Minimum recommendation:"," 72+ bits of entropy for important accounts. This means at least 12 characters with mixed case, digits, and symbols — or 6 random words.",[18,4761,4763],{"id":4762},"generating-strong-passwords","Generating Strong Passwords",[195,4765,4767],{"id":4766},"what-makes-a-password-strong","What makes a password strong?",[563,4769,4770,4775,4781],{},[29,4771,4772,4774],{},[568,4773,4656],{}," — the single most important factor. Each additional character multiplies the search space",[29,4776,4777,4780],{},[568,4778,4779],{},"Randomness"," — must be generated by a cryptographic random source, not chosen by a human",[29,4782,4783,4786],{},[568,4784,4785],{},"Uniqueness"," — one password per service, never reused",[195,4788,4790],{"id":4789},"why-humans-are-bad-at-passwords","Why humans are bad at passwords",[11,4792,4793,4794,4797],{},"Humans choose predictable patterns: dictionary words, dates, keyboard patterns (qwerty), substitutions (p@ssw0rd). These patterns are in every password cracker's dictionary. A \"clever\" human-chosen password like ",[32,4795,4796],{},"Tr0ub4dor&3"," has about 28 bits of entropy — far less than a random 12-character string.",[195,4799,4801],{"id":4800},"cryptographic-randomness","Cryptographic randomness",[11,4803,4804],{},"Password generators must use a cryptographic random number generator (CSPRNG):",[26,4806,4807,4813,4819,4825],{},[29,4808,4809,4810],{},"Browser: ",[32,4811,4812],{},"crypto.getRandomValues()",[29,4814,4815,4816],{},"Node.js: ",[32,4817,4818],{},"crypto.randomBytes()",[29,4820,4821,4822],{},"Python: ",[32,4823,4824],{},"secrets.token_hex()",[29,4826,4827,4828],{},"Linux: ",[32,4829,4830],{},"\u002Fdev\u002Furandom",[11,4832,4833,4834,4837],{},"Never use ",[32,4835,4836],{},"Math.random()"," or language-level pseudo-random generators — they are predictable.",[18,4839,4841],{"id":4840},"storing-passwords-server-side","Storing Passwords (Server-Side)",[195,4843,4845],{"id":4844},"never-store-plaintext-passwords","Never store plaintext passwords",[11,4847,4848],{},"This should be obvious, but breaches at major companies prove it is not. Never store passwords in plaintext, Base64, or reversible encryption.",[195,4850,4852],{"id":4851},"use-a-password-hashing-function","Use a password hashing function",[11,4854,4855],{},"Password hashing functions are designed to be slow — they take 100ms+ per hash, making brute-force attacks impractical:",[96,4857,4858,4870],{},[99,4859,4860],{},[102,4861,4862,4865,4868],{},[105,4863,4864],{},"Algorithm",[105,4866,4867],{},"Recommended?",[105,4869,4526],{},[118,4871,4872,4885,4897,4909,4922,4933],{},[102,4873,4874,4879,4882],{},[123,4875,4876],{},[568,4877,4878],{},"Argon2id",[123,4880,4881],{},"Best choice",[123,4883,4884],{},"Winner of the Password Hashing Competition. Memory-hard, resistant to GPU and ASIC attacks",[102,4886,4887,4892,4894],{},[123,4888,4889],{},[568,4890,4891],{},"bcrypt",[123,4893,3443],{},[123,4895,4896],{},"Widely available, CPU-hard. 72-byte input limit",[102,4898,4899,4904,4906],{},[123,4900,4901],{},[568,4902,4903],{},"scrypt",[123,4905,3443],{},[123,4907,4908],{},"Memory-hard and CPU-hard",[102,4910,4911,4916,4919],{},[123,4912,4913],{},[568,4914,4915],{},"PBKDF2",[123,4917,4918],{},"Acceptable",[123,4920,4921],{},"Available everywhere but GPU-parallelizable. Use with SHA-256 and high iteration count",[102,4923,4924,4927,4930],{},[123,4925,4926],{},"MD5",[123,4928,4929],{},"Never",[123,4931,4932],{},"Fast hash, trivially cracked",[102,4934,4935,4938,4940],{},[123,4936,4937],{},"SHA-256",[123,4939,4929],{},[123,4941,4942],{},"Fast hash, not designed for passwords",[195,4944,4946],{"id":4945},"always-salt-passwords","Always salt passwords",[11,4948,4949],{},"A salt is a random value added to each password before hashing:",[76,4951,4954],{"className":4952,"code":4953,"language":81},[79],"hash = argon2id(password + salt)\nstore: salt + hash\n",[32,4955,4953],{"__ignoreMap":84},[11,4957,4958],{},"Salting prevents:",[26,4960,4961,4967],{},[29,4962,4963,4966],{},[568,4964,4965],{},"Rainbow tables"," — precomputed hash lookups",[29,4968,4969,4972],{},[568,4970,4971],{},"Identical hashes"," — two users with the same password get different hashes",[11,4974,4975],{},"Most password hashing libraries handle salting automatically (bcrypt, Argon2id include the salt in the output).",[195,4977,4979],{"id":4978},"configuration-recommendations","Configuration recommendations",[11,4981,4982,4985],{},[568,4983,4984],{},"Argon2id:"," memory=64MB, iterations=3, parallelism=1 (adjust based on your server's resources)",[11,4987,4988,4991],{},[568,4989,4990],{},"bcrypt:"," cost factor=12 (adjust upward as hardware improves)",[11,4993,4994,4997],{},[568,4995,4996],{},"PBKDF2:"," iterations=600,000+ with SHA-256",[18,4999,5001],{"id":5000},"password-validation-rules","Password Validation Rules",[195,5003,5005],{"id":5004},"do","Do",[26,5007,5008,5011,5014,5017],{},[29,5009,5010],{},"Require a minimum length (12+ characters recommended by NIST SP 800-63B)",[29,5012,5013],{},"Check against a list of known breached passwords (the Have I Been Pwned API provides this)",[29,5015,5016],{},"Allow all printable Unicode characters, including spaces",[29,5018,5019],{},"Allow passwords up to at least 128 characters",[195,5021,5023],{"id":5022},"do-not","Do not",[26,5025,5026,5029,5032,5035],{},[29,5027,5028],{},"Require specific character classes (uppercase, digit, symbol) — NIST recommends against this",[29,5030,5031],{},"Impose a maximum length under 64 characters",[29,5033,5034],{},"Force periodic password changes — NIST found this leads to weaker passwords",[29,5036,5037],{},"Use password hints or security questions — these leak information",[11,5039,5040,5041,5044],{},"NIST's research shows that composition rules (must include uppercase, digit, symbol) lead to predictable patterns like ",[32,5042,5043],{},"Password1!",". Length and randomness are more effective than complexity rules.",[18,5046,561],{"id":560},[563,5048,5049,5055,5064,5070,5076],{},[29,5050,5051,5054],{},[568,5052,5053],{},"Logging passwords"," — never log request bodies that contain passwords, even in error logs",[29,5056,5057,5063],{},[568,5058,5059,5060],{},"Comparing with ",[32,5061,5062],{},"=="," — use constant-time comparison to prevent timing attacks",[29,5065,5066,5069],{},[568,5067,5068],{},"Rolling your own crypto"," — use established libraries (bcrypt, Argon2id) rather than implementing hashing yourself",[29,5071,5072,5075],{},[568,5073,5074],{},"Rate limiting failures"," — without rate limiting, an attacker can brute-force the login endpoint",[29,5077,5078,5081],{},[568,5079,5080],{},"Password in URL"," — query parameters appear in server logs, browser history, and referrer headers",[18,5083,5085],{"id":5084},"generate-passwords","Generate Passwords",[11,5087,5088,5092],{},[621,5089,5091],{"href":5090},"\u002Ftools\u002Fpassword-generator","StackCache Password Generator"," creates strong passwords with cryptographic browser randomness. Configure length, character classes, and exclusion rules — everything runs locally with no server.",{"title":84,"searchDepth":321,"depth":321,"links":5094},[5095,5096,5101,5107,5111,5112],{"id":4631,"depth":321,"text":4632},{"id":4762,"depth":321,"text":4763,"children":5097},[5098,5099,5100],{"id":4766,"depth":335,"text":4767},{"id":4789,"depth":335,"text":4790},{"id":4800,"depth":335,"text":4801},{"id":4840,"depth":321,"text":4841,"children":5102},[5103,5104,5105,5106],{"id":4844,"depth":335,"text":4845},{"id":4851,"depth":335,"text":4852},{"id":4945,"depth":335,"text":4946},{"id":4978,"depth":335,"text":4979},{"id":5000,"depth":321,"text":5001,"children":5108},[5109,5110],{"id":5004,"depth":335,"text":5005},{"id":5022,"depth":335,"text":5023},{"id":560,"depth":321,"text":561},{"id":5084,"depth":321,"text":5085},"Learn how to generate, store, and validate passwords securely. Covers entropy, hashing algorithms, salting, and common mistakes in password systems.",{},"\u002Fblog\u002Fpassword-security-best-practices",{"title":4620,"description":5113},"blog\u002Fpassword-security-best-practices","password-generator","p4HX1cih5Se2nv7tPvO7lJL5nkhsS7mmkLZZFlrSYo8",{"id":5121,"title":5122,"body":5123,"category":5980,"date":653,"description":5981,"extension":655,"meta":5982,"navigation":407,"path":5983,"readingTime":433,"seo":5984,"stem":5985,"tool":5986,"updated":661,"__hash__":5987},"blog\u002Fblog\u002Fregex-cheat-sheet-for-developers.md","RegEx Cheat Sheet for Developers",{"type":8,"value":5124,"toc":5959},[5125,5128,5132,5274,5278,5369,5378,5384,5388,5444,5448,5524,5528,5591,5595,5661,5664,5670,5674,5764,5768,5772,5783,5786,5795,5799,5808,5812,5821,5825,5834,5838,5847,5851,5860,5864,5873,5875,5946,5948,5956],[11,5126,5127],{},"Regular expressions (regex) are one of the most powerful text processing tools available to developers — and one of the most frequently forgotten. This cheat sheet covers the syntax you need for everyday pattern matching, from basic metacharacters to advanced lookahead assertions.",[18,5129,5131],{"id":5130},"basic-metacharacters","Basic Metacharacters",[96,5133,5134,5146],{},[99,5135,5136],{},[102,5137,5138,5141,5144],{},[105,5139,5140],{},"Pattern",[105,5142,5143],{},"Matches",[105,5145,3793],{},[118,5147,5148,5163,5179,5195,5211,5226,5242,5258],{},[102,5149,5150,5154,5157],{},[123,5151,5152],{},[32,5153,1220],{},[123,5155,5156],{},"Any character except newline",[123,5158,5159,5162],{},[32,5160,5161],{},"a.c"," → \"abc\", \"a1c\"",[102,5164,5165,5170,5173],{},[123,5166,5167],{},[32,5168,5169],{},"\\d",[123,5171,5172],{},"Any digit (0-9)",[123,5174,5175,5178],{},[32,5176,5177],{},"\\d{3}"," → \"123\"",[102,5180,5181,5186,5189],{},[123,5182,5183],{},[32,5184,5185],{},"\\D",[123,5187,5188],{},"Any non-digit",[123,5190,5191,5194],{},[32,5192,5193],{},"\\D+"," → \"abc\"",[102,5196,5197,5202,5205],{},[123,5198,5199],{},[32,5200,5201],{},"\\w",[123,5203,5204],{},"Word character (a-z, A-Z, 0-9, _)",[123,5206,5207,5210],{},[32,5208,5209],{},"\\w+"," → \"hello_world\"",[102,5212,5213,5218,5221],{},[123,5214,5215],{},[32,5216,5217],{},"\\W",[123,5219,5220],{},"Non-word character",[123,5222,5223,5225],{},[32,5224,5217],{}," → \"@\", \" \"",[102,5227,5228,5233,5236],{},[123,5229,5230],{},[32,5231,5232],{},"\\s",[123,5234,5235],{},"Whitespace (space, tab, newline)",[123,5237,5238,5241],{},[32,5239,5240],{},"\\s+"," → \"  \"",[102,5243,5244,5249,5252],{},[123,5245,5246],{},[32,5247,5248],{},"\\S",[123,5250,5251],{},"Non-whitespace",[123,5253,5254,5257],{},[32,5255,5256],{},"\\S+"," → \"hello\"",[102,5259,5260,5265,5268],{},[123,5261,5262],{},[32,5263,5264],{},"\\b",[123,5266,5267],{},"Word boundary",[123,5269,5270,5273],{},[32,5271,5272],{},"\\bcat\\b"," → \"cat\" but not \"catch\"",[18,5275,5277],{"id":5276},"quantifiers","Quantifiers",[96,5279,5280,5289],{},[99,5281,5282],{},[102,5283,5284,5286],{},[105,5285,5140],{},[105,5287,5288],{},"Meaning",[118,5290,5291,5300,5309,5319,5329,5339,5349,5359],{},[102,5292,5293,5297],{},[123,5294,5295],{},[32,5296,703],{},[123,5298,5299],{},"0 or more",[102,5301,5302,5306],{},[123,5303,5304],{},[32,5305,52],{},[123,5307,5308],{},"1 or more",[102,5310,5311,5316],{},[123,5312,5313],{},[32,5314,5315],{},"?",[123,5317,5318],{},"0 or 1 (optional)",[102,5320,5321,5326],{},[123,5322,5323],{},[32,5324,5325],{},"{n}",[123,5327,5328],{},"Exactly n",[102,5330,5331,5336],{},[123,5332,5333],{},[32,5334,5335],{},"{n,}",[123,5337,5338],{},"n or more",[102,5340,5341,5346],{},[123,5342,5343],{},[32,5344,5345],{},"{n,m}",[123,5347,5348],{},"Between n and m",[102,5350,5351,5356],{},[123,5352,5353],{},[32,5354,5355],{},"*?",[123,5357,5358],{},"0 or more (lazy\u002Fnon-greedy)",[102,5360,5361,5366],{},[123,5362,5363],{},[32,5364,5365],{},"+?",[123,5367,5368],{},"1 or more (lazy\u002Fnon-greedy)",[11,5370,5371,5374,5375,5377],{},[568,5372,5373],{},"Greedy vs lazy:"," By default, quantifiers are greedy — they match as much as possible. Adding ",[32,5376,5315],{}," makes them lazy — matching as little as possible.",[76,5379,5382],{"className":5380,"code":5381,"language":81},[79],"\"\u003Cb>bold\u003C\u002Fb>\" with \u003C.*>  → matches \"\u003Cb>bold\u003C\u002Fb>\" (greedy)\n\"\u003Cb>bold\u003C\u002Fb>\" with \u003C.*?> → matches \"\u003Cb>\" (lazy)\n",[32,5383,5381],{"__ignoreMap":84},[18,5385,5387],{"id":5386},"anchors","Anchors",[96,5389,5390,5398],{},[99,5391,5392],{},[102,5393,5394,5396],{},[105,5395,5140],{},[105,5397,5143],{},[118,5399,5400,5414,5426,5434],{},[102,5401,5402,5407],{},[123,5403,5404],{},[32,5405,5406],{},"^",[123,5408,5409,5410,5413],{},"Start of string (or line with ",[32,5411,5412],{},"m"," flag)",[102,5415,5416,5421],{},[123,5417,5418],{},[32,5419,5420],{},"$",[123,5422,5423,5424,5413],{},"End of string (or line with ",[32,5425,5412],{},[102,5427,5428,5432],{},[123,5429,5430],{},[32,5431,5264],{},[123,5433,5267],{},[102,5435,5436,5441],{},[123,5437,5438],{},[32,5439,5440],{},"\\B",[123,5442,5443],{},"Non-word boundary",[18,5445,5447],{"id":5446},"character-classes","Character Classes",[96,5449,5450,5458],{},[99,5451,5452],{},[102,5453,5454,5456],{},[105,5455,5140],{},[105,5457,5143],{},[118,5459,5460,5470,5480,5490,5500,5512],{},[102,5461,5462,5467],{},[123,5463,5464],{},[32,5465,5466],{},"[abc]",[123,5468,5469],{},"Any of a, b, or c",[102,5471,5472,5477],{},[123,5473,5474],{},[32,5475,5476],{},"[^abc]",[123,5478,5479],{},"Any character except a, b, c",[102,5481,5482,5487],{},[123,5483,5484],{},[32,5485,5486],{},"[a-z]",[123,5488,5489],{},"Any lowercase letter",[102,5491,5492,5497],{},[123,5493,5494],{},[32,5495,5496],{},"[A-Z]",[123,5498,5499],{},"Any uppercase letter",[102,5501,5502,5507],{},[123,5503,5504],{},[32,5505,5506],{},"[0-9]",[123,5508,5509,5510,936],{},"Any digit (same as ",[32,5511,5169],{},[102,5513,5514,5519],{},[123,5515,5516],{},[32,5517,5518],{},"[a-zA-Z0-9_]",[123,5520,5521,5522],{},"Same as ",[32,5523,5201],{},[18,5525,5527],{"id":5526},"groups-and-alternation","Groups and Alternation",[96,5529,5530,5539],{},[99,5531,5532],{},[102,5533,5534,5536],{},[105,5535,5140],{},[105,5537,5538],{},"Purpose",[118,5540,5541,5551,5561,5571,5581],{},[102,5542,5543,5548],{},[123,5544,5545],{},[32,5546,5547],{},"(abc)",[123,5549,5550],{},"Capturing group",[102,5552,5553,5558],{},[123,5554,5555],{},[32,5556,5557],{},"(?:abc)",[123,5559,5560],{},"Non-capturing group",[102,5562,5563,5568],{},[123,5564,5565],{},[32,5566,5567],{},"(?\u003Cname>abc)",[123,5569,5570],{},"Named capturing group",[102,5572,5573,5578],{},[123,5574,5575],{},[32,5576,5577],{},"a|b",[123,5579,5580],{},"Alternation (a or b)",[102,5582,5583,5588],{},[123,5584,5585],{},[32,5586,5587],{},"\\1",[123,5589,5590],{},"Backreference to group 1",[18,5592,5594],{"id":5593},"lookahead-and-lookbehind","Lookahead and Lookbehind",[96,5596,5597,5607],{},[99,5598,5599],{},[102,5600,5601,5603,5605],{},[105,5602,5140],{},[105,5604,3790],{},[105,5606,5143],{},[118,5608,5609,5622,5635,5648],{},[102,5610,5611,5616,5619],{},[123,5612,5613],{},[32,5614,5615],{},"(?=abc)",[123,5617,5618],{},"Positive lookahead",[123,5620,5621],{},"Followed by \"abc\"",[102,5623,5624,5629,5632],{},[123,5625,5626],{},[32,5627,5628],{},"(?!abc)",[123,5630,5631],{},"Negative lookahead",[123,5633,5634],{},"NOT followed by \"abc\"",[102,5636,5637,5642,5645],{},[123,5638,5639],{},[32,5640,5641],{},"(?\u003C=abc)",[123,5643,5644],{},"Positive lookbehind",[123,5646,5647],{},"Preceded by \"abc\"",[102,5649,5650,5655,5658],{},[123,5651,5652],{},[32,5653,5654],{},"(?\u003C!abc)",[123,5656,5657],{},"Negative lookbehind",[123,5659,5660],{},"NOT preceded by \"abc\"",[11,5662,5663],{},"Lookarounds are zero-width assertions — they check a condition without consuming characters.",[76,5665,5668],{"className":5666,"code":5667,"language":81},[79],"\\d+(?= dollars)     → \"100\" in \"100 dollars\"\n(?\u003C=\\$)\\d+           → \"50\" in \"$50\"\n\\b\\w+(?!ing\\b)       → words not ending in \"ing\"\n",[32,5669,5667],{"__ignoreMap":84},[18,5671,5673],{"id":5672},"flags","Flags",[96,5675,5676,5688],{},[99,5677,5678],{},[102,5679,5680,5683,5685],{},[105,5681,5682],{},"Flag",[105,5684,3790],{},[105,5686,5687],{},"Effect",[118,5689,5690,5703,5720,5736,5751],{},[102,5691,5692,5697,5700],{},[123,5693,5694],{},[32,5695,5696],{},"g",[123,5698,5699],{},"Global",[123,5701,5702],{},"Find all matches, not just the first",[102,5704,5705,5710,5713],{},[123,5706,5707],{},[32,5708,5709],{},"i",[123,5711,5712],{},"Case-insensitive",[123,5714,5715,4335,5717],{},[32,5716,621],{},[32,5718,5719],{},"A",[102,5721,5722,5726,5729],{},[123,5723,5724],{},[32,5725,5412],{},[123,5727,5728],{},"Multiline",[123,5730,5731,184,5733,5735],{},[32,5732,5406],{},[32,5734,5420],{}," match line boundaries",[102,5737,5738,5743,5746],{},[123,5739,5740],{},[32,5741,5742],{},"s",[123,5744,5745],{},"Dotall",[123,5747,5748,5750],{},[32,5749,1220],{}," matches newline characters",[102,5752,5753,5758,5761],{},[123,5754,5755],{},[32,5756,5757],{},"u",[123,5759,5760],{},"Unicode",[123,5762,5763],{},"Full Unicode support",[18,5765,5767],{"id":5766},"practical-patterns","Practical Patterns",[195,5769,5771],{"id":5770},"email-simplified","Email (simplified)",[76,5773,5777],{"className":5774,"code":5775,"language":5776,"meta":84,"style":84},"language-regex shiki shiki-themes github-light github-dark","[\\w.-]+@[\\w.-]+\\.\\w{2,}\n","regex",[32,5778,5779],{"__ignoreMap":84},[210,5780,5781],{"class":212,"line":213},[210,5782,5775],{},[195,5784,5785],{"id":259},"URL",[76,5787,5789],{"className":5774,"code":5788,"language":5776,"meta":84,"style":84},"https?:\\\u002F\\\u002F[\\w.-]+(?:\\\u002F[\\w.\u002F?#&=-]*)?\n",[32,5790,5791],{"__ignoreMap":84},[210,5792,5793],{"class":212,"line":213},[210,5794,5788],{},[195,5796,5798],{"id":5797},"ipv4-address","IPv4 Address",[76,5800,5802],{"className":5774,"code":5801,"language":5776,"meta":84,"style":84},"\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b\n",[32,5803,5804],{"__ignoreMap":84},[210,5805,5806],{"class":212,"line":213},[210,5807,5801],{},[195,5809,5811],{"id":5810},"date-yyyy-mm-dd","Date (YYYY-MM-DD)",[76,5813,5815],{"className":5774,"code":5814,"language":5776,"meta":84,"style":84},"\\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\\d|3[01])\n",[32,5816,5817],{"__ignoreMap":84},[210,5818,5819],{"class":212,"line":213},[210,5820,5814],{},[195,5822,5824],{"id":5823},"phone-number-us","Phone Number (US)",[76,5826,5828],{"className":5774,"code":5827,"language":5776,"meta":84,"style":84},"(?:\\+1[-.\\s]?)?(?:\\(?\\d{3}\\)?[-.\\s]?)?\\d{3}[-.\\s]?\\d{4}\n",[32,5829,5830],{"__ignoreMap":84},[210,5831,5832],{"class":212,"line":213},[210,5833,5827],{},[195,5835,5837],{"id":5836},"hex-color","Hex Color",[76,5839,5841],{"className":5774,"code":5840,"language":5776,"meta":84,"style":84},"#(?:[0-9a-fA-F]{3}){1,2}\\b\n",[32,5842,5843],{"__ignoreMap":84},[210,5844,5845],{"class":212,"line":213},[210,5846,5840],{},[195,5848,5850],{"id":5849},"html-tag","HTML Tag",[76,5852,5854],{"className":5774,"code":5853,"language":5776,"meta":84,"style":84},"\u003C\\\u002F?[\\w]+(?:\\s+[\\w-]+(?:=\"[^\"]*\")?)*\\s*\\\u002F?>\n",[32,5855,5856],{"__ignoreMap":84},[210,5857,5858],{"class":212,"line":213},[210,5859,5853],{},[195,5861,5863],{"id":5862},"password-strength-8-chars-upper-lower-digit","Password Strength (8+ chars, upper, lower, digit)",[76,5865,5867],{"className":5774,"code":5866,"language":5776,"meta":84,"style":84},"^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).{8,}$\n",[32,5868,5869],{"__ignoreMap":84},[210,5870,5871],{"class":212,"line":213},[210,5872,5866],{},[18,5874,561],{"id":560},[563,5876,5877,5912,5925,5936],{},[29,5878,5879,575,5882,1749,5884,1749,5886,1749,5888,1749,5890,1749,5892,1749,5894,1749,5896,1749,5898,1749,5901,1749,5903,1749,5905,5908,5909,5911],{},[568,5880,5881],{},"Not escaping special characters",[32,5883,1220],{},[32,5885,703],{},[32,5887,52],{},[32,5889,5315],{},[32,5891,262],{},[32,5893,936],{},[32,5895,2585],{},[32,5897,2576],{},[32,5899,5900],{},"\\",[32,5902,5406],{},[32,5904,5420],{},[32,5906,5907],{},"|"," all have special meaning. Escape them with ",[32,5910,5900],{}," when matching literally.",[29,5913,5914,575,5917,5920,5921,5924],{},[568,5915,5916],{},"Greedy matching",[32,5918,5919],{},".*"," in the middle of a pattern often matches more than expected. Use ",[32,5922,5923],{},".*?"," for lazy matching or be more specific.",[29,5926,5927,5930,5931,184,5933,5935],{},[568,5928,5929],{},"Not anchoring"," — without ",[32,5932,5406],{},[32,5934,5420],{},", a pattern can match anywhere in the string, not just the full string.",[29,5937,5938,5941,5942,5945],{},[568,5939,5940],{},"Catastrophic backtracking"," — nested quantifiers like ",[32,5943,5944],{},"(a+)+b"," can cause exponential backtracking. Avoid patterns where the regex engine has too many ways to match.",[18,5947,617],{"id":616},[11,5949,5950,5951,5955],{},"Test your regex patterns with live highlighting using ",[621,5952,5954],{"href":5953},"\u002Ftools\u002Fregex-tester","StackCache Regex Tester",". See matches, capture groups, and named groups in real time — all locally in your browser.",[627,5957,5958],{},"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);}",{"title":84,"searchDepth":321,"depth":321,"links":5960},[5961,5962,5963,5964,5965,5966,5967,5968,5978,5979],{"id":5130,"depth":321,"text":5131},{"id":5276,"depth":321,"text":5277},{"id":5386,"depth":321,"text":5387},{"id":5446,"depth":321,"text":5447},{"id":5526,"depth":321,"text":5527},{"id":5593,"depth":321,"text":5594},{"id":5672,"depth":321,"text":5673},{"id":5766,"depth":321,"text":5767,"children":5969},[5970,5971,5972,5973,5974,5975,5976,5977],{"id":5770,"depth":335,"text":5771},{"id":259,"depth":335,"text":5785},{"id":5797,"depth":335,"text":5798},{"id":5810,"depth":335,"text":5811},{"id":5823,"depth":335,"text":5824},{"id":5836,"depth":335,"text":5837},{"id":5849,"depth":335,"text":5850},{"id":5862,"depth":335,"text":5863},{"id":560,"depth":321,"text":561},{"id":616,"depth":321,"text":617},"Reference","A practical regex reference with patterns for emails, URLs, IPs, dates, and more. Covers metacharacters, quantifiers, groups, lookahead, and flags.",{},"\u002Fblog\u002Fregex-cheat-sheet-for-developers",{"title":5122,"description":5981},"blog\u002Fregex-cheat-sheet-for-developers","regex-tester","Tr56_w7fl9qLYaMEYGyZebCxaGingnJUgdfCLftlLuY",{"id":5989,"title":5990,"body":5991,"category":652,"date":653,"description":6760,"extension":655,"meta":6761,"navigation":407,"path":6762,"readingTime":422,"seo":6763,"stem":6764,"tool":6765,"updated":661,"__hash__":6766},"blog\u002Fblog\u002Fsql-formatting-best-practices.md","SQL Formatting Best Practices",{"type":8,"value":5992,"toc":6746},[5993,5996,5999,6003,6006,6017,6020,6085,6088,6102,6106,6134,6179,6183,6192,6223,6227,6230,6239,6242,6246,6249,6294,6298,6301,6331,6334,6338,6341,6465,6469,6472,6514,6518,6523,6547,6553,6577,6580,6584,6587,6706,6709,6713,6733,6737,6744],[11,5994,5995],{},"Well-formatted SQL is the difference between a query you can debug in 30 seconds and one that takes 30 minutes. When a query fails at 2 AM, formatting is not cosmetic — it is operational. Yet SQL formatting is inconsistent across teams, with debates about uppercase keywords, indent depth, and comma placement that never resolve.",[11,5997,5998],{},"This guide establishes practical formatting rules with reasoning, so you can pick a style, enforce it, and move on.",[18,6000,6002],{"id":6001},"why-format-sql","Why Format SQL?",[11,6004,6005],{},"Unformatted SQL is common in production:",[76,6007,6011],{"className":6008,"code":6009,"language":6010,"meta":84,"style":84},"language-sql shiki shiki-themes github-light github-dark","SELECT u.id, u.name, u.email, o.total, o.created_at FROM users u JOIN orders o ON u.id = o.user_id WHERE o.status = 'completed' AND o.total > 100 ORDER BY o.created_at DESC LIMIT 20;\n","sql",[32,6012,6013],{"__ignoreMap":84},[210,6014,6015],{"class":212,"line":213},[210,6016,6009],{},[11,6018,6019],{},"The same query, formatted:",[76,6021,6023],{"className":6008,"code":6022,"language":6010,"meta":84,"style":84},"SELECT\n  u.id,\n  u.name,\n  u.email,\n  o.total,\n  o.created_at\nFROM users u\nJOIN orders o ON u.id = o.user_id\nWHERE o.status = 'completed'\n  AND o.total > 100\nORDER BY o.created_at DESC\nLIMIT 20;\n",[32,6024,6025,6030,6035,6040,6045,6050,6055,6060,6065,6070,6075,6080],{"__ignoreMap":84},[210,6026,6027],{"class":212,"line":213},[210,6028,6029],{},"SELECT\n",[210,6031,6032],{"class":212,"line":321},[210,6033,6034],{},"  u.id,\n",[210,6036,6037],{"class":212,"line":335},[210,6038,6039],{},"  u.name,\n",[210,6041,6042],{"class":212,"line":346},[210,6043,6044],{},"  u.email,\n",[210,6046,6047],{"class":212,"line":416},[210,6048,6049],{},"  o.total,\n",[210,6051,6052],{"class":212,"line":422},[210,6053,6054],{},"  o.created_at\n",[210,6056,6057],{"class":212,"line":427},[210,6058,6059],{},"FROM users u\n",[210,6061,6062],{"class":212,"line":433},[210,6063,6064],{},"JOIN orders o ON u.id = o.user_id\n",[210,6066,6067],{"class":212,"line":439},[210,6068,6069],{},"WHERE o.status = 'completed'\n",[210,6071,6072],{"class":212,"line":497},[210,6073,6074],{},"  AND o.total > 100\n",[210,6076,6077],{"class":212,"line":1312},[210,6078,6079],{},"ORDER BY o.created_at DESC\n",[210,6081,6082],{"class":212,"line":1320},[210,6083,6084],{},"LIMIT 20;\n",[11,6086,6087],{},"Formatted SQL makes it obvious:",[26,6089,6090,6093,6096,6099],{},[29,6091,6092],{},"Which columns are selected",[29,6094,6095],{},"Which tables are joined and how",[29,6097,6098],{},"What filters are applied",[29,6100,6101],{},"How results are ordered",[18,6103,6105],{"id":6104},"rule-1-one-clause-per-line","Rule 1: One Clause Per Line",[11,6107,6108,6109,1749,6112,1749,6115,1749,6118,1749,6121,1749,6124,1749,6127,1749,6130,6133],{},"Each major clause (",[32,6110,6111],{},"SELECT",[32,6113,6114],{},"FROM",[32,6116,6117],{},"WHERE",[32,6119,6120],{},"JOIN",[32,6122,6123],{},"ORDER BY",[32,6125,6126],{},"GROUP BY",[32,6128,6129],{},"HAVING",[32,6131,6132],{},"LIMIT",") starts on its own line:",[76,6135,6137],{"className":6008,"code":6136,"language":6010,"meta":84,"style":84},"SELECT count(*) AS total\nFROM orders\nWHERE created_at >= '2024-01-01'\n  AND status = 'completed'\nGROUP BY customer_id\nHAVING count(*) > 5\nORDER BY total DESC\nLIMIT 10;\n",[32,6138,6139,6144,6149,6154,6159,6164,6169,6174],{"__ignoreMap":84},[210,6140,6141],{"class":212,"line":213},[210,6142,6143],{},"SELECT count(*) AS total\n",[210,6145,6146],{"class":212,"line":321},[210,6147,6148],{},"FROM orders\n",[210,6150,6151],{"class":212,"line":335},[210,6152,6153],{},"WHERE created_at >= '2024-01-01'\n",[210,6155,6156],{"class":212,"line":346},[210,6157,6158],{},"  AND status = 'completed'\n",[210,6160,6161],{"class":212,"line":416},[210,6162,6163],{},"GROUP BY customer_id\n",[210,6165,6166],{"class":212,"line":422},[210,6167,6168],{},"HAVING count(*) > 5\n",[210,6170,6171],{"class":212,"line":427},[210,6172,6173],{},"ORDER BY total DESC\n",[210,6175,6176],{"class":212,"line":433},[210,6177,6178],{},"LIMIT 10;\n",[18,6180,6182],{"id":6181},"rule-2-indent-continuation-lines","Rule 2: Indent Continuation Lines",[11,6184,6185,6186,6188,6189,6191],{},"Columns in ",[32,6187,6111],{},", conditions in ",[32,6190,6117],{},", and join conditions continue with consistent indentation (2 or 4 spaces):",[76,6193,6195],{"className":6008,"code":6194,"language":6010,"meta":84,"style":84},"SELECT\n  u.name,\n  u.email,\n  count(o.id) AS order_count,\n  sum(o.total) AS lifetime_value\nFROM users u\n",[32,6196,6197,6201,6205,6209,6214,6219],{"__ignoreMap":84},[210,6198,6199],{"class":212,"line":213},[210,6200,6029],{},[210,6202,6203],{"class":212,"line":321},[210,6204,6039],{},[210,6206,6207],{"class":212,"line":335},[210,6208,6044],{},[210,6210,6211],{"class":212,"line":346},[210,6212,6213],{},"  count(o.id) AS order_count,\n",[210,6215,6216],{"class":212,"line":416},[210,6217,6218],{},"  sum(o.total) AS lifetime_value\n",[210,6220,6221],{"class":212,"line":422},[210,6222,6059],{},[18,6224,6226],{"id":6225},"rule-3-uppercase-keywords","Rule 3: Uppercase Keywords",[11,6228,6229],{},"SQL keywords in UPPERCASE distinguish them from identifiers:",[76,6231,6233],{"className":6008,"code":6232,"language":6010,"meta":84,"style":84},"SELECT name FROM users WHERE id = 42 ORDER BY created_at DESC;\n",[32,6234,6235],{"__ignoreMap":84},[210,6236,6237],{"class":212,"line":213},[210,6238,6232],{},[11,6240,6241],{},"Not everyone agrees on this — lowercase keywords are more readable to some developers, and syntax highlighting makes case irrelevant in most editors. Pick one style for your team and enforce it.",[18,6243,6245],{"id":6244},"rule-4-one-column-per-line-in-select","Rule 4: One Column Per Line in SELECT",[11,6247,6248],{},"For more than 2-3 columns, put each on its own line:",[76,6250,6252],{"className":6008,"code":6251,"language":6010,"meta":84,"style":84},"SELECT\n  u.id,\n  u.name,\n  u.email,\n  u.created_at,\n  count(o.id) AS order_count\nFROM users u\nLEFT JOIN orders o ON u.id = o.user_id\nGROUP BY u.id, u.name, u.email, u.created_at;\n",[32,6253,6254,6258,6262,6266,6270,6275,6280,6284,6289],{"__ignoreMap":84},[210,6255,6256],{"class":212,"line":213},[210,6257,6029],{},[210,6259,6260],{"class":212,"line":321},[210,6261,6034],{},[210,6263,6264],{"class":212,"line":335},[210,6265,6039],{},[210,6267,6268],{"class":212,"line":346},[210,6269,6044],{},[210,6271,6272],{"class":212,"line":416},[210,6273,6274],{},"  u.created_at,\n",[210,6276,6277],{"class":212,"line":422},[210,6278,6279],{},"  count(o.id) AS order_count\n",[210,6281,6282],{"class":212,"line":427},[210,6283,6059],{},[210,6285,6286],{"class":212,"line":433},[210,6287,6288],{},"LEFT JOIN orders o ON u.id = o.user_id\n",[210,6290,6291],{"class":212,"line":439},[210,6292,6293],{},"GROUP BY u.id, u.name, u.email, u.created_at;\n",[18,6295,6297],{"id":6296},"rule-5-align-joins","Rule 5: Align JOINs",[11,6299,6300],{},"Each JOIN gets its own line with the ON condition:",[76,6302,6304],{"className":6008,"code":6303,"language":6010,"meta":84,"style":84},"FROM orders o\nJOIN users u ON u.id = o.user_id\nJOIN products p ON p.id = o.product_id\nLEFT JOIN reviews r ON r.order_id = o.id\n  AND r.deleted_at IS NULL;\n",[32,6305,6306,6311,6316,6321,6326],{"__ignoreMap":84},[210,6307,6308],{"class":212,"line":213},[210,6309,6310],{},"FROM orders o\n",[210,6312,6313],{"class":212,"line":321},[210,6314,6315],{},"JOIN users u ON u.id = o.user_id\n",[210,6317,6318],{"class":212,"line":335},[210,6319,6320],{},"JOIN products p ON p.id = o.product_id\n",[210,6322,6323],{"class":212,"line":346},[210,6324,6325],{},"LEFT JOIN reviews r ON r.order_id = o.id\n",[210,6327,6328],{"class":212,"line":416},[210,6329,6330],{},"  AND r.deleted_at IS NULL;\n",[11,6332,6333],{},"Multi-condition joins indent the additional conditions.",[18,6335,6337],{"id":6336},"rule-6-format-ctes-clearly","Rule 6: Format CTEs Clearly",[11,6339,6340],{},"Common Table Expressions (CTEs) are the modern way to structure complex queries. Format each CTE as a named block:",[76,6342,6344],{"className":6008,"code":6343,"language":6010,"meta":84,"style":84},"WITH monthly_revenue AS (\n  SELECT\n    date_trunc('month', created_at) AS month,\n    sum(total) AS revenue\n  FROM orders\n  WHERE status = 'completed'\n  GROUP BY 1\n),\ngrowth AS (\n  SELECT\n    month,\n    revenue,\n    lag(revenue) OVER (ORDER BY month) AS prev_revenue,\n    round(\n      (revenue - lag(revenue) OVER (ORDER BY month))\n      \u002F lag(revenue) OVER (ORDER BY month) * 100,\n      1\n    ) AS growth_pct\n  FROM monthly_revenue\n)\nSELECT *\nFROM growth\nWHERE growth_pct IS NOT NULL\nORDER BY month;\n",[32,6345,6346,6351,6356,6361,6366,6371,6376,6381,6386,6391,6395,6400,6405,6410,6415,6420,6425,6430,6435,6440,6445,6450,6455,6460],{"__ignoreMap":84},[210,6347,6348],{"class":212,"line":213},[210,6349,6350],{},"WITH monthly_revenue AS (\n",[210,6352,6353],{"class":212,"line":321},[210,6354,6355],{},"  SELECT\n",[210,6357,6358],{"class":212,"line":335},[210,6359,6360],{},"    date_trunc('month', created_at) AS month,\n",[210,6362,6363],{"class":212,"line":346},[210,6364,6365],{},"    sum(total) AS revenue\n",[210,6367,6368],{"class":212,"line":416},[210,6369,6370],{},"  FROM orders\n",[210,6372,6373],{"class":212,"line":422},[210,6374,6375],{},"  WHERE status = 'completed'\n",[210,6377,6378],{"class":212,"line":427},[210,6379,6380],{},"  GROUP BY 1\n",[210,6382,6383],{"class":212,"line":433},[210,6384,6385],{},"),\n",[210,6387,6388],{"class":212,"line":439},[210,6389,6390],{},"growth AS (\n",[210,6392,6393],{"class":212,"line":497},[210,6394,6355],{},[210,6396,6397],{"class":212,"line":1312},[210,6398,6399],{},"    month,\n",[210,6401,6402],{"class":212,"line":1320},[210,6403,6404],{},"    revenue,\n",[210,6406,6407],{"class":212,"line":1328},[210,6408,6409],{},"    lag(revenue) OVER (ORDER BY month) AS prev_revenue,\n",[210,6411,6412],{"class":212,"line":1333},[210,6413,6414],{},"    round(\n",[210,6416,6417],{"class":212,"line":1341},[210,6418,6419],{},"      (revenue - lag(revenue) OVER (ORDER BY month))\n",[210,6421,6422],{"class":212,"line":1351},[210,6423,6424],{},"      \u002F lag(revenue) OVER (ORDER BY month) * 100,\n",[210,6426,6427],{"class":212,"line":1359},[210,6428,6429],{},"      1\n",[210,6431,6432],{"class":212,"line":1370},[210,6433,6434],{},"    ) AS growth_pct\n",[210,6436,6437],{"class":212,"line":1378},[210,6438,6439],{},"  FROM monthly_revenue\n",[210,6441,6442],{"class":212,"line":1386},[210,6443,6444],{},")\n",[210,6446,6447],{"class":212,"line":1391},[210,6448,6449],{},"SELECT *\n",[210,6451,6452],{"class":212,"line":1399},[210,6453,6454],{},"FROM growth\n",[210,6456,6457],{"class":212,"line":2243},[210,6458,6459],{},"WHERE growth_pct IS NOT NULL\n",[210,6461,6462],{"class":212,"line":2251},[210,6463,6464],{},"ORDER BY month;\n",[18,6466,6468],{"id":6467},"rule-7-subqueries-get-full-formatting","Rule 7: Subqueries Get Full Formatting",[11,6470,6471],{},"Inline subqueries are formatted with the same rules, indented one level:",[76,6473,6475],{"className":6008,"code":6474,"language":6010,"meta":84,"style":84},"SELECT *\nFROM users\nWHERE id IN (\n  SELECT user_id\n  FROM orders\n  WHERE total > 1000\n    AND created_at >= '2024-01-01'\n);\n",[32,6476,6477,6481,6486,6491,6496,6500,6505,6510],{"__ignoreMap":84},[210,6478,6479],{"class":212,"line":213},[210,6480,6449],{},[210,6482,6483],{"class":212,"line":321},[210,6484,6485],{},"FROM users\n",[210,6487,6488],{"class":212,"line":335},[210,6489,6490],{},"WHERE id IN (\n",[210,6492,6493],{"class":212,"line":346},[210,6494,6495],{},"  SELECT user_id\n",[210,6497,6498],{"class":212,"line":416},[210,6499,6370],{},[210,6501,6502],{"class":212,"line":422},[210,6503,6504],{},"  WHERE total > 1000\n",[210,6506,6507],{"class":212,"line":427},[210,6508,6509],{},"    AND created_at >= '2024-01-01'\n",[210,6511,6512],{"class":212,"line":433},[210,6513,3253],{},[18,6515,6517],{"id":6516},"comma-placement-leading-vs-trailing","Comma Placement: Leading vs Trailing",[11,6519,6520,6522],{},[568,6521,3488],{}," (more common):",[76,6524,6526],{"className":6008,"code":6525,"language":6010,"meta":84,"style":84},"SELECT\n  name,\n  email,\n  created_at\n",[32,6527,6528,6532,6537,6542],{"__ignoreMap":84},[210,6529,6530],{"class":212,"line":213},[210,6531,6029],{},[210,6533,6534],{"class":212,"line":321},[210,6535,6536],{},"  name,\n",[210,6538,6539],{"class":212,"line":335},[210,6540,6541],{},"  email,\n",[210,6543,6544],{"class":212,"line":346},[210,6545,6546],{},"  created_at\n",[11,6548,6549,6552],{},[568,6550,6551],{},"Leading commas"," (easier to comment out lines):",[76,6554,6556],{"className":6008,"code":6555,"language":6010,"meta":84,"style":84},"SELECT\n  name\n  , email\n  , created_at\n",[32,6557,6558,6562,6567,6572],{"__ignoreMap":84},[210,6559,6560],{"class":212,"line":213},[210,6561,6029],{},[210,6563,6564],{"class":212,"line":321},[210,6565,6566],{},"  name\n",[210,6568,6569],{"class":212,"line":335},[210,6570,6571],{},"  , email\n",[210,6573,6574],{"class":212,"line":346},[210,6575,6576],{},"  , created_at\n",[11,6578,6579],{},"Both are valid. Pick one for your team. Most formatters default to trailing commas.",[18,6581,6583],{"id":6582},"dialect-differences","Dialect Differences",[11,6585,6586],{},"Different databases have different keywords, functions, and syntax:",[96,6588,6589,6607],{},[99,6590,6591],{},[102,6592,6593,6595,6598,6601,6604],{},[105,6594,3421],{},[105,6596,6597],{},"PostgreSQL",[105,6599,6600],{},"MySQL",[105,6602,6603],{},"SQL Server",[105,6605,6606],{},"SQLite",[118,6608,6609,6632,6660,6683],{},[102,6610,6611,6614,6619,6624,6628],{},[123,6612,6613],{},"String concat",[123,6615,6616],{},[32,6617,6618],{},"||",[123,6620,6621],{},[32,6622,6623],{},"CONCAT()",[123,6625,6626],{},[32,6627,52],{},[123,6629,6630],{},[32,6631,6618],{},[102,6633,6634,6637,6645,6650,6655],{},[123,6635,6636],{},"Auto increment",[123,6638,6639,2620,6642],{},[32,6640,6641],{},"SERIAL",[32,6643,6644],{},"GENERATED",[123,6646,6647],{},[32,6648,6649],{},"AUTO_INCREMENT",[123,6651,6652],{},[32,6653,6654],{},"IDENTITY",[123,6656,6657],{},[32,6658,6659],{},"AUTOINCREMENT",[102,6661,6662,6665,6670,6674,6679],{},[123,6663,6664],{},"Limit",[123,6666,6667],{},[32,6668,6669],{},"LIMIT n",[123,6671,6672],{},[32,6673,6669],{},[123,6675,6676],{},[32,6677,6678],{},"TOP n",[123,6680,6681],{},[32,6682,6669],{},[102,6684,6685,6688,6693,6698,6702],{},[123,6686,6687],{},"Boolean",[123,6689,6690],{},[32,6691,6692],{},"TRUE\u002FFALSE",[123,6694,6695],{},[32,6696,6697],{},"1\u002F0",[123,6699,6700],{},[32,6701,6697],{},[123,6703,6704],{},[32,6705,6697],{},[11,6707,6708],{},"A good formatter supports multiple dialects and adjusts keyword recognition accordingly.",[18,6710,6712],{"id":6711},"enforcing-consistency","Enforcing Consistency",[563,6714,6715,6721,6727],{},[29,6716,6717,6720],{},[568,6718,6719],{},"Use an automated formatter"," — manual formatting drifts. Run a formatter in CI or as a pre-commit hook.",[29,6722,6723,6726],{},[568,6724,6725],{},"Document your style"," — one page in your wiki: indent size, keyword case, comma placement, CTE style.",[29,6728,6729,6732],{},[568,6730,6731],{},"Format on save"," — editor plugins that format SQL on save eliminate style debates in code review.",[18,6734,6736],{"id":6735},"format-your-sql","Format Your SQL",[11,6738,6739,6743],{},[621,6740,6742],{"href":6741},"\u002Ftools\u002Fsql-formatter","StackCache SQL Formatter"," formats SQL for 13 dialects including PostgreSQL, MySQL, SQLite, SQL Server, Oracle, BigQuery, and Snowflake. Paste your query, choose your dialect, and get consistently formatted output — all locally in your browser.",[627,6745,5958],{},{"title":84,"searchDepth":321,"depth":321,"links":6747},[6748,6749,6750,6751,6752,6753,6754,6755,6756,6757,6758,6759],{"id":6001,"depth":321,"text":6002},{"id":6104,"depth":321,"text":6105},{"id":6181,"depth":321,"text":6182},{"id":6225,"depth":321,"text":6226},{"id":6244,"depth":321,"text":6245},{"id":6296,"depth":321,"text":6297},{"id":6336,"depth":321,"text":6337},{"id":6467,"depth":321,"text":6468},{"id":6516,"depth":321,"text":6517},{"id":6582,"depth":321,"text":6583},{"id":6711,"depth":321,"text":6712},{"id":6735,"depth":321,"text":6736},"Learn how to format SQL queries for readability. Covers indentation, capitalization, JOIN alignment, CTE formatting, and team style consistency.",{},"\u002Fblog\u002Fsql-formatting-best-practices",{"title":5990,"description":6760},"blog\u002Fsql-formatting-best-practices","sql-formatter","4GpCUuAk4iZD-B9u3kv1znDbEbvZKAGATzyF3AFXb0g",{"id":6768,"title":6769,"body":6770,"category":7286,"date":653,"description":7287,"extension":655,"meta":7288,"navigation":407,"path":7289,"readingTime":427,"seo":7290,"stem":7291,"tool":7292,"updated":661,"__hash__":7293},"blog\u002Fblog\u002Fsubnet-calculator-how-to-read-cidr.md","Subnet Calculator: How to Read CIDR Notation",{"type":8,"value":6771,"toc":7275},[6772,6775,6778,6782,6785,6791,6797,6803,6807,6818,6932,6935,6939,6942,6956,6962,6988,6991,6995,6998,7026,7029,7059,7063,7066,7072,7075,7079,7082,7132,7135,7155,7159,7162,7214,7217,7221,7224,7261,7264,7268],[11,6773,6774],{},"CIDR (Classless Inter-Domain Routing) notation is how networks are defined in the modern internet. If you configure firewalls, security groups, VPCs, VPNs, or any network infrastructure, you need to read CIDR fluently. Yet many developers treat subnet math as a black art, reaching for a calculator without understanding what the numbers mean.",[11,6776,6777],{},"This guide teaches you to read CIDR notation by sight and understand what the numbers represent.",[18,6779,6781],{"id":6780},"what-is-cidr-notation","What is CIDR Notation?",[11,6783,6784],{},"CIDR notation appends a prefix length to an IP address:",[76,6786,6789],{"className":6787,"code":6788,"language":81},[79],"192.168.1.0\u002F24\n",[32,6790,6788],{"__ignoreMap":84},[11,6792,87,6793,6796],{},[32,6794,6795],{},"\u002F24"," means the first 24 bits (out of 32) identify the network. The remaining 8 bits identify hosts within that network.",[76,6798,6801],{"className":6799,"code":6800,"language":81},[79],"192.168.1.0\u002F24\n\nIP:        11000000.10101000.00000001.00000000\nMask:      11111111.11111111.11111111.00000000\n           ├── network (24 bits) ──┤├ host (8)┤\n",[32,6802,6800],{"__ignoreMap":84},[18,6804,6806],{"id":6805},"the-subnet-mask","The Subnet Mask",[11,6808,6809,6810,6813,6814,6817],{},"The prefix length ",[32,6811,6812],{},"\u002Fn"," creates a subnet mask — a 32-bit value where the first ",[32,6815,6816],{},"n"," bits are 1 and the rest are 0:",[96,6819,6820,6836],{},[99,6821,6822],{},[102,6823,6824,6827,6830,6833],{},[105,6825,6826],{},"Prefix",[105,6828,6829],{},"Subnet mask",[105,6831,6832],{},"Total addresses",[105,6834,6835],{},"Usable hosts",[118,6837,6838,6851,6864,6877,6890,6904,6918],{},[102,6839,6840,6843,6846,6848],{},[123,6841,6842],{},"\u002F32",[123,6844,6845],{},"255.255.255.255",[123,6847,917],{},[123,6849,6850],{},"0 (single host)",[102,6852,6853,6856,6859,6861],{},[123,6854,6855],{},"\u002F30",[123,6857,6858],{},"255.255.255.252",[123,6860,4672],{},[123,6862,6863],{},"2 (point-to-point)",[102,6865,6866,6869,6872,6874],{},[123,6867,6868],{},"\u002F28",[123,6870,6871],{},"255.255.255.240",[123,6873,4725],{},[123,6875,6876],{},"14",[102,6878,6879,6881,6884,6887],{},[123,6880,6795],{},[123,6882,6883],{},"255.255.255.0",[123,6885,6886],{},"256",[123,6888,6889],{},"254",[102,6891,6892,6895,6898,6901],{},[123,6893,6894],{},"\u002F20",[123,6896,6897],{},"255.255.240.0",[123,6899,6900],{},"4,096",[123,6902,6903],{},"4,094",[102,6905,6906,6909,6912,6915],{},[123,6907,6908],{},"\u002F16",[123,6910,6911],{},"255.255.0.0",[123,6913,6914],{},"65,536",[123,6916,6917],{},"65,534",[102,6919,6920,6923,6926,6929],{},[123,6921,6922],{},"\u002F8",[123,6924,6925],{},"255.0.0.0",[123,6927,6928],{},"16,777,216",[123,6930,6931],{},"16,777,214",[11,6933,6934],{},"The pattern: each bit you add to the prefix halves the network. Each bit you remove doubles it.",[18,6936,6938],{"id":6937},"network-and-broadcast-addresses","Network and Broadcast Addresses",[11,6940,6941],{},"Every subnet has two reserved addresses:",[26,6943,6944,6950],{},[29,6945,6946,6949],{},[568,6947,6948],{},"Network address"," — all host bits set to 0 (first address)",[29,6951,6952,6955],{},[568,6953,6954],{},"Broadcast address"," — all host bits set to 1 (last address)",[11,6957,6958,6959,2594],{},"For ",[32,6960,6961],{},"192.168.1.0\u002F24",[26,6963,6964,6970,6976,6982],{},[29,6965,6966,6967],{},"Network: ",[32,6968,6969],{},"192.168.1.0",[29,6971,6972,6973],{},"First usable host: ",[32,6974,6975],{},"192.168.1.1",[29,6977,6978,6979],{},"Last usable host: ",[32,6980,6981],{},"192.168.1.254",[29,6983,6984,6985],{},"Broadcast: ",[32,6986,6987],{},"192.168.1.255",[11,6989,6990],{},"This is why a \u002F24 has 256 addresses but only 254 usable hosts.",[18,6992,6994],{"id":6993},"reading-cidr-by-sight","Reading CIDR by Sight",[11,6996,6997],{},"With practice, you can read common prefixes instantly:",[26,6999,7000,7005,7010,7015,7020],{},[29,7001,7002,7004],{},[32,7003,6795],{}," = 256 addresses, last octet varies (192.168.1.0 - 192.168.1.255)",[29,7006,7007,7009],{},[32,7008,6908],{}," = 65,536 addresses, last two octets vary (10.0.0.0 - 10.0.255.255)",[29,7011,7012,7014],{},[32,7013,6922],{}," = 16M addresses, last three octets vary (10.0.0.0 - 10.255.255.255)",[29,7016,7017,7019],{},[32,7018,6842],{}," = single IP address (host route)",[29,7021,7022,7025],{},[32,7023,7024],{},"\u002F0"," = all IP addresses (default route)",[11,7027,7028],{},"For anything between, remember: each step from \u002F24 toward \u002F16 doubles the network.",[26,7030,7031,7036,7042,7048,7054],{},[29,7032,7033,7035],{},[32,7034,6795],{}," = 256",[29,7037,7038,7041],{},[32,7039,7040],{},"\u002F23"," = 512",[29,7043,7044,7047],{},[32,7045,7046],{},"\u002F22"," = 1,024",[29,7049,7050,7053],{},[32,7051,7052],{},"\u002F21"," = 2,048",[29,7055,7056,7058],{},[32,7057,6894],{}," = 4,096",[18,7060,7062],{"id":7061},"splitting-subnets","Splitting Subnets",[11,7064,7065],{},"Splitting (subnetting) divides a network into smaller pieces. Split a \u002F24 into four \u002F26 networks:",[76,7067,7070],{"className":7068,"code":7069,"language":81},[79],"192.168.1.0\u002F24 splits into:\n  192.168.1.0\u002F26    (hosts .1 - .62)\n  192.168.1.64\u002F26   (hosts .65 - .126)\n  192.168.1.128\u002F26  (hosts .129 - .190)\n  192.168.1.192\u002F26  (hosts .193 - .254)\n",[32,7071,7069],{"__ignoreMap":84},[11,7073,7074],{},"Each \u002F26 has 64 addresses (62 usable). This is the standard approach for creating VLANs, cloud subnets, or isolated network segments.",[18,7076,7078],{"id":7077},"private-ip-ranges-rfc-1918","Private IP Ranges (RFC 1918)",[11,7080,7081],{},"These ranges are reserved for private networks and are not routable on the public internet:",[96,7083,7084,7097],{},[99,7085,7086],{},[102,7087,7088,7091,7094],{},[105,7089,7090],{},"Range",[105,7092,7093],{},"CIDR",[105,7095,7096],{},"Typical use",[118,7098,7099,7110,7121],{},[102,7100,7101,7104,7107],{},[123,7102,7103],{},"10.0.0.0 - 10.255.255.255",[123,7105,7106],{},"10.0.0.0\u002F8",[123,7108,7109],{},"Large enterprise, cloud VPCs",[102,7111,7112,7115,7118],{},[123,7113,7114],{},"172.16.0.0 - 172.31.255.255",[123,7116,7117],{},"172.16.0.0\u002F12",[123,7119,7120],{},"Mid-size networks",[102,7122,7123,7126,7129],{},[123,7124,7125],{},"192.168.0.0 - 192.168.255.255",[123,7127,7128],{},"192.168.0.0\u002F16",[123,7130,7131],{},"Home and small office",[11,7133,7134],{},"Other reserved ranges:",[26,7136,7137,7143,7149],{},[29,7138,7139,7142],{},[32,7140,7141],{},"127.0.0.0\u002F8"," — loopback (localhost)",[29,7144,7145,7148],{},[32,7146,7147],{},"169.254.0.0\u002F16"," — link-local (auto-assigned when DHCP fails)",[29,7150,7151,7154],{},[32,7152,7153],{},"100.64.0.0\u002F10"," — carrier-grade NAT (RFC 6598)",[18,7156,7158],{"id":7157},"cloud-vpc-sizing","Cloud VPC Sizing",[11,7160,7161],{},"When creating a VPC in AWS, Azure, or GCP, choose the CIDR block carefully — it cannot be changed later:",[96,7163,7164,7179],{},[99,7165,7166],{},[102,7167,7168,7171,7173,7176],{},[105,7169,7170],{},"VPC size",[105,7172,7093],{},[105,7174,7175],{},"Addresses",[105,7177,7178],{},"Subnets you can create",[118,7180,7181,7192,7203],{},[102,7182,7183,7185,7187,7189],{},[123,7184,3508],{},[123,7186,6795],{},[123,7188,6886],{},[123,7190,7191],{},"4 x \u002F26 or 8 x \u002F28",[102,7193,7194,7196,7198,7200],{},[123,7195,3505],{},[123,7197,6894],{},[123,7199,6900],{},[123,7201,7202],{},"16 x \u002F24",[102,7204,7205,7207,7209,7211],{},[123,7206,3511],{},[123,7208,6908],{},[123,7210,6914],{},[123,7212,7213],{},"256 x \u002F24",[11,7215,7216],{},"AWS reserves 5 addresses per subnet (network, broadcast, and three for internal services). So an AWS \u002F24 subnet has 251 usable IPs, not 254.",[18,7218,7220],{"id":7219},"the-wildcard-mask","The Wildcard Mask",[11,7222,7223],{},"The wildcard mask is the bitwise inverse of the subnet mask. It is used in Cisco ACLs and OSPF configuration:",[96,7225,7226,7235],{},[99,7227,7228],{},[102,7229,7230,7232],{},[105,7231,6829],{},[105,7233,7234],{},"Wildcard mask",[118,7236,7237,7245,7253],{},[102,7238,7239,7242],{},[123,7240,7241],{},"255.255.255.0 (\u002F24)",[123,7243,7244],{},"0.0.0.255",[102,7246,7247,7250],{},[123,7248,7249],{},"255.255.240.0 (\u002F20)",[123,7251,7252],{},"0.0.15.255",[102,7254,7255,7258],{},[123,7256,7257],{},"255.255.255.252 (\u002F30)",[123,7259,7260],{},"0.0.0.3",[11,7262,7263],{},"The wildcard mask marks which bits can vary. In a \u002F24, the last 8 bits (0.0.0.255) can be any value.",[18,7265,7267],{"id":7266},"calculate-subnets","Calculate Subnets",[11,7269,7270,7274],{},[621,7271,7273],{"href":7272},"\u002Ftools\u002Fip-calculator","StackCache IP Calculator"," derives network address, broadcast address, subnet mask, wildcard mask, host range, and CIDR splits — all locally in your browser with no account needed.",{"title":84,"searchDepth":321,"depth":321,"links":7276},[7277,7278,7279,7280,7281,7282,7283,7284,7285],{"id":6780,"depth":321,"text":6781},{"id":6805,"depth":321,"text":6806},{"id":6937,"depth":321,"text":6938},{"id":6993,"depth":321,"text":6994},{"id":7061,"depth":321,"text":7062},{"id":7077,"depth":321,"text":7078},{"id":7157,"depth":321,"text":7158},{"id":7219,"depth":321,"text":7220},{"id":7266,"depth":321,"text":7267},"Networking","Learn CIDR notation, subnet masks, network and broadcast addresses, and how to split networks. Includes a visual breakdown and practical examples.",{},"\u002Fblog\u002Fsubnet-calculator-how-to-read-cidr",{"title":6769,"description":7287},"blog\u002Fsubnet-calculator-how-to-read-cidr","ip-calculator","Vozn1sZgM8Ti1xnPmNeUR7KMINbC_h-mPWp5OoN87wI",{"id":7295,"title":7296,"body":7297,"category":7286,"date":653,"description":7752,"extension":655,"meta":7753,"navigation":407,"path":7754,"readingTime":439,"seo":7755,"stem":7756,"tool":7757,"updated":661,"__hash__":7758},"blog\u002Fblog\u002Funderstanding-dns-record-types.md","Understanding DNS Record Types",{"type":8,"value":7298,"toc":7725},[7299,7302,7305,7309,7316,7319,7343,7347,7351,7354,7360,7363,7367,7370,7376,7379,7383,7387,7397,7403,7406,7410,7413,7440,7443,7447,7451,7454,7460,7465,7476,7480,7484,7487,7493,7497,7500,7506,7509,7513,7517,7520,7526,7529,7533,7537,7540,7546,7552,7556,7559,7565,7568,7572,7715,7717],[11,7300,7301],{},"DNS (Domain Name System) is the infrastructure that translates domain names into IP addresses and routes email, certificates, and services. Understanding DNS record types is essential for configuring domains, debugging connectivity, setting up email, and deploying web services.",[11,7303,7304],{},"This guide covers every DNS record type you are likely to encounter, with practical examples.",[18,7306,7308],{"id":7307},"how-dns-works","How DNS Works",[11,7310,7311,7312,7315],{},"When you type ",[32,7313,7314],{},"example.com"," in a browser, your computer sends a DNS query to a recursive resolver (like Cloudflare 1.1.1.1 or Google 8.8.8.8). The resolver walks the DNS hierarchy — root servers, TLD servers, authoritative servers — to find the answer, then caches it for the TTL (Time To Live) duration.",[11,7317,7318],{},"Each DNS record has four parts:",[26,7320,7321,7326,7331,7337],{},[29,7322,7323,7325],{},[568,7324,3790],{}," — the domain or subdomain",[29,7327,7328,7330],{},[568,7329,4523],{}," — what kind of record (A, MX, TXT, etc.)",[29,7332,7333,7336],{},[568,7334,7335],{},"Value"," — the record data",[29,7338,7339,7342],{},[568,7340,7341],{},"TTL"," — how long resolvers can cache the answer (in seconds)",[18,7344,7346],{"id":7345},"address-records","Address Records",[195,7348,7350],{"id":7349},"a-record-ipv4-address","A Record (IPv4 Address)",[11,7352,7353],{},"Maps a domain to an IPv4 address. This is the most fundamental record type.",[76,7355,7358],{"className":7356,"code":7357,"language":81},[79],"example.com.    300    IN    A    93.184.216.34\n",[32,7359,7357],{"__ignoreMap":84},[11,7361,7362],{},"Most domains have one or more A records. Multiple A records provide basic round-robin load balancing.",[195,7364,7366],{"id":7365},"aaaa-record-ipv6-address","AAAA Record (IPv6 Address)",[11,7368,7369],{},"Maps a domain to an IPv6 address. The \"quad-A\" name comes from being four times the size of an A record (128 bits vs 32 bits).",[76,7371,7374],{"className":7372,"code":7373,"language":81},[79],"example.com.    300    IN    AAAA    2606:2800:220:1:248:1893:25c8:1946\n",[32,7375,7373],{"__ignoreMap":84},[11,7377,7378],{},"Publish both A and AAAA records for dual-stack connectivity.",[18,7380,7382],{"id":7381},"mail-records","Mail Records",[195,7384,7386],{"id":7385},"mx-record-mail-exchange","MX Record (Mail Exchange)",[11,7388,7389,7390,7393,7394,1220],{},"Directs email to the correct mail servers. Each MX record has a ",[568,7391,7392],{},"priority"," (lower = preferred) and a ",[568,7395,7396],{},"mail server hostname",[76,7398,7401],{"className":7399,"code":7400,"language":81},[79],"example.com.    3600    IN    MX    10 mail1.example.com.\nexample.com.    3600    IN    MX    20 mail2.example.com.\n",[32,7402,7400],{"__ignoreMap":84},[11,7404,7405],{},"Sending servers try the lowest priority first and fall back to higher priorities.",[195,7407,7409],{"id":7408},"txt-record-for-spf-dkim-dmarc","TXT Record (for SPF, DKIM, DMARC)",[11,7411,7412],{},"TXT records store arbitrary text, but their primary modern use is email authentication:",[26,7414,7415,7423,7432],{},[29,7416,7417,256,7420],{},[568,7418,7419],{},"SPF",[32,7421,7422],{},"v=spf1 include:_spf.google.com -all",[29,7424,7425,7428,7429],{},[568,7426,7427],{},"DKIM",": Published at ",[32,7430,7431],{},"selector._domainkey.example.com",[29,7433,7434,7428,7437],{},[568,7435,7436],{},"DMARC",[32,7438,7439],{},"_dmarc.example.com",[11,7441,7442],{},"TXT records are also used for domain verification (Google, Let's Encrypt), DKIM keys, and other protocols.",[18,7444,7446],{"id":7445},"aliasing-records","Aliasing Records",[195,7448,7450],{"id":7449},"cname-record-canonical-name","CNAME Record (Canonical Name)",[11,7452,7453],{},"Creates an alias from one domain to another. The resolver follows the CNAME to find the actual address.",[76,7455,7458],{"className":7456,"code":7457,"language":81},[79],"www.example.com.    3600    IN    CNAME    example.com.\nblog.example.com.   3600    IN    CNAME    hosting.provider.com.\n",[32,7459,7457],{"__ignoreMap":84},[11,7461,7462],{},[568,7463,7464],{},"Important rules:",[26,7466,7467,7470],{},[29,7468,7469],{},"A CNAME cannot coexist with other record types at the same name (no CNAME + MX at the same subdomain)",[29,7471,7472,7473,7475],{},"You cannot CNAME a zone apex (",[32,7474,7314],{}," without a subdomain) in standard DNS — some providers offer workarounds (ALIAS, ANAME, CNAME flattening)",[18,7477,7479],{"id":7478},"delegation-records","Delegation Records",[195,7481,7483],{"id":7482},"ns-record-name-server","NS Record (Name Server)",[11,7485,7486],{},"Delegates a domain or subdomain to specific name servers. Every domain has NS records pointing to its authoritative DNS servers.",[76,7488,7491],{"className":7489,"code":7490,"language":81},[79],"example.com.    86400    IN    NS    ns1.dnshost.com.\nexample.com.    86400    IN    NS    ns2.dnshost.com.\n",[32,7492,7490],{"__ignoreMap":84},[195,7494,7496],{"id":7495},"soa-record-start-of-authority","SOA Record (Start of Authority)",[11,7498,7499],{},"Contains administrative metadata about the zone: the primary name server, contact email, serial number, and refresh\u002Fretry\u002Fexpire timers.",[76,7501,7504],{"className":7502,"code":7503,"language":81},[79],"example.com.    3600    IN    SOA    ns1.dnshost.com. admin.example.com. 2024010101 3600 900 604800 86400\n",[32,7505,7503],{"__ignoreMap":84},[11,7507,7508],{},"Every DNS zone has exactly one SOA record.",[18,7510,7512],{"id":7511},"security-records","Security Records",[195,7514,7516],{"id":7515},"caa-record-certificate-authority-authorization","CAA Record (Certificate Authority Authorization)",[11,7518,7519],{},"Specifies which certificate authorities (CAs) are allowed to issue TLS certificates for your domain.",[76,7521,7524],{"className":7522,"code":7523,"language":81},[79],"example.com.    3600    IN    CAA    0 issue \"letsencrypt.org\"\nexample.com.    3600    IN    CAA    0 issuewild \"letsencrypt.org\"\nexample.com.    3600    IN    CAA    0 iodef \"mailto:security@example.com\"\n",[32,7525,7523],{"__ignoreMap":84},[11,7527,7528],{},"If no CAA record exists, any CA can issue a certificate. Publishing CAA records prevents unauthorized certificate issuance.",[18,7530,7532],{"id":7531},"service-records","Service Records",[195,7534,7536],{"id":7535},"srv-record-service-locator","SRV Record (Service Locator)",[11,7538,7539],{},"Specifies the host and port for a service. Used by SIP, XMPP, LDAP, and other protocols.",[76,7541,7544],{"className":7542,"code":7543,"language":81},[79],"_sip._tcp.example.com.    3600    IN    SRV    10 60 5060 sip.example.com.\n",[32,7545,7543],{"__ignoreMap":84},[11,7547,7548,7549],{},"Format: ",[32,7550,7551],{},"priority weight port target",[195,7553,7555],{"id":7554},"ptr-record-pointer-reverse-dns","PTR Record (Pointer \u002F Reverse DNS)",[11,7557,7558],{},"Maps an IP address back to a domain name. Used for reverse DNS lookups and email server verification.",[76,7560,7563],{"className":7561,"code":7562,"language":81},[79],"34.216.184.93.in-addr.arpa.    3600    IN    PTR    example.com.\n",[32,7564,7562],{"__ignoreMap":84},[11,7566,7567],{},"Many mail servers reject email from IPs without valid PTR records.",[18,7569,7571],{"id":7570},"quick-reference-table","Quick Reference Table",[96,7573,7574,7585],{},[99,7575,7576],{},[102,7577,7578,7580,7582],{},[105,7579,4523],{},[105,7581,5538],{},[105,7583,7584],{},"Example value",[118,7586,7587,7599,7612,7625,7638,7651,7664,7677,7690,7703],{},[102,7588,7589,7591,7594],{},[123,7590,5719],{},[123,7592,7593],{},"IPv4 address",[123,7595,7596],{},[32,7597,7598],{},"93.184.216.34",[102,7600,7601,7604,7607],{},[123,7602,7603],{},"AAAA",[123,7605,7606],{},"IPv6 address",[123,7608,7609],{},[32,7610,7611],{},"2606:2800:220:1:...",[102,7613,7614,7617,7620],{},[123,7615,7616],{},"MX",[123,7618,7619],{},"Mail server",[123,7621,7622],{},[32,7623,7624],{},"10 mail.example.com.",[102,7626,7627,7630,7633],{},[123,7628,7629],{},"CNAME",[123,7631,7632],{},"Alias to another name",[123,7634,7635],{},[32,7636,7637],{},"example.com.",[102,7639,7640,7643,7646],{},[123,7641,7642],{},"TXT",[123,7644,7645],{},"Text (SPF, DKIM, verification)",[123,7647,7648],{},[32,7649,7650],{},"v=spf1 include:...",[102,7652,7653,7656,7659],{},[123,7654,7655],{},"NS",[123,7657,7658],{},"Name server delegation",[123,7660,7661],{},[32,7662,7663],{},"ns1.dnshost.com.",[102,7665,7666,7669,7672],{},[123,7667,7668],{},"SOA",[123,7670,7671],{},"Zone authority metadata",[123,7673,7674],{},[32,7675,7676],{},"ns1. admin. serial ...",[102,7678,7679,7682,7685],{},[123,7680,7681],{},"CAA",[123,7683,7684],{},"Certificate authority control",[123,7686,7687],{},[32,7688,7689],{},"0 issue \"letsencrypt.org\"",[102,7691,7692,7695,7698],{},[123,7693,7694],{},"SRV",[123,7696,7697],{},"Service host and port",[123,7699,7700],{},[32,7701,7702],{},"10 60 5060 sip.example.com.",[102,7704,7705,7708,7711],{},[123,7706,7707],{},"PTR",[123,7709,7710],{},"Reverse DNS",[123,7712,7713],{},[32,7714,7637],{},[18,7716,617],{"id":616},[11,7718,7719,7720,7724],{},"Look up any DNS record type for any domain with ",[621,7721,7723],{"href":7722},"\u002Ftools\u002Fdns-lookup","StackCache DNS Lookup",". It queries via DNS-over-HTTPS (Cloudflare) and displays results with TTL, DNSSEC status, and full answer details — all from your browser.",{"title":84,"searchDepth":321,"depth":321,"links":7726},[7727,7728,7732,7736,7739,7743,7746,7750,7751],{"id":7307,"depth":321,"text":7308},{"id":7345,"depth":321,"text":7346,"children":7729},[7730,7731],{"id":7349,"depth":335,"text":7350},{"id":7365,"depth":335,"text":7366},{"id":7381,"depth":321,"text":7382,"children":7733},[7734,7735],{"id":7385,"depth":335,"text":7386},{"id":7408,"depth":335,"text":7409},{"id":7445,"depth":321,"text":7446,"children":7737},[7738],{"id":7449,"depth":335,"text":7450},{"id":7478,"depth":321,"text":7479,"children":7740},[7741,7742],{"id":7482,"depth":335,"text":7483},{"id":7495,"depth":335,"text":7496},{"id":7511,"depth":321,"text":7512,"children":7744},[7745],{"id":7515,"depth":335,"text":7516},{"id":7531,"depth":321,"text":7532,"children":7747},[7748,7749],{"id":7535,"depth":335,"text":7536},{"id":7554,"depth":335,"text":7555},{"id":7570,"depth":321,"text":7571},{"id":616,"depth":321,"text":617},"A complete guide to DNS record types: A, AAAA, MX, CNAME, TXT, NS, SOA, CAA, PTR, and SRV. Learn what each record does and when to use it.",{},"\u002Fblog\u002Funderstanding-dns-record-types",{"title":7296,"description":7752},"blog\u002Funderstanding-dns-record-types","dns-lookup","2Er1WidpWnthaXzunjsCzWNqHYPMTf9uNSiQjrfzjLI",{"id":7760,"title":7761,"body":7762,"category":8109,"date":653,"description":8110,"extension":655,"meta":8111,"navigation":407,"path":8112,"readingTime":427,"seo":8113,"stem":8114,"tool":8115,"updated":661,"__hash__":8116},"blog\u002Fblog\u002Fuuid-vs-ulid-which-id-format.md","UUID vs ULID: Which ID Format to Use?",{"type":8,"value":7763,"toc":8100},[7764,7767,7770,7774,7777,7783,7788,7799,7804,7815,7819,7828,7834,7838,7852,7856,7867,7871,7874,7880,7884,7898,7902,7913,7917,8033,8037,8040,8051,8054,8059,8070,8074,8079,8084,8089,8093],[11,7765,7766],{},"Every application needs unique identifiers. The question is which format: UUID v4, UUID v7, ULID, or something else? Each has trade-offs in sortability, collision probability, database performance, and information leakage.",[11,7768,7769],{},"This guide compares the three most popular options so you can make an informed choice.",[18,7771,7773],{"id":7772},"uuid-v4-the-default-choice","UUID v4: The Default Choice",[11,7775,7776],{},"UUID v4 (Universally Unique Identifier, version 4) generates 122 random bits in the standard 8-4-4-4-12 hex format:",[76,7778,7781],{"className":7779,"code":7780,"language":81},[79],"550e8400-e29b-41d4-a716-446655440000\n",[32,7782,7780],{"__ignoreMap":84},[11,7784,7785],{},[568,7786,7787],{},"Advantages:",[26,7789,7790,7793,7796],{},[29,7791,7792],{},"Universally supported — every language, database, and framework has UUID v4 support",[29,7794,7795],{},"No coordination needed — two systems can generate UUIDs independently with negligible collision probability (2^122 possibilities)",[29,7797,7798],{},"No information leakage — purely random, reveals nothing about creation time or order",[11,7800,7801],{},[568,7802,7803],{},"Disadvantages:",[26,7805,7806,7809,7812],{},[29,7807,7808],{},"Not sortable by time — random distribution causes B-tree index fragmentation in databases, leading to slower inserts and more page splits",[29,7810,7811],{},"Not human-readable — 36 characters of hex with dashes",[29,7813,7814],{},"No embedded timestamp — you cannot determine when a record was created from its ID",[18,7816,7818],{"id":7817},"uuid-v7-sortable-uuids","UUID v7: Sortable UUIDs",[11,7820,7821,7822,7827],{},"UUID v7 (defined in ",[621,7823,7826],{"href":7824,"rel":7825},"https:\u002F\u002Fdatatracker.ietf.org\u002Fdoc\u002Fhtml\u002Frfc9562",[2567],"RFC 9562",") embeds a millisecond-precision Unix timestamp in the first 48 bits, followed by random bits:",[76,7829,7832],{"className":7830,"code":7831,"language":81},[79],"018f3e5c-5b00-7000-8000-1a2b3c4d5e6f\n│                    │\n└── timestamp ───────┘ random ──────┘\n",[32,7833,7831],{"__ignoreMap":84},[11,7835,7836],{},[568,7837,7787],{},[26,7839,7840,7843,7846,7849],{},[29,7841,7842],{},"Time-sortable — UUIDs created later have higher values, matching insertion order",[29,7844,7845],{},"Database-friendly — sequential values reduce B-tree page splits and improve write performance",[29,7847,7848],{},"Standard format — uses the same 8-4-4-4-12 format as UUID v4, so existing UUID columns work without schema changes",[29,7850,7851],{},"Timestamp extractable — you can recover the creation time from the ID",[11,7853,7854],{},[568,7855,7803],{},[26,7857,7858,7861,7864],{},[29,7859,7860],{},"Information leakage — the creation timestamp is readable by anyone who has the ID",[29,7862,7863],{},"Millisecond resolution — multiple IDs generated in the same millisecond are ordered by random bits, not guaranteed monotonic within that millisecond",[29,7865,7866],{},"Newer standard — some older libraries and databases do not yet have native UUID v7 support",[18,7868,7870],{"id":7869},"ulid-compact-and-sortable","ULID: Compact and Sortable",[11,7872,7873],{},"ULID (Universally Unique Lexicographically Sortable Identifier) uses a different format: a 48-bit millisecond timestamp followed by 80 random bits, encoded as 26 Crockford Base32 characters:",[76,7875,7878],{"className":7876,"code":7877,"language":81},[79],"01ARZ3NDEKTSV4RRFFQ69G5FAV\n│          │\n└ timestamp┘ randomness ────┘\n",[32,7879,7877],{"__ignoreMap":84},[11,7881,7882],{},[568,7883,7787],{},[26,7885,7886,7889,7892,7895],{},[29,7887,7888],{},"Shorter — 26 characters vs 36 for UUID",[29,7890,7891],{},"Case-insensitive — Crockford Base32 uses only uppercase letters and digits, no confusable characters (no I\u002FL\u002FO\u002FU)",[29,7893,7894],{},"Time-sortable — lexicographic sort matches chronological order",[29,7896,7897],{},"Monotonic option — within the same millisecond, the random component can be incremented to guarantee ordering",[11,7899,7900],{},[568,7901,7803],{},[26,7903,7904,7907,7910],{},[29,7905,7906],{},"Not a standard format — ULIDs cannot be stored in UUID database columns without conversion",[29,7908,7909],{},"Less ecosystem support — not natively supported by most databases and ORMs",[29,7911,7912],{},"Timestamp leakage — same as UUID v7",[18,7914,7916],{"id":7915},"head-to-head-comparison","Head-to-Head Comparison",[96,7918,7919,7934],{},[99,7920,7921],{},[102,7922,7923,7925,7928,7931],{},[105,7924,3421],{},[105,7926,7927],{},"UUID v4",[105,7929,7930],{},"UUID v7",[105,7932,7933],{},"ULID",[118,7935,7936,7948,7961,7972,7984,7997,8010,8022],{},[102,7937,7938,7940,7943,7945],{},[123,7939,4656],{},[123,7941,7942],{},"36 chars",[123,7944,7942],{},[123,7946,7947],{},"26 chars",[102,7949,7950,7953,7956,7958],{},[123,7951,7952],{},"Format",[123,7954,7955],{},"Hex + dashes",[123,7957,7955],{},[123,7959,7960],{},"Crockford Base32",[102,7962,7963,7966,7968,7970],{},[123,7964,7965],{},"Sortable by time",[123,7967,3459],{},[123,7969,3462],{},[123,7971,3462],{},[102,7973,7974,7977,7979,7982],{},[123,7975,7976],{},"Timestamp embedded",[123,7978,3459],{},[123,7980,7981],{},"Yes (ms)",[123,7983,7981],{},[102,7985,7986,7989,7992,7994],{},[123,7987,7988],{},"Random bits",[123,7990,7991],{},"122",[123,7993,4697],{},[123,7995,7996],{},"80",[102,7998,7999,8002,8005,8007],{},[123,8000,8001],{},"Database column type",[123,8003,8004],{},"UUID",[123,8006,8004],{},[123,8008,8009],{},"Text or UUID (with conversion)",[102,8011,8012,8015,8017,8019],{},[123,8013,8014],{},"Standard",[123,8016,7826],{},[123,8018,7826],{},[123,8020,8021],{},"Informal spec",[102,8023,8024,8027,8029,8031],{},[123,8025,8026],{},"Privacy (no time leak)",[123,8028,3462],{},[123,8030,3459],{},[123,8032,3459],{},[18,8034,8036],{"id":8035},"database-performance-impact","Database Performance Impact",[11,8038,8039],{},"In databases with B-tree indexes (PostgreSQL, MySQL, SQLite), random UUIDs (v4) cause index fragmentation because new values are inserted at random positions in the tree. This leads to:",[26,8041,8042,8045,8048],{},[29,8043,8044],{},"More page splits during inserts",[29,8046,8047],{},"Lower cache hit ratio (pages are not sequential)",[29,8049,8050],{},"2-5x slower bulk inserts compared to sequential IDs",[11,8052,8053],{},"UUID v7 and ULID solve this because their time-based prefix makes new values approximately sequential, appending to the end of the index rather than inserting in the middle.",[11,8055,8056],{},[568,8057,8058],{},"Benchmarks (PostgreSQL, 10M rows):",[26,8060,8061,8064,8067],{},[29,8062,8063],{},"Auto-increment integer: baseline",[29,8065,8066],{},"UUID v7: ~1.2x slower inserts, ~1.1x slower reads",[29,8068,8069],{},"UUID v4: ~2.5x slower inserts, ~1.3x slower reads",[18,8071,8073],{"id":8072},"when-to-use-each","When to Use Each",[11,8075,8076,8078],{},[568,8077,7927],{}," — when you need maximum privacy (no timestamp leakage), universal compatibility, or are working with systems that only support UUID format. Good for user-facing IDs where you do not want to reveal creation order.",[11,8080,8081,8083],{},[568,8082,7930],{}," — when you need time-sorted IDs in a system that already uses UUID columns. The best choice for new projects using PostgreSQL, MySQL, or any database with native UUID support. Drop-in replacement for UUID v4 with better performance.",[11,8085,8086,8088],{},[568,8087,7933],{}," — when you need shorter IDs, case-insensitive identifiers, or are building a system without UUID column constraints. Good for URLs, API keys, and systems where 26 characters is significantly better than 36.",[18,8090,8092],{"id":8091},"generate-ids","Generate IDs",[11,8094,8095,8099],{},[621,8096,8098],{"href":8097},"\u002Ftools\u002Fidentifier-generator","StackCache UUID & ULID Generator"," creates UUID v4, UUID v7, and ULID identifiers with cryptographic randomness, directly in your browser. Generate single IDs or batches of up to 100 — all locally with no server.",{"title":84,"searchDepth":321,"depth":321,"links":8101},[8102,8103,8104,8105,8106,8107,8108],{"id":7772,"depth":321,"text":7773},{"id":7817,"depth":321,"text":7818},{"id":7869,"depth":321,"text":7870},{"id":7915,"depth":321,"text":7916},{"id":8035,"depth":321,"text":8036},{"id":8072,"depth":321,"text":8073},{"id":8091,"depth":321,"text":8092},"Architecture","Compare UUID v4, UUID v7, and ULID for unique identifiers. Learn the trade-offs in sortability, collision probability, database performance, and privacy.",{},"\u002Fblog\u002Fuuid-vs-ulid-which-id-format",{"title":7761,"description":8110},"blog\u002Fuuid-vs-ulid-which-id-format","identifier-generator","tJnqY3dIf5w_JDp9qcVyW5HpltqQJlDOL5x23nKFV6U",{"id":8118,"title":8119,"body":8120,"category":8438,"date":653,"description":8439,"extension":655,"meta":8440,"navigation":407,"path":8441,"readingTime":422,"seo":8442,"stem":8443,"tool":8444,"updated":661,"__hash__":8445},"blog\u002Fblog\u002Fwcag-contrast-ratio-requirements.md","WCAG Contrast Ratio Requirements",{"type":8,"value":8121,"toc":8412},[8122,8125,8128,8132,8135,8138,8144,8147,8151,8155,8198,8202,8233,8240,8244,8247,8261,8272,8276,8280,8286,8292,8296,8302,8306,8309,8313,8316,8320,8324,8327,8331,8351,8355,8358,8362,8366,8376,8380,8383,8387,8390,8394,8401,8405],[11,8123,8124],{},"Color contrast is the single most common accessibility failure on the web. The WebAIM Million study consistently finds that over 80% of homepages have at least one WCAG contrast failure. Low contrast text is unreadable for people with low vision, color blindness, or anyone using a screen in bright sunlight.",[11,8126,8127],{},"WCAG (Web Content Accessibility Guidelines) defines specific contrast ratios that text and UI elements must meet. This guide explains what those ratios are, how to measure them, and how to fix failures.",[18,8129,8131],{"id":8130},"what-is-contrast-ratio","What is Contrast Ratio?",[11,8133,8134],{},"Contrast ratio is the relative luminance difference between two colors. It ranges from 1:1 (no contrast — same color) to 21:1 (maximum contrast — black on white).",[11,8136,8137],{},"The formula uses relative luminance (a perceptual measure, not raw brightness):",[76,8139,8142],{"className":8140,"code":8141,"language":81},[79],"contrast ratio = (L1 + 0.05) \u002F (L2 + 0.05)\n",[32,8143,8141],{"__ignoreMap":84},[11,8145,8146],{},"Where L1 is the lighter color's relative luminance and L2 is the darker color's.",[18,8148,8150],{"id":8149},"wcag-21-requirements","WCAG 2.1 Requirements",[195,8152,8154],{"id":8153},"level-aa-minimum","Level AA (Minimum)",[96,8156,8157,8167],{},[99,8158,8159],{},[102,8160,8161,8164],{},[105,8162,8163],{},"Element",[105,8165,8166],{},"Minimum ratio",[118,8168,8169,8179,8189],{},[102,8170,8171,8174],{},[123,8172,8173],{},"Normal text (\u003C 18px or \u003C 14px bold)",[123,8175,8176],{},[568,8177,8178],{},"4.5:1",[102,8180,8181,8184],{},[123,8182,8183],{},"Large text (≥ 18px or ≥ 14px bold)",[123,8185,8186],{},[568,8187,8188],{},"3:1",[102,8190,8191,8194],{},[123,8192,8193],{},"UI components and graphical objects",[123,8195,8196],{},[568,8197,8188],{},[195,8199,8201],{"id":8200},"level-aaa-enhanced","Level AAA (Enhanced)",[96,8203,8204,8212],{},[99,8205,8206],{},[102,8207,8208,8210],{},[105,8209,8163],{},[105,8211,8166],{},[118,8213,8214,8224],{},[102,8215,8216,8219],{},[123,8217,8218],{},"Normal text",[123,8220,8221],{},[568,8222,8223],{},"7:1",[102,8225,8226,8229],{},[123,8227,8228],{},"Large text",[123,8230,8231],{},[568,8232,8178],{},[11,8234,8235,8236,8239],{},"Most organizations target ",[568,8237,8238],{},"Level AA"," as the minimum standard. Level AAA is recommended for text-heavy content like articles and documentation.",[18,8241,8243],{"id":8242},"what-counts-as-large-text","What Counts as \"Large Text\"?",[11,8245,8246],{},"WCAG defines large text as:",[26,8248,8249,8255],{},[29,8250,8251,8254],{},[568,8252,8253],{},"18px (14pt) or larger"," at regular weight",[29,8256,8257,8260],{},[568,8258,8259],{},"14px (10.5pt) or larger"," at bold weight (700+)",[11,8262,8263,8264,8267,8268,8271],{},"CSS ",[32,8265,8266],{},"font-size: 18px"," meets the threshold for normal weight. For bold text, ",[32,8269,8270],{},"font-size: 14px; font-weight: 700"," qualifies as large.",[18,8273,8275],{"id":8274},"common-contrast-failures","Common Contrast Failures",[195,8277,8279],{"id":8278},"light-gray-text-on-white","Light gray text on white",[76,8281,8284],{"className":8282,"code":8283,"language":81},[79],"#999999 on #FFFFFF → 2.85:1 (FAILS AA)\n#767676 on #FFFFFF → 4.54:1 (PASSES AA) ← minimum gray on white\n#595959 on #FFFFFF → 7.0:1  (PASSES AAA)\n",[32,8285,8283],{"__ignoreMap":84},[11,8287,8288,8291],{},[32,8289,8290],{},"#767676"," is the lightest gray that passes AA on white. This is a useful reference point.",[195,8293,8295],{"id":8294},"white-text-on-colored-backgrounds","White text on colored backgrounds",[76,8297,8300],{"className":8298,"code":8299,"language":81},[79],"#FFFFFF on #1E90FF (dodger blue) → 3.07:1 (FAILS for normal text)\n#FFFFFF on #0066CC             → 4.84:1 (PASSES AA)\n#FFFFFF on #004D99             → 7.08:1 (PASSES AAA)\n",[32,8301,8299],{"__ignoreMap":84},[195,8303,8305],{"id":8304},"placeholder-text","Placeholder text",[11,8307,8308],{},"Placeholder text in form inputs is notoriously low contrast. The default browser placeholder color typically fails WCAG AA.",[195,8310,8312],{"id":8311},"disabled-state-colors","Disabled state colors",[11,8314,8315],{},"Disabled UI elements are exempt from contrast requirements under WCAG 2.1 (criterion 1.4.3 note: \"Text that is part of an inactive user interface component\" has no contrast requirement). However, making disabled elements distinguishable from enabled elements still improves usability.",[18,8317,8319],{"id":8318},"how-to-test-contrast","How to Test Contrast",[195,8321,8323],{"id":8322},"browser-devtools","Browser DevTools",[11,8325,8326],{},"Chrome and Firefox DevTools show contrast ratios in the color picker. Open DevTools → Inspect an element → Click the color swatch → See the contrast ratio and WCAG compliance.",[195,8328,8330],{"id":8329},"automated-tools","Automated tools",[26,8332,8333,8339,8345],{},[29,8334,8335,8338],{},[568,8336,8337],{},"axe DevTools"," (browser extension) — scans the entire page for contrast failures",[29,8340,8341,8344],{},[568,8342,8343],{},"Lighthouse"," (built into Chrome) — includes contrast checks in the accessibility audit",[29,8346,8347,8350],{},[568,8348,8349],{},"WAVE"," (web evaluation tool) — highlights contrast errors inline",[195,8352,8354],{"id":8353},"manual-check","Manual check",[11,8356,8357],{},"For custom graphics, gradients, or text on images, you need to check the specific foreground\u002Fbackground color combination. Use a contrast calculator that computes the ratio from two color values.",[18,8359,8361],{"id":8360},"fixing-contrast-issues","Fixing Contrast Issues",[195,8363,8365],{"id":8364},"strategy-1-darken-the-text","Strategy 1: Darken the text",[11,8367,8368,8369,8372,8373,8375],{},"The simplest fix is to make text darker. Going from ",[32,8370,8371],{},"#999"," to ",[32,8374,8290],{}," on white fixes the most common failure with minimal visual change.",[195,8377,8379],{"id":8378},"strategy-2-darken-the-background","Strategy 2: Darken the background",[11,8381,8382],{},"For light text on colored backgrounds, darken the background until the ratio passes. Shift the hue toward a darker shade rather than adding black, which dulls the color.",[195,8384,8386],{"id":8385},"strategy-3-increase-font-size-or-weight","Strategy 3: Increase font size or weight",[11,8388,8389],{},"Large text has a lower contrast threshold (3:1 vs 4.5:1). If a color combination fails at 16px, it may pass at 18px or at 14px bold.",[195,8391,8393],{"id":8392},"strategy-4-add-a-text-shadow-or-background-overlay","Strategy 4: Add a text shadow or background overlay",[11,8395,8396,8397,8400],{},"For text over images, add a semi-transparent overlay between the image and text, or use ",[32,8398,8399],{},"text-shadow"," to create a contrasting halo.",[18,8402,8404],{"id":8403},"check-your-colors","Check Your Colors",[11,8406,8407,8411],{},[621,8408,8410],{"href":8409},"\u002Ftools\u002Fcolor-converter","StackCache Color & Contrast"," converts between Hex, RGB, HSL, and CMYK and checks WCAG contrast ratios for any color pair — all locally in your browser.",{"title":84,"searchDepth":321,"depth":321,"links":8413},[8414,8415,8419,8420,8426,8431,8437],{"id":8130,"depth":321,"text":8131},{"id":8149,"depth":321,"text":8150,"children":8416},[8417,8418],{"id":8153,"depth":335,"text":8154},{"id":8200,"depth":335,"text":8201},{"id":8242,"depth":321,"text":8243},{"id":8274,"depth":321,"text":8275,"children":8421},[8422,8423,8424,8425],{"id":8278,"depth":335,"text":8279},{"id":8294,"depth":335,"text":8295},{"id":8304,"depth":335,"text":8305},{"id":8311,"depth":335,"text":8312},{"id":8318,"depth":321,"text":8319,"children":8427},[8428,8429,8430],{"id":8322,"depth":335,"text":8323},{"id":8329,"depth":335,"text":8330},{"id":8353,"depth":335,"text":8354},{"id":8360,"depth":321,"text":8361,"children":8432},[8433,8434,8435,8436],{"id":8364,"depth":335,"text":8365},{"id":8378,"depth":335,"text":8379},{"id":8385,"depth":335,"text":8386},{"id":8392,"depth":335,"text":8393},{"id":8403,"depth":321,"text":8404},"Accessibility","Understand WCAG 2.1 contrast ratios for text, UI components, and graphical objects. Learn how to test and fix contrast issues for web accessibility.",{},"\u002Fblog\u002Fwcag-contrast-ratio-requirements",{"title":8119,"description":8439},"blog\u002Fwcag-contrast-ratio-requirements","color-converter","8NPrrUNk_gKDWKc0hRyfoM9ZsfcXnTZOJo04V89HWTQ",1788868139187]