[{"data":1,"prerenderedAt":2390},["ShallowReactive",2],{"blog-post-\u002Fblogs\u002Fdurable-execution-and-temporal":3,"all-blogs-for-navigation":255},{"id":4,"title":5,"alt":6,"body":7,"date":241,"description":242,"extension":243,"image":244,"meta":245,"navigation":246,"ogImage":244,"path":247,"published":246,"seo":248,"stem":249,"tags":250,"__hash__":254},"content\u002Fblogs\u002F10. durable-execution-and-temporal.md","Durable Execution: The Problem It Solves and How Temporal Works","Illustration representing reliable workflow execution",{"type":8,"value":9,"toc":229},"minimark",[10,14,17,22,25,28,31,66,69,73,76,94,97,100,104,114,117,134,137,141,148,155,158,162,165,168,172,175,195,198,202,205,208,212,215],[11,12,13],"p",{},"Imagine an online order that needs to charge a card, reserve inventory, wait for a shipping update, and notify the customer. The process may take minutes or days. If a server restarts after charging the card but before recording the shipment, what happens next?",[11,15,16],{},"Without a durable process coordinator, application code must reconstruct what happened. It needs to avoid charging twice, decide which step to retry, track long waits, and handle messages that arrive late or more than once. Durable execution is a way to make that multi-step process recoverable when workers, servers, or networks fail.",[18,19,21],"h2",{"id":20},"what-durable-execution-means","What durable execution means",[11,23,24],{},"Durable execution means recording enough information about a running process that it can continue after a failure. Instead of keeping all progress only in a server's memory, the system persists the workflow's history and state transitions. When a worker disappears, another worker can use that recorded history to rebuild the workflow's state and continue.",[11,26,27],{},"The process can wait for a timer, an external event, or a human decision without requiring a server to remain occupied in memory the whole time. The workflow's progress is stored durably, and a worker can resume it when there is new work to do.",[11,29,30],{},"Durable execution addresses several familiar problems:",[32,33,34,42,48,54,60],"ul",{},[35,36,37,41],"li",{},[38,39,40],"strong",{},"Process crashes:"," in-memory variables disappear when a process stops.",[35,43,44,47],{},[38,45,46],{},"Partial progress:"," a multi-step operation can fail after some side effects have already happened.",[35,49,50,53],{},[38,51,52],{},"Retries:"," a transient error may need another attempt, but careless retries can duplicate work.",[35,55,56,59],{},[38,57,58],{},"Long waits:"," timers and human approvals are awkward to manage with a process that must stay alive.",[35,61,62,65],{},[38,63,64],{},"Coordination:"," messages, timeouts, and service responses can arrive late, repeatedly, or out of order.",[11,67,68],{},"It does not make external systems infallible. A payment provider can still be unavailable, and a request can still have an ambiguous outcome. The application still needs idempotency, sensible retry policies, timeouts, and compensation where a completed side effect must be reversed.",[18,70,72],{"id":71},"a-simple-example","A simple example",[11,74,75],{},"Consider a customer onboarding flow:",[77,78,79,82,85,88,91],"ol",{},[35,80,81],{},"Create the customer account.",[35,83,84],{},"Send a verification email.",[35,86,87],{},"Wait for the customer to verify the address.",[35,89,90],{},"Provision the requested service.",[35,92,93],{},"Send a welcome message.",[11,95,96],{},"If the process is implemented as one request handler, it may time out while waiting for verification. If it is spread across queues and scheduled jobs, the application needs to persist which step completed, correlate messages with the right customer, and decide what to do after each retry.",[11,98,99],{},"A durable workflow models those steps as one logical process. The process can sleep while awaiting verification, then resume when the verification event arrives. If the worker restarts during the wait, the workflow's recorded progress remains available.",[18,101,103],{"id":102},"how-temporal-provides-durable-execution","How Temporal provides durable execution",[11,105,106,113],{},[107,108,112],"a",{"href":109,"rel":110},"https:\u002F\u002Fdocs.temporal.io\u002Ftemporal",[111],"nofollow","Temporal"," is a platform for running durable workflows. A Temporal application has workflow code that describes the orchestration and activity code that performs external or otherwise non-deterministic work. A Temporal Service stores workflow event history and places tasks on task queues; worker processes poll those queues and execute workflow tasks and activities.",[11,115,116],{},"At a high level, the cycle looks like this:",[77,118,119,122,125,128,131],{},[35,120,121],{},"A client starts a workflow execution.",[35,123,124],{},"A worker runs the workflow code and asks Temporal to schedule work, such as an activity or timer.",[35,126,127],{},"The Temporal Service records workflow events in the execution's event history.",[35,129,130],{},"Workers perform activities and report their results.",[35,132,133],{},"The workflow continues from the recorded results and schedules the next work.",[11,135,136],{},"The event history is central. If a worker goes away, another worker can replay the workflow code against the recorded history. During replay, completed activities are represented by their recorded results rather than being run again. The workflow's state is reconstructed, and execution can proceed from the point where new work is needed.",[18,138,140],{"id":139},"workflows-and-activities","Workflows and activities",[11,142,143,144,147],{},"A ",[38,145,146],{},"Workflow"," defines the process and coordinates its steps. Workflow code must be deterministic: given the same recorded history, it must make the same decisions and produce the same commands. This lets Temporal replay the workflow safely to rebuild its state.",[11,149,150,151,154],{},"An ",[38,152,153],{},"Activity"," performs work that interacts with the outside world, such as calling a payment API, sending an email, or writing to a database. Activities can fail for transient reasons, so they can use retry policies and timeouts. Because an activity may have completed an external side effect just before its worker lost contact, activity code should be designed to handle retries safely. Idempotency keys are one common technique when the external service supports them.",[11,156,157],{},"For example, a workflow might coordinate payment and fulfillment while activities call the payment and inventory services. If the workflow worker restarts after payment succeeds, replay uses the recorded workflow history to reconstruct progress. If an activity attempt itself has an uncertain outcome, the activity's retry and idempotency design determines how to avoid an unintended duplicate charge.",[18,159,161],{"id":160},"timers-signals-and-human-input","Timers, signals, and human input",[11,163,164],{},"Durable workflows can wait without keeping a worker busy. A workflow timer is recorded by the service and can trigger later progress. External events can be delivered to a workflow as signals, and the workflow can wait for a signal such as an approval or verification event.",[11,166,167],{},"This is useful for scheduled reminders, delayed retries, subscription renewals, order fulfillment, and other processes that span a long time. The application can express the wait as part of the workflow instead of relying on an in-memory sleep or building all timer recovery logic itself.",[18,169,171],{"id":170},"what-durable-execution-does-not-remove","What durable execution does not remove",[11,173,174],{},"Temporal manages workflow progress, task delivery, event history, and supported retry behavior, but application design still matters:",[32,176,177,180,183,186,189,192],{},[35,178,179],{},"Put external side effects in activities, not in replayed workflow logic.",[35,181,182],{},"Make activities safe to retry, especially when they can charge money or create records.",[35,184,185],{},"Set timeouts and retry policies based on the operation and its failure modes.",[35,187,188],{},"Keep workflow decisions deterministic, and follow Temporal's guidance when changing workflow code used by existing executions.",[35,190,191],{},"Use compensation or a saga-style process when earlier side effects need a business-level reversal.",[35,193,194],{},"Monitor workers and the Temporal Service, and plan how the service and its database are operated.",[11,196,197],{},"Durable execution changes the recovery model; it does not remove the need to understand failure semantics at system boundaries.",[18,199,201],{"id":200},"when-to-consider-it","When to consider it",[11,203,204],{},"Durable execution is a strong fit when a business process has multiple steps, can take a long time, must survive deploys or crashes, or needs careful retries and timers. Examples include payments and fulfillment, onboarding, report generation, data pipelines, and approval flows.",[11,206,207],{},"For a short request that performs one quick operation, a regular service handler may be simpler. The value of a workflow platform grows when coordinating progress and recovery has become more complex than the business logic itself.",[18,209,211],{"id":210},"takeaway","Takeaway",[11,213,214],{},"Durable execution makes process progress persistent so a workflow can recover after failures instead of starting from lost in-memory state. Temporal implements this with workflow event history, deterministic replay, workers, and activities. The model can simplify long-running coordination, while retries and external side effects still need deliberate, safe application design.",[11,216,217,218,222,223,228],{},"For implementation details, see Temporal's official documentation on ",[107,219,221],{"href":109,"rel":220},[111],"what Temporal is"," and ",[107,224,227],{"href":225,"rel":226},"https:\u002F\u002Fdocs.temporal.io\u002Ftasks",[111],"workflow tasks and replay",".",{"title":230,"searchDepth":231,"depth":231,"links":232},"",2,[233,234,235,236,237,238,239,240],{"id":20,"depth":231,"text":21},{"id":71,"depth":231,"text":72},{"id":102,"depth":231,"text":103},{"id":139,"depth":231,"text":140},{"id":160,"depth":231,"text":161},{"id":170,"depth":231,"text":171},{"id":200,"depth":231,"text":201},{"id":210,"depth":231,"text":211},"29th Sep 2026","Learn how durable execution helps long-running processes survive failures, and how Temporal uses workflows, event history, activities, and replay to resume work.","md","\u002Fblogs-img\u002Fblog10.png",{},true,"\u002Fblogs\u002Fdurable-execution-and-temporal",{"title":5,"description":242},"blogs\u002F10. durable-execution-and-temporal",[251,252,253],"durable-execution","temporal","distributed-systems","lhWM-B606UFrilIUvAMMR0cPr0qNoMe9RKgbc9GeaBk",[256,350,501,677,751,1123,1249,1397,1654,1904],{"id":257,"title":258,"alt":259,"body":260,"date":339,"description":340,"extension":243,"image":341,"meta":342,"navigation":246,"ogImage":341,"path":343,"published":246,"seo":344,"stem":345,"tags":346,"__hash__":349},"content\u002Fblogs\u002F1. connect-namecheap-to-vercel.md","How to Connect Your Namecheap Domain to a Vercel App","Steps for connecting a Namecheap domain to a Vercel app",{"type":8,"value":261,"toc":330},[262,267,270,274,281,285,297,301,316,320,323,327],[263,264,266],"h3",{"id":265},"introduction","Introduction",[11,268,269],{},"If you have purchased a domain from Namecheap and want to connect it to your Vercel app, follow these steps.",[263,271,273],{"id":272},"step-1-add-your-domain-to-vercel","Step 1: Add your domain to Vercel",[11,275,276,277,280],{},"Sign in to Vercel and open your project. Go to ",[38,278,279],{},"Settings → Domains",", enter your domain, and add it to the project.",[263,282,284],{"id":283},"step-2-review-vercels-dns-instructions","Step 2: Review Vercel's DNS instructions",[11,286,287,288,292,293,296],{},"After adding the domain, Vercel will show the DNS records it expects. The required records depend on whether you are connecting the apex domain (such as ",[289,290,291],"code",{},"example.com",") or a subdomain (such as ",[289,294,295],{},"www.example.com","). Use the values shown for your domain in Vercel.",[263,298,300],{"id":299},"step-3-add-the-dns-records-in-namecheap","Step 3: Add the DNS records in Namecheap",[11,302,303,304,307,308,311,312,315],{},"Sign in to Namecheap and open ",[38,305,306],{},"Domain List → Manage → Advanced DNS",". Add or update the records Vercel requested. For example, an apex domain commonly uses an A record with host ",[289,309,310],{},"@",", while ",[289,313,314],{},"www"," commonly uses a CNAME record. Use Vercel's current values rather than copying values from another setup. Remove conflicting records if Vercel instructs you to do so.",[263,317,319],{"id":318},"step-4-verify-the-domain","Step 4: Verify the domain",[11,321,322],{},"Return to the Domains page in Vercel. It will check the DNS configuration and show when the domain is connected. DNS changes may take time to propagate.",[263,324,326],{"id":325},"conclusion","Conclusion",[11,328,329],{},"Once the DNS records match Vercel's instructions and have propagated, your Namecheap domain should point to your Vercel app. If verification fails, compare each record in Namecheap with the values shown in Vercel.",{"title":230,"searchDepth":231,"depth":231,"links":331},[332,334,335,336,337,338],{"id":265,"depth":333,"text":266},3,{"id":272,"depth":333,"text":273},{"id":283,"depth":333,"text":284},{"id":299,"depth":333,"text":300},{"id":318,"depth":333,"text":319},{"id":325,"depth":333,"text":326},"1st Mar 2023","Learn how to connect a Namecheap domain to an app deployed on Vercel.","\u002Fblogs-img\u002Fblog1.jpg",{},"\u002Fblogs\u002Fconnect-namecheap-to-vercel",{"title":258,"description":340},"blogs\u002F1. connect-namecheap-to-vercel",[347,348],"namecheap","vercel","DteEqA6Yjcdjwr6YbCF4J3DWr8qrzKY4FEh0xomHPTI",{"id":4,"title":5,"alt":6,"body":351,"date":241,"description":242,"extension":243,"image":244,"meta":498,"navigation":246,"ogImage":244,"path":247,"published":246,"seo":499,"stem":249,"tags":500,"__hash__":254},{"type":8,"value":352,"toc":488},[353,355,357,359,361,363,365,387,389,391,393,405,407,409,411,416,418,430,432,434,438,442,444,446,448,450,452,454,468,470,472,474,476,478,480],[11,354,13],{},[11,356,16],{},[18,358,21],{"id":20},[11,360,24],{},[11,362,27],{},[11,364,30],{},[32,366,367,371,375,379,383],{},[35,368,369,41],{},[38,370,40],{},[35,372,373,47],{},[38,374,46],{},[35,376,377,53],{},[38,378,52],{},[35,380,381,59],{},[38,382,58],{},[35,384,385,65],{},[38,386,64],{},[11,388,68],{},[18,390,72],{"id":71},[11,392,75],{},[77,394,395,397,399,401,403],{},[35,396,81],{},[35,398,84],{},[35,400,87],{},[35,402,90],{},[35,404,93],{},[11,406,96],{},[11,408,99],{},[18,410,103],{"id":102},[11,412,413,113],{},[107,414,112],{"href":109,"rel":415},[111],[11,417,116],{},[77,419,420,422,424,426,428],{},[35,421,121],{},[35,423,124],{},[35,425,127],{},[35,427,130],{},[35,429,133],{},[11,431,136],{},[18,433,140],{"id":139},[11,435,143,436,147],{},[38,437,146],{},[11,439,150,440,154],{},[38,441,153],{},[11,443,157],{},[18,445,161],{"id":160},[11,447,164],{},[11,449,167],{},[18,451,171],{"id":170},[11,453,174],{},[32,455,456,458,460,462,464,466],{},[35,457,179],{},[35,459,182],{},[35,461,185],{},[35,463,188],{},[35,465,191],{},[35,467,194],{},[11,469,197],{},[18,471,201],{"id":200},[11,473,204],{},[11,475,207],{},[18,477,211],{"id":210},[11,479,214],{},[11,481,217,482,222,485,228],{},[107,483,221],{"href":109,"rel":484},[111],[107,486,227],{"href":225,"rel":487},[111],{"title":230,"searchDepth":231,"depth":231,"links":489},[490,491,492,493,494,495,496,497],{"id":20,"depth":231,"text":21},{"id":71,"depth":231,"text":72},{"id":102,"depth":231,"text":103},{"id":139,"depth":231,"text":140},{"id":160,"depth":231,"text":161},{"id":170,"depth":231,"text":171},{"id":200,"depth":231,"text":201},{"id":210,"depth":231,"text":211},{},{"title":5,"description":242},[251,252,253],{"id":502,"title":503,"alt":504,"body":505,"date":666,"description":667,"extension":243,"image":668,"meta":669,"navigation":246,"ogImage":668,"path":670,"published":246,"seo":671,"stem":672,"tags":673,"__hash__":676},"content\u002Fblogs\u002F2. fix-tailwindcss-intellisense-in-nuxt3.md","How to Fix Tailwind CSS IntelliSense in a Nuxt 3 Project","Tailwind CSS IntelliSense settings for a Nuxt 3 project",{"type":8,"value":506,"toc":661},[507,511,520,524,531,534,541,563,654,657],[263,508,510],{"id":509},"the-problem","The problem",[11,512,513,514,519],{},"I was working on a Nuxt 3 project in VS Code, but Tailwind CSS IntelliSense was not behaving as expected. Reinstalling the extension did not help. After researching the issue, I found a ",[107,515,518],{"href":516,"rel":517},"https:\u002F\u002Fgithub.com\u002Ftailwindlabs\u002Ftailwindcss-intellisense\u002Fissues\u002F663#issuecomment-1316788128",[111],"workaround"," that I am sharing here.",[263,521,523],{"id":522},"why-it-happens","Why it happens",[11,525,526,527,530],{},"Nuxt generates files in the ",[289,528,529],{},".nuxt\u002F"," directory during development. A generated Tailwind configuration can be detected alongside the configuration in the project root, which may confuse the IntelliSense extension.",[263,532,533],{"id":518},"Workaround",[11,535,536,537,540],{},"Configure the VS Code extension to ignore the generated ",[289,538,539],{},".nuxt"," directory:",[77,542,543,550,557],{},[35,544,545,546,549],{},"Create a ",[289,547,548],{},".vscode"," directory in your project root if it does not already exist.",[35,551,552,553,556],{},"Create or edit ",[289,554,555],{},".vscode\u002Fsettings.json"," inside it.",[35,558,559,560,562],{},"Add ",[289,561,539],{}," to the extension's excluded files:",[564,565,569],"pre",{"className":566,"code":567,"language":568,"meta":230,"style":230},"language-json shiki shiki-themes github-light dracula","{\n  \"tailwindCSS.files.exclude\": [\"**\u002F.git\u002F**\", \"**\u002Fnode_modules\u002F**\", \"**\u002F.hg\u002F**\", \"**\u002F.svn\u002F**\", \"**\u002F.nuxt\u002F**\"]\n}\n","json",[289,570,571,580,649],{"__ignoreMap":230},[572,573,576],"span",{"class":574,"line":575},"line",1,[572,577,579],{"class":578},"scbbO","{\n",[572,581,582,586,590,593,597,600,603,607,609,612,614,617,619,621,623,626,628,630,632,635,637,639,641,644,646],{"class":574,"line":231},[572,583,585],{"class":584},"sgYky","  \"",[572,587,589],{"class":588},"sDgm9","tailwindCSS.files.exclude",[572,591,592],{"class":584},"\"",[572,594,596],{"class":595},"sDoOe",":",[572,598,599],{"class":578}," [",[572,601,592],{"class":602},"sMWOi",[572,604,606],{"class":605},"sEzAm","**\u002F.git\u002F**",[572,608,592],{"class":602},[572,610,611],{"class":578},", ",[572,613,592],{"class":602},[572,615,616],{"class":605},"**\u002Fnode_modules\u002F**",[572,618,592],{"class":602},[572,620,611],{"class":578},[572,622,592],{"class":602},[572,624,625],{"class":605},"**\u002F.hg\u002F**",[572,627,592],{"class":602},[572,629,611],{"class":578},[572,631,592],{"class":602},[572,633,634],{"class":605},"**\u002F.svn\u002F**",[572,636,592],{"class":602},[572,638,611],{"class":578},[572,640,592],{"class":602},[572,642,643],{"class":605},"**\u002F.nuxt\u002F**",[572,645,592],{"class":602},[572,647,648],{"class":578},"]\n",[572,650,651],{"class":574,"line":333},[572,652,653],{"class":578},"}\n",[11,655,656],{},"The extension should now ignore Nuxt's generated files when searching for Tailwind classes and configuration.",[658,659,660],"style",{},"html pre.shiki code .scbbO, html code.shiki .scbbO{--shiki-default:#24292E;--shiki-dark:#F8F8F2}html pre.shiki code .sgYky, html code.shiki .sgYky{--shiki-default:#005CC5;--shiki-dark:#8BE9FE}html pre.shiki code .sDgm9, html code.shiki .sDgm9{--shiki-default:#005CC5;--shiki-dark:#8BE9FD}html pre.shiki code .sDoOe, html code.shiki .sDoOe{--shiki-default:#24292E;--shiki-dark:#FF79C6}html pre.shiki code .sMWOi, html code.shiki .sMWOi{--shiki-default:#032F62;--shiki-dark:#E9F284}html pre.shiki code .sEzAm, html code.shiki .sEzAm{--shiki-default:#032F62;--shiki-dark:#F1FA8C}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":230,"searchDepth":231,"depth":231,"links":662},[663,664,665],{"id":509,"depth":333,"text":510},{"id":522,"depth":333,"text":523},{"id":518,"depth":333,"text":533},"26th Jan 2023","Tailwind CSS IntelliSense may offer incorrect suggestions in Nuxt 3 when it detects generated configuration files. This workaround tells the VS Code extension to ignore the .nuxt directory.","\u002Fblogs-img\u002Fblog2.jpg",{},"\u002Fblogs\u002Ffix-tailwindcss-intellisense-in-nuxt3",{"title":503,"description":667},"blogs\u002F2. fix-tailwindcss-intellisense-in-nuxt3",[674,675],"nuxt","tailwindcss","Ujbv_ybIoeVrMaUkYn7RGkNjRsxHalF1HPZsxYcu0HU",{"id":678,"title":679,"alt":680,"body":681,"date":339,"description":742,"extension":243,"image":743,"meta":744,"navigation":246,"ogImage":743,"path":745,"published":246,"seo":746,"stem":747,"tags":748,"__hash__":750},"content\u002Fblogs\u002F3. create-namespace-subdomain-connect-to-vercel.md","How to Create a Namecheap Subdomain and Connect It to Vercel","Namecheap DNS settings for connecting a subdomain to Vercel",{"type":8,"value":682,"toc":735},[683,685,688,692,702,706,723,727,730,732],[263,684,266],{"id":265},[11,686,687],{},"You can create a subdomain in Namecheap and point it to an app deployed on Vercel by adding the DNS record Vercel requests. The exact values may vary, so check the domain instructions in your Vercel project.",[263,689,691],{"id":690},"step-1-add-the-subdomain-in-vercel","Step 1: Add the subdomain in Vercel",[11,693,694,695,697,698,701],{},"Open your Vercel project, go to ",[38,696,279],{},", and add the subdomain you want to use, such as ",[289,699,700],{},"app.example.com",". Vercel will show the DNS record needed to connect it.",[263,703,705],{"id":704},"step-2-create-the-dns-record-in-namecheap","Step 2: Create the DNS record in Namecheap",[11,707,303,708,710,711,714,715,718,719,722],{},[38,709,306],{}," for the domain. Add the record shown by Vercel. For a typical subdomain this is a CNAME record: set ",[38,712,713],{},"Host"," to the subdomain label (for example, ",[289,716,717],{},"app",") and use the ",[38,720,721],{},"Value"," provided by Vercel.",[263,724,726],{"id":725},"step-3-verify-the-connection","Step 3: Verify the connection",[11,728,729],{},"Return to the Domains page in Vercel. It will check the DNS configuration and show when the subdomain is connected. DNS updates can take time to propagate.",[263,731,326],{"id":325},[11,733,734],{},"Once the DNS record matches Vercel's instructions and has propagated, the subdomain should direct visitors to your app. If verification fails, compare the record in Namecheap with the values Vercel displays.",{"title":230,"searchDepth":231,"depth":231,"links":736},[737,738,739,740,741],{"id":265,"depth":333,"text":266},{"id":690,"depth":333,"text":691},{"id":704,"depth":333,"text":705},{"id":725,"depth":333,"text":726},{"id":325,"depth":333,"text":326},"Learn how to create a subdomain in Namecheap and connect it to an app deployed on Vercel.","\u002Fblogs-img\u002Fblog3.jpg",{},"\u002Fblogs\u002Fcreate-namespace-subdomain-connect-to-vercel",{"title":679,"description":742},"blogs\u002F3. create-namespace-subdomain-connect-to-vercel",[347,348,749],"dns","6hwsxeRyJ1ngQsrUlb6F3mnh4G8sI36K_8iAf6z6vxk",{"id":752,"title":753,"alt":754,"body":755,"date":339,"description":1114,"extension":243,"image":1115,"meta":1116,"navigation":246,"ogImage":1115,"path":1117,"published":246,"seo":1118,"stem":1119,"tags":1120,"__hash__":1122},"content\u002Fblogs\u002F4. fetch-content-data-render-pages.md","How to Fetch Nuxt Content Data and Render It in a Nuxt Page","Example code for querying and rendering Nuxt Content",{"type":8,"value":756,"toc":1107},[757,766,768,771,775,778,789,793,806,853,857,867,912,916,926,1101,1104],[758,759,760],"blockquote",{},[11,761,762,765],{},[38,763,764],{},"Note:"," This article describes Nuxt Content v2 and Nuxt 3 APIs, which differ from the Nuxt Content v3 setup used by this site. Check the documentation for the versions in your project before applying the examples.",[263,767,266],{"id":265},[11,769,770],{},"Nuxt Content lets you manage Markdown and other content files alongside your application. This guide introduces the Nuxt Content v2 workflow for installing the module, configuring it, creating content, and rendering a document in a page.",[263,772,774],{"id":773},"step-1-install-nuxt-content","Step 1: Install Nuxt Content",[11,776,777],{},"Install the module in your Nuxt 3 project:",[564,779,783],{"className":780,"code":781,"language":782,"meta":230,"style":230},"language-sh shiki shiki-themes github-light dracula","npm install @nuxt\u002Fcontent\n","sh",[289,784,785],{"__ignoreMap":230},[572,786,787],{"class":574,"line":575},[572,788,781],{},[263,790,792],{"id":791},"step-2-configure-the-module","Step 2: Configure the module",[11,794,559,795,798,799,802,803,596],{},[289,796,797],{},"@nuxt\u002Fcontent"," to the ",[289,800,801],{},"modules"," array in your existing ",[289,804,805],{},"nuxt.config.ts",[564,807,811],{"className":808,"code":809,"language":810,"meta":230,"style":230},"language-ts shiki shiki-themes github-light dracula","export default defineNuxtConfig({\n  modules: ['@nuxt\u002Fcontent'],\n})\n","ts",[289,812,813,829,848],{"__ignoreMap":230},[572,814,815,819,822,826],{"class":574,"line":575},[572,816,818],{"class":817},"szJfE","export",[572,820,821],{"class":817}," default",[572,823,825],{"class":824},"sCLZk"," defineNuxtConfig",[572,827,828],{"class":578},"({\n",[572,830,831,834,836,838,841,843,845],{"class":574,"line":231},[572,832,833],{"class":578},"  modules",[572,835,596],{"class":595},[572,837,599],{"class":578},[572,839,840],{"class":602},"'",[572,842,797],{"class":605},[572,844,840],{"class":602},[572,846,847],{"class":578},"],\n",[572,849,850],{"class":574,"line":333},[572,851,852],{"class":578},"})\n",[263,854,856],{"id":855},"step-3-create-a-content-file","Step 3: Create a content file",[11,858,859,860,863,864,596],{},"Create a Markdown file under the ",[289,861,862],{},"content\u002F"," directory, for example ",[289,865,866],{},"content\u002Fhello.md",[564,868,871],{"className":869,"code":870,"language":243,"meta":230,"style":230},"language-md shiki shiki-themes github-light dracula","---\ntitle: Hello, world!\n---\n\n# Welcome to Nuxt Content\n\nThis is an example Markdown document.\n",[289,872,873,879,884,889,895,901,906],{"__ignoreMap":230},[572,874,875],{"class":574,"line":575},[572,876,878],{"class":877},"sdqdA","---\n",[572,880,881],{"class":574,"line":231},[572,882,883],{"class":578},"title: Hello, world!\n",[572,885,886],{"class":574,"line":333},[572,887,878],{"class":888},"sPz4u",[572,890,892],{"class":574,"line":891},4,[572,893,894],{"emptyLinePlaceholder":246},"\n",[572,896,898],{"class":574,"line":897},5,[572,899,900],{"class":888},"# Welcome to Nuxt Content\n",[572,902,904],{"class":574,"line":903},6,[572,905,894],{"emptyLinePlaceholder":246},[572,907,909],{"class":574,"line":908},7,[572,910,911],{"class":578},"This is an example Markdown document.\n",[263,913,915],{"id":914},"step-4-query-and-render-the-document","Step 4: Query and render the document",[11,917,918,919,922,923,596],{},"In a page such as ",[289,920,921],{},"pages\u002F[...slug].vue",", query the route and pass the resulting document to ",[289,924,925],{},"ContentDoc",[564,927,931],{"className":928,"code":929,"language":930,"meta":230,"style":230},"language-vue shiki shiki-themes github-light dracula","\u003Cscript setup lang=\"ts\">\nconst route = useRoute()\nconst { data: page } = await useAsyncData(route.path, () => queryContent(route.path).findOne())\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cmain>\n    \u003CContentDoc :path=\"$route.path\" \u002F>\n  \u003C\u002Fmain>\n\u003C\u002Ftemplate>\n","vue",[289,932,933,961,979,1024,1033,1037,1046,1056,1082,1092],{"__ignoreMap":230},[572,934,935,938,942,946,949,952,954,956,958],{"class":574,"line":575},[572,936,937],{"class":578},"\u003C",[572,939,941],{"class":940},"sR8l4","script",[572,943,945],{"class":944},"sKRiH"," setup",[572,947,948],{"class":944}," lang",[572,950,951],{"class":595},"=",[572,953,592],{"class":602},[572,955,810],{"class":605},[572,957,592],{"class":602},[572,959,960],{"class":578},">\n",[572,962,963,966,970,973,976],{"class":574,"line":231},[572,964,965],{"class":817},"const",[572,967,969],{"class":968},"sZIln"," route",[572,971,972],{"class":817}," =",[572,974,975],{"class":824}," useRoute",[572,977,978],{"class":578},"()\n",[572,980,981,983,986,990,992,995,998,1000,1003,1006,1009,1012,1015,1018,1021],{"class":574,"line":333},[572,982,965],{"class":817},[572,984,985],{"class":578}," { ",[572,987,989],{"class":988},"szYTq","data",[572,991,596],{"class":595},[572,993,994],{"class":968}," page",[572,996,997],{"class":578}," } ",[572,999,951],{"class":817},[572,1001,1002],{"class":817}," await",[572,1004,1005],{"class":824}," useAsyncData",[572,1007,1008],{"class":578},"(route.path, () ",[572,1010,1011],{"class":817},"=>",[572,1013,1014],{"class":824}," queryContent",[572,1016,1017],{"class":578},"(route.path).",[572,1019,1020],{"class":824},"findOne",[572,1022,1023],{"class":578},"())\n",[572,1025,1026,1029,1031],{"class":574,"line":891},[572,1027,1028],{"class":578},"\u003C\u002F",[572,1030,941],{"class":940},[572,1032,960],{"class":578},[572,1034,1035],{"class":574,"line":897},[572,1036,894],{"emptyLinePlaceholder":246},[572,1038,1039,1041,1044],{"class":574,"line":903},[572,1040,937],{"class":578},[572,1042,1043],{"class":940},"template",[572,1045,960],{"class":578},[572,1047,1048,1051,1054],{"class":574,"line":908},[572,1049,1050],{"class":578},"  \u003C",[572,1052,1053],{"class":940},"main",[572,1055,960],{"class":578},[572,1057,1059,1062,1064,1067,1070,1072,1074,1077,1079],{"class":574,"line":1058},8,[572,1060,1061],{"class":578},"    \u003C",[572,1063,925],{"class":940},[572,1065,1066],{"class":578}," :",[572,1068,1069],{"class":944},"path",[572,1071,951],{"class":595},[572,1073,592],{"class":602},[572,1075,1076],{"class":578},"$route.path",[572,1078,592],{"class":602},[572,1080,1081],{"class":578}," \u002F>\n",[572,1083,1085,1088,1090],{"class":574,"line":1084},9,[572,1086,1087],{"class":578},"  \u003C\u002F",[572,1089,1053],{"class":940},[572,1091,960],{"class":578},[572,1093,1095,1097,1099],{"class":574,"line":1094},10,[572,1096,1028],{"class":578},[572,1098,1043],{"class":940},[572,1100,960],{"class":578},[11,1102,1103],{},"The query result can also be used to show fields such as the title or description in your page layout. Refer to the Nuxt Content v2 documentation for the complete API and migration details.",[658,1105,1106],{},"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 .szJfE, html code.shiki .szJfE{--shiki-default:#D73A49;--shiki-dark:#FF79C6}html pre.shiki code .sCLZk, html code.shiki .sCLZk{--shiki-default:#6F42C1;--shiki-dark:#50FA7B}html pre.shiki code .scbbO, html code.shiki .scbbO{--shiki-default:#24292E;--shiki-dark:#F8F8F2}html pre.shiki code .sDoOe, html code.shiki .sDoOe{--shiki-default:#24292E;--shiki-dark:#FF79C6}html pre.shiki code .sMWOi, html code.shiki .sMWOi{--shiki-default:#032F62;--shiki-dark:#E9F284}html pre.shiki code .sEzAm, html code.shiki .sEzAm{--shiki-default:#032F62;--shiki-dark:#F1FA8C}html pre.shiki code .sdqdA, html code.shiki .sdqdA{--shiki-default:#005CC5;--shiki-default-font-weight:bold;--shiki-dark:#6272A4;--shiki-dark-font-weight:inherit}html pre.shiki code .sPz4u, html code.shiki .sPz4u{--shiki-default:#005CC5;--shiki-default-font-weight:bold;--shiki-dark:#BD93F9;--shiki-dark-font-weight:bold}html pre.shiki code .sR8l4, html code.shiki .sR8l4{--shiki-default:#22863A;--shiki-dark:#FF79C6}html pre.shiki code .sKRiH, html code.shiki .sKRiH{--shiki-default:#6F42C1;--shiki-default-font-style:inherit;--shiki-dark:#50FA7B;--shiki-dark-font-style:italic}html pre.shiki code .sZIln, html code.shiki .sZIln{--shiki-default:#005CC5;--shiki-dark:#F8F8F2}html pre.shiki code .szYTq, html code.shiki .szYTq{--shiki-default:#E36209;--shiki-dark:#F8F8F2}",{"title":230,"searchDepth":231,"depth":231,"links":1108},[1109,1110,1111,1112,1113],{"id":265,"depth":333,"text":266},{"id":773,"depth":333,"text":774},{"id":791,"depth":333,"text":792},{"id":855,"depth":333,"text":856},{"id":914,"depth":333,"text":915},"An introduction to querying Markdown content and rendering it in a Nuxt page with Nuxt Content.","\u002Fblogs-img\u002Fblog4.jpg",{},"\u002Fblogs\u002Ffetch-content-data-render-pages",{"title":753,"description":1114},"blogs\u002F4. fetch-content-data-render-pages",[674,1121],"nuxt-content","KZ2xJDxhZH4Hevsmzpoz2m2zbwIMW8BBIjmDkBmUHMY",{"id":1124,"title":1125,"alt":1126,"body":1127,"date":1239,"description":1240,"extension":243,"image":1241,"meta":1242,"navigation":246,"ogImage":1241,"path":1243,"published":246,"seo":1244,"stem":1245,"tags":1246,"__hash__":1248},"content\u002Fblogs\u002F5. vue3-awesome-library.md","Useful Libraries for Vue 3 Projects","Selection of useful libraries for Vue 3 projects",{"type":8,"value":1128,"toc":1232},[1129,1131,1134,1138,1170,1174,1177,1197,1201,1227,1229],[263,1130,266],{"id":265},[11,1132,1133],{},"Vue 3 has a broad ecosystem of libraries that can help with common application needs. Here are some options in a few categories. Review each project's documentation and maintenance status before choosing it for a new application.",[263,1135,1137],{"id":1136},"core-tools","Core tools",[32,1139,1140,1146,1152,1158,1164],{},[35,1141,1142,1145],{},[38,1143,1144],{},"Vue Router",": The official router for building navigable Vue applications.",[35,1147,1148,1151],{},[38,1149,1150],{},"Pinia",": A store library for sharing and managing application state.",[35,1153,1154,1157],{},[38,1155,1156],{},"VueUse",": A collection of Vue composition utilities.",[35,1159,1160,1163],{},[38,1161,1162],{},"Vitest",": A test runner designed to work with Vite-based projects.",[35,1165,1166,1169],{},[38,1167,1168],{},"Vue Macros",": A collection of experimental and proposed syntax extensions for Vue. Check compatibility and project activity before adopting it.",[263,1171,1173],{"id":1172},"ui-libraries","UI libraries",[11,1175,1176],{},"UI libraries provide ready-made components and styling. Some options include:",[32,1178,1179,1185,1191],{},[35,1180,1181,1184],{},[38,1182,1183],{},"Naive UI",": A Vue 3 component library with TypeScript support and theming options.",[35,1186,1187,1190],{},[38,1188,1189],{},"Vuetify",": A Material Design component framework for Vue.",[35,1192,1193,1196],{},[38,1194,1195],{},"Vuestic UI",": A Vue component library with tools for building interfaces and dashboards.",[263,1198,1200],{"id":1199},"other-useful-libraries","Other useful libraries",[32,1202,1203,1209,1215,1221],{},[35,1204,1205,1208],{},[38,1206,1207],{},"VueFire",": Firebase bindings for Vue and Nuxt.",[35,1210,1211,1214],{},[38,1212,1213],{},"Vue I18n",": Internationalization support for Vue applications.",[35,1216,1217,1220],{},[38,1218,1219],{},"AutoAnimate",": Adds simple transitions to interfaces with minimal setup.",[35,1222,1223,1226],{},[38,1224,1225],{},"Vuelidate",": Model-based form validation for Vue.",[263,1228,326],{"id":325},[11,1230,1231],{},"These libraries cover common needs, but the right choice depends on your project and its constraints. Check the current documentation, compatibility, and maintenance activity before adding a dependency.",{"title":230,"searchDepth":231,"depth":231,"links":1233},[1234,1235,1236,1237,1238],{"id":265,"depth":333,"text":266},{"id":1136,"depth":333,"text":1137},{"id":1172,"depth":333,"text":1173},{"id":1199,"depth":333,"text":1200},{"id":325,"depth":333,"text":326},"1st Jan 2023","Explore useful Vue 3 libraries for routing, state management, utilities, testing, and user interface components.","\u002Fblogs-img\u002Fblog5.jpg",{},"\u002Fblogs\u002Fvue3-awesome-library",{"title":1125,"description":1240},"blogs\u002F5. vue3-awesome-library",[930,1247],"javascript","0Ql5scCF8l_TPX87zyImQ6ugzFsfx5FgRFG1eIoy484",{"id":1250,"title":1251,"alt":1252,"body":1253,"date":1387,"description":1388,"extension":243,"image":1389,"meta":1390,"navigation":246,"ogImage":1389,"path":1391,"published":246,"seo":1392,"stem":1393,"tags":1394,"__hash__":1396},"content\u002Fblogs\u002F6. how-to-fix-vuex-type-issue.md","How to Fix Vuex TypeScript Errors in a Vue Project","TypeScript declaration example for Vuex",{"type":8,"value":1254,"toc":1383},[1255,1257,1260,1264,1279,1372,1377,1380],[263,1256,266],{"id":265},[11,1258,1259],{},"In some Vue and TypeScript projects, the editor may report that Vuex types cannot be found. If your installed Vuex version exposes the declaration files shown below, a local module declaration can help TypeScript resolve them.",[263,1261,1263],{"id":1262},"add-a-declaration-file","Add a declaration file",[77,1265,1266,1276],{},[35,1267,545,1268,1271,1272,1275],{},[289,1269,1270],{},"vuex.d.ts"," file in your project root (or another directory included by ",[289,1273,1274],{},"tsconfig.json",").",[35,1277,1278],{},"Add the following declarations:",[564,1280,1282],{"className":808,"code":1281,"language":810,"meta":230,"style":230},"declare module 'vuex' {\n  export * from 'vuex\u002Ftypes\u002Findex.d.ts'\n  export * from 'vuex\u002Ftypes\u002Fhelpers.d.ts'\n  export * from 'vuex\u002Ftypes\u002Flogger.d.ts'\n  export * from 'vuex\u002Ftypes\u002Fvue.d.ts'\n}\n",[289,1283,1284,1303,1323,1338,1353,1368],{"__ignoreMap":230},[572,1285,1286,1289,1292,1295,1298,1300],{"class":574,"line":575},[572,1287,1288],{"class":817},"declare",[572,1290,1291],{"class":817}," module",[572,1293,1294],{"class":602}," '",[572,1296,1297],{"class":605},"vuex",[572,1299,840],{"class":602},[572,1301,1302],{"class":578}," {\n",[572,1304,1305,1308,1312,1315,1317,1320],{"class":574,"line":231},[572,1306,1307],{"class":817},"  export",[572,1309,1311],{"class":1310},"soDru"," *",[572,1313,1314],{"class":817}," from",[572,1316,1294],{"class":602},[572,1318,1319],{"class":605},"vuex\u002Ftypes\u002Findex.d.ts",[572,1321,1322],{"class":602},"'\n",[572,1324,1325,1327,1329,1331,1333,1336],{"class":574,"line":333},[572,1326,1307],{"class":817},[572,1328,1311],{"class":1310},[572,1330,1314],{"class":817},[572,1332,1294],{"class":602},[572,1334,1335],{"class":605},"vuex\u002Ftypes\u002Fhelpers.d.ts",[572,1337,1322],{"class":602},[572,1339,1340,1342,1344,1346,1348,1351],{"class":574,"line":891},[572,1341,1307],{"class":817},[572,1343,1311],{"class":1310},[572,1345,1314],{"class":817},[572,1347,1294],{"class":602},[572,1349,1350],{"class":605},"vuex\u002Ftypes\u002Flogger.d.ts",[572,1352,1322],{"class":602},[572,1354,1355,1357,1359,1361,1363,1366],{"class":574,"line":897},[572,1356,1307],{"class":817},[572,1358,1311],{"class":1310},[572,1360,1314],{"class":817},[572,1362,1294],{"class":602},[572,1364,1365],{"class":605},"vuex\u002Ftypes\u002Fvue.d.ts",[572,1367,1322],{"class":602},[572,1369,1370],{"class":574,"line":903},[572,1371,653],{"class":578},[77,1373,1374],{"start":333},[35,1375,1376],{},"Restart the TypeScript server or development server so it picks up the new declaration.",[11,1378,1379],{},"If the error remains, check that the paths exist in your installed Vuex version and that the declaration file is included by your TypeScript configuration. Package declaration layouts can differ between versions.",[658,1381,1382],{},"html pre.shiki code .szJfE, html code.shiki .szJfE{--shiki-default:#D73A49;--shiki-dark:#FF79C6}html pre.shiki code .sMWOi, html code.shiki .sMWOi{--shiki-default:#032F62;--shiki-dark:#E9F284}html pre.shiki code .sEzAm, html code.shiki .sEzAm{--shiki-default:#032F62;--shiki-dark:#F1FA8C}html pre.shiki code .scbbO, html code.shiki .scbbO{--shiki-default:#24292E;--shiki-dark:#F8F8F2}html pre.shiki code .soDru, html code.shiki .soDru{--shiki-default:#005CC5;--shiki-dark:#BD93F9}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":230,"searchDepth":231,"depth":231,"links":1384},[1385,1386],{"id":265,"depth":333,"text":266},{"id":1262,"depth":333,"text":1263},"9th June 2024","Fix missing Vuex type declarations in a TypeScript project by adding a module declaration file.","\u002Fblogs-img\u002Fblog6.jpg",{},"\u002Fblogs\u002Fhow-to-fix-vuex-type-issue",{"title":1251,"description":1388},"blogs\u002F6. how-to-fix-vuex-type-issue",[930,1297,1395],"typescript","X5-hUBNEDyhqDNULh8mO8ldDmc9ieKpH1ncIbuJZL2U",{"id":1398,"title":1399,"alt":1400,"body":1401,"date":1642,"description":1643,"extension":243,"image":1644,"meta":1645,"navigation":246,"ogImage":1644,"path":1646,"published":246,"seo":1647,"stem":1648,"tags":1649,"__hash__":1653},"content\u002Fblogs\u002F7. redis-ttl-jitter-and-how-i-almost-crashed-a-server.md","Redis TTL Jitter and How It Can Help Prevent a Cache Avalanche 🚀","Redis cache expiration times spread across multiple days",{"type":8,"value":1402,"toc":1634},[1403,1407,1410,1414,1417,1470,1473,1477,1480,1484,1487,1611,1614,1618,1621,1624,1628,1631],[263,1404,1406],{"id":1405},"the-setup-a-cache-without-expiration","The setup: A cache without expiration",[11,1408,1409],{},"We were storing data from another system in Redis to make reads faster, but the keys had no expiration time. As a result, the cache kept growing instead of eventually clearing out old entries.",[263,1411,1413],{"id":1412},"the-task-add-a-ttl","The task: Add a TTL",[11,1415,1416],{},"The task was to set a two-week time to live (TTL) for the cached data. A fixed expiration might look like this with the node-redis API:",[564,1418,1422],{"className":1419,"code":1420,"language":1421,"meta":230,"style":230},"language-js shiki shiki-themes github-light dracula","await redis.set('mykey', value, { EX: 14 * 24 * 60 * 60 })\n","js",[289,1423,1424],{"__ignoreMap":230},[572,1425,1426,1429,1432,1435,1438,1440,1443,1445,1448,1450,1453,1455,1458,1460,1463,1465,1467],{"class":574,"line":575},[572,1427,1428],{"class":817},"await",[572,1430,1431],{"class":578}," redis.",[572,1433,1434],{"class":824},"set",[572,1436,1437],{"class":578},"(",[572,1439,840],{"class":602},[572,1441,1442],{"class":605},"mykey",[572,1444,840],{"class":602},[572,1446,1447],{"class":578},", value, { EX",[572,1449,596],{"class":595},[572,1451,1452],{"class":1310}," 14",[572,1454,1311],{"class":817},[572,1456,1457],{"class":1310}," 24",[572,1459,1311],{"class":817},[572,1461,1462],{"class":1310}," 60",[572,1464,1311],{"class":817},[572,1466,1462],{"class":1310},[572,1468,1469],{"class":578}," })\n",[11,1471,1472],{},"Check the command syntax for your Redis client, since clients expose different APIs.",[263,1474,1476],{"id":1475},"the-problem-synchronized-expirations","The problem: Synchronized expirations",[11,1478,1479],{},"If many keys are created around the same time and all receive the same fixed TTL, they can expire in a short window together. Requests for those values then miss the cache and return to the source system. That sudden increase in work can contribute to a cache avalanche and put pressure on the backend.",[263,1481,1483],{"id":1482},"the-solution-add-jitter","The solution: Add jitter",[11,1485,1486],{},"Jitter adds a random amount of time to each key's expiration so the keys do not all expire together. For example, to spread expirations across 14 to 16 days:",[564,1488,1490],{"className":1419,"code":1489,"language":1421,"meta":230,"style":230},"const secondsPerDay = 24 * 60 * 60\nconst baseTTL = 14 * secondsPerDay\nconst jitter = Math.floor(Math.random() * (2 * secondsPerDay))\nconst ttl = baseTTL + jitter\n\nawait redis.set('mykey', value, { EX: ttl })\n",[289,1491,1492,1512,1528,1566,1584,1588],{"__ignoreMap":230},[572,1493,1494,1496,1499,1501,1503,1505,1507,1509],{"class":574,"line":575},[572,1495,965],{"class":817},[572,1497,1498],{"class":968}," secondsPerDay",[572,1500,972],{"class":817},[572,1502,1457],{"class":1310},[572,1504,1311],{"class":817},[572,1506,1462],{"class":1310},[572,1508,1311],{"class":817},[572,1510,1511],{"class":1310}," 60\n",[572,1513,1514,1516,1519,1521,1523,1525],{"class":574,"line":231},[572,1515,965],{"class":817},[572,1517,1518],{"class":968}," baseTTL",[572,1520,972],{"class":817},[572,1522,1452],{"class":1310},[572,1524,1311],{"class":817},[572,1526,1527],{"class":578}," secondsPerDay\n",[572,1529,1530,1532,1535,1537,1540,1543,1546,1549,1552,1555,1558,1561,1563],{"class":574,"line":333},[572,1531,965],{"class":817},[572,1533,1534],{"class":968}," jitter",[572,1536,972],{"class":817},[572,1538,1539],{"class":578}," Math.",[572,1541,1542],{"class":824},"floor",[572,1544,1545],{"class":578},"(Math.",[572,1547,1548],{"class":824},"random",[572,1550,1551],{"class":578},"() ",[572,1553,1554],{"class":817},"*",[572,1556,1557],{"class":578}," (",[572,1559,1560],{"class":1310},"2",[572,1562,1311],{"class":817},[572,1564,1565],{"class":578}," secondsPerDay))\n",[572,1567,1568,1570,1573,1575,1578,1581],{"class":574,"line":891},[572,1569,965],{"class":817},[572,1571,1572],{"class":968}," ttl",[572,1574,972],{"class":817},[572,1576,1577],{"class":578}," baseTTL ",[572,1579,1580],{"class":817},"+",[572,1582,1583],{"class":578}," jitter\n",[572,1585,1586],{"class":574,"line":897},[572,1587,894],{"emptyLinePlaceholder":246},[572,1589,1590,1592,1594,1596,1598,1600,1602,1604,1606,1608],{"class":574,"line":903},[572,1591,1428],{"class":817},[572,1593,1431],{"class":578},[572,1595,1434],{"class":824},[572,1597,1437],{"class":578},[572,1599,840],{"class":602},[572,1601,1442],{"class":605},[572,1603,840],{"class":602},[572,1605,1447],{"class":578},[572,1607,596],{"class":595},[572,1609,1610],{"class":578}," ttl })\n",[11,1612,1613],{},"Each key now expires at a slightly different time. The spread can reduce synchronized cache misses, though the right range depends on the data and how quickly it can be refreshed.",[263,1615,1617],{"id":1616},"why-it-matters","Why it matters",[11,1619,1620],{},"Without jitter, a large group of keys can expire close together and send a burst of requests to the source system. With jitter, those expirations are distributed over a longer period, which can smooth the load.",[11,1622,1623],{},"Jitter does not replace capacity planning, cache refresh strategies, or protection against individual hot keys, but it is a small technique that can help avoid synchronized expiration spikes.",[263,1625,1627],{"id":1626},"final-thoughts","Final thoughts",[11,1629,1630],{},"Choose a TTL based on how fresh the data needs to be, then consider adding a suitable amount of jitter when many keys are created together. Test the range against your workload so expiration behavior stays within your freshness requirements.",[658,1632,1633],{},"html pre.shiki code .szJfE, html code.shiki .szJfE{--shiki-default:#D73A49;--shiki-dark:#FF79C6}html pre.shiki code .scbbO, html code.shiki .scbbO{--shiki-default:#24292E;--shiki-dark:#F8F8F2}html pre.shiki code .sCLZk, html code.shiki .sCLZk{--shiki-default:#6F42C1;--shiki-dark:#50FA7B}html pre.shiki code .sMWOi, html code.shiki .sMWOi{--shiki-default:#032F62;--shiki-dark:#E9F284}html pre.shiki code .sEzAm, html code.shiki .sEzAm{--shiki-default:#032F62;--shiki-dark:#F1FA8C}html pre.shiki code .sDoOe, html code.shiki .sDoOe{--shiki-default:#24292E;--shiki-dark:#FF79C6}html pre.shiki code .soDru, html code.shiki .soDru{--shiki-default:#005CC5;--shiki-dark:#BD93F9}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 .sZIln, html code.shiki .sZIln{--shiki-default:#005CC5;--shiki-dark:#F8F8F2}",{"title":230,"searchDepth":231,"depth":231,"links":1635},[1636,1637,1638,1639,1640,1641],{"id":1405,"depth":333,"text":1406},{"id":1412,"depth":333,"text":1413},{"id":1475,"depth":333,"text":1476},{"id":1482,"depth":333,"text":1483},{"id":1616,"depth":333,"text":1617},{"id":1626,"depth":333,"text":1627},"18th Sep 2025","Learn how adding randomness to Redis expiration times can reduce synchronized cache expirations and protect downstream services from traffic spikes.","\u002Fblogs-img\u002Fblog7.png",{},"\u002Fblogs\u002Fredis-ttl-jitter-and-how-i-almost-crashed-a-server",{"title":1399,"description":1643},"blogs\u002F7. redis-ttl-jitter-and-how-i-almost-crashed-a-server",[1650,1651,1652],"redis","ttl","caching","cX3kBO65JzGOTT7IJM000SYq65u5xxyP3ymHuag97VA",{"id":1655,"title":1656,"alt":1657,"body":1658,"date":1657,"description":230,"extension":243,"image":1657,"meta":1888,"navigation":246,"ogImage":1657,"path":1889,"published":1890,"seo":1891,"stem":1902,"tags":1657,"__hash__":1903},"content\u002Fblogs\u002F8. float-make-my-dollar-float-away.md","[object Object]",null,{"type":8,"value":1659,"toc":1879},[1660,1664,1679,1683,1691,1697,1738,1744,1748,1765,1775,1779,1786,1823,1826,1830,1842,1845,1849,1869,1873,1876],[263,1661,1663],{"id":1662},"the-task","The task",[11,1665,1666,1667,1670,1671,1674,1675,1678],{},"I was asked to change a MySQL column from ",[289,1668,1669],{},"FLOAT"," to ",[289,1672,1673],{},"DECIMAL(10,2)",". It sounded like a simple ",[289,1676,1677],{},"ALTER TABLE",", but I needed to understand whether converting the column would preserve the original monetary values.",[263,1680,1682],{"id":1681},"why-float-can-be-a-problem","Why FLOAT can be a problem",[11,1684,1685,1687,1688,1690],{},[289,1686,1669],{}," is an approximate, binary floating-point type. Many decimal fractions cannot be represented exactly in binary, and a ",[289,1689,1669],{}," also has limited precision. This makes it a poor choice for values that require exact decimal arithmetic, such as money.",[11,1692,1693,1694,1696],{},"For example, a ",[289,1695,1669],{}," column may not preserve a large value to the cent:",[564,1698,1702],{"className":1699,"code":1700,"language":1701,"meta":230,"style":230},"language-sql shiki shiki-themes github-light dracula","CREATE TABLE money_float (\n  id INT AUTO_INCREMENT PRIMARY KEY,\n  amount FLOAT\n);\n\nINSERT INTO money_float (amount) VALUES (1000000.25), (123456789.99);\nSELECT * FROM money_float;\n","sql",[289,1703,1704,1709,1714,1719,1724,1728,1733],{"__ignoreMap":230},[572,1705,1706],{"class":574,"line":575},[572,1707,1708],{},"CREATE TABLE money_float (\n",[572,1710,1711],{"class":574,"line":231},[572,1712,1713],{},"  id INT AUTO_INCREMENT PRIMARY KEY,\n",[572,1715,1716],{"class":574,"line":333},[572,1717,1718],{},"  amount FLOAT\n",[572,1720,1721],{"class":574,"line":891},[572,1722,1723],{},");\n",[572,1725,1726],{"class":574,"line":897},[572,1727,894],{"emptyLinePlaceholder":246},[572,1729,1730],{"class":574,"line":903},[572,1731,1732],{},"INSERT INTO money_float (amount) VALUES (1000000.25), (123456789.99);\n",[572,1734,1735],{"class":574,"line":908},[572,1736,1737],{},"SELECT * FROM money_float;\n",[11,1739,1740,1741,1743],{},"The exact displayed result can depend on the MySQL version and client, but a single precision ",[289,1742,1669],{}," cannot represent every cent at that magnitude. Inspect and validate the actual values in your database before making a conversion.",[263,1745,1747],{"id":1746},"why-decimal-fractions-are-approximated","Why decimal fractions are approximated",[32,1749,1750,1755,1762],{},[35,1751,1752,1754],{},[289,1753,1669],{}," represents values using binary floating-point.",[35,1756,1757,1758,1761],{},"Fractions such as ",[289,1759,1760],{},"0.1"," have repeating binary expansions.",[35,1763,1764],{},"The stored value is therefore an approximation with limited precision.",[11,1766,1767,1768,1771,1772,1774],{},"This is a property of binary floating-point, not unique to MySQL. ",[289,1769,1770],{},"DOUBLE"," has more precision than ",[289,1773,1669],{},", but it is also approximate.",[263,1776,1778],{"id":1777},"when-to-use-decimal","When to use DECIMAL",[11,1780,1781,1782,1785],{},"MySQL's ",[289,1783,1784],{},"DECIMAL"," type stores fixed-point decimal values with a chosen precision and scale, making it suitable for exact decimal arithmetic within that range:",[564,1787,1789],{"className":1699,"code":1788,"language":1701,"meta":230,"style":230},"CREATE TABLE money_decimal (\n  id INT AUTO_INCREMENT PRIMARY KEY,\n  amount DECIMAL(15, 2)\n);\n\nINSERT INTO money_decimal (amount) VALUES (1000000.25), (123456789.99);\nSELECT * FROM money_decimal;\n",[289,1790,1791,1796,1800,1805,1809,1813,1818],{"__ignoreMap":230},[572,1792,1793],{"class":574,"line":575},[572,1794,1795],{},"CREATE TABLE money_decimal (\n",[572,1797,1798],{"class":574,"line":231},[572,1799,1713],{},[572,1801,1802],{"class":574,"line":333},[572,1803,1804],{},"  amount DECIMAL(15, 2)\n",[572,1806,1807],{"class":574,"line":891},[572,1808,1723],{},[572,1810,1811],{"class":574,"line":897},[572,1812,894],{"emptyLinePlaceholder":246},[572,1814,1815],{"class":574,"line":903},[572,1816,1817],{},"INSERT INTO money_decimal (amount) VALUES (1000000.25), (123456789.99);\n",[572,1819,1820],{"class":574,"line":908},[572,1821,1822],{},"SELECT * FROM money_decimal;\n",[11,1824,1825],{},"Choose precision and scale to fit the largest values and number of fractional digits your application needs.",[263,1827,1829],{"id":1828},"why-alter-may-not-recover-the-original-value","Why ALTER may not recover the original value",[11,1831,1832,1833,1835,1836,1838,1839,1841],{},"Changing a ",[289,1834,1669],{}," column to ",[289,1837,1784],{}," converts the value currently stored in the ",[289,1840,1669],{}," column. It cannot infer the original decimal value if precision was already lost during insertion or calculation.",[11,1843,1844],{},"Before migrating, back up the data, inspect representative values, and compare them with an authoritative source if one is available. Decide on an explicit rounding or correction strategy for values that need repair; do not assume the type conversion can restore lost information.",[263,1846,1848],{"id":1847},"lessons-learned","Lessons learned",[32,1850,1851,1859,1866],{},[35,1852,1853,1854,222,1856,1858],{},"Avoid ",[289,1855,1669],{},[289,1857,1770],{}," for monetary values that need exact decimal arithmetic.",[35,1860,1861,1862,1865],{},"Use ",[289,1863,1864],{},"DECIMAL(precision, scale)"," with a range that fits your domain.",[35,1867,1868],{},"Validate existing data before converting a column, because a type change cannot recover precision that is already gone.",[263,1870,1872],{"id":1871},"final-thought","Final thought",[11,1874,1875],{},"For amounts where every cent matters, choose a fixed-point type deliberately and verify how values are written, calculated, and migrated throughout the application.",[658,1877,1878],{},"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":230,"searchDepth":231,"depth":231,"links":1880},[1881,1882,1883,1884,1885,1886,1887],{"id":1662,"depth":333,"text":1663},{"id":1681,"depth":333,"text":1682},{"id":1746,"depth":333,"text":1747},{"id":1777,"depth":333,"text":1778},{"id":1828,"depth":333,"text":1829},{"id":1847,"depth":333,"text":1848},{"id":1871,"depth":333,"text":1872},{},"\u002Fblogs\u002Ffloat-make-my-dollar-float-away",false,{"title":1892,"description":230},{"FLOAT Made My Dollars Float Away":1893,"date":1894,"description":1895,"image":1896,"alt":1897,"ogImage":1896,"tags":1898,"published":246},"FLOAT vs. DECIMAL in MySQL 💸","19th Sep 2025","Learn why FLOAT can lose precision for monetary values in MySQL and what to check before converting a column to DECIMAL.","\u002Fblogs-img\u002Fblog8.png","Comparison of FLOAT and DECIMAL values in MySQL",[1899,1900,1901],"mysql","float","decimal","blogs\u002F8. float-make-my-dollar-float-away","TIP0DtdJ2K8Yx4vZ3EjoS8lcvGh6T_dOKb36k9EYn9U",{"id":1905,"title":1906,"alt":1907,"body":1908,"date":241,"description":2380,"extension":243,"image":2381,"meta":2382,"navigation":246,"ogImage":2381,"path":2383,"published":246,"seo":2384,"stem":2385,"tags":2386,"__hash__":2389},"content\u002Fblogs\u002F9. how-to-write-a-blog-post.md","How to Write and Publish a Blog Post on This Site","Blog writing and publishing guide",{"type":8,"value":1909,"toc":2369},[1910,1913,1917,1920,1940,1943,1947,1950,1988,1991,1995,1998,2001,2022,2025,2029,2036,2044,2047,2156,2159,2216,2222,2226,2229,2246,2252,2256,2285,2296,2300,2303,2332,2339,2343,2346,2363,2366],[11,1911,1912],{},"Writing a useful blog post starts with a clear idea and ends with a careful review. This guide explains how to prepare a post for this site, from choosing a topic to checking its Markdown frontmatter before publishing.",[18,1914,1916],{"id":1915},"_1-choose-one-useful-topic","1. Choose one useful topic",[11,1918,1919],{},"Start with a question, problem, lesson, or experience that a reader can learn from. Keep the post focused on one main point. Before drafting, write down:",[32,1921,1922,1928,1934],{},[35,1923,1924,1927],{},[38,1925,1926],{},"Who the post is for:"," describe the reader and what they already know.",[35,1929,1930,1933],{},[38,1931,1932],{},"What they will learn:"," state the practical outcome in one sentence.",[35,1935,1936,1939],{},[38,1937,1938],{},"What evidence you can share:"," gather examples, steps, code, screenshots, or sources that support the explanation.",[11,1941,1942],{},"If the topic is broad, narrow it. A post about one specific error and its fix is usually more useful than a general overview of an entire technology.",[18,1944,1946],{"id":1945},"_2-make-a-simple-outline","2. Make a simple outline",[11,1948,1949],{},"Organize the explanation in the order a reader needs it. A tutorial might use this structure:",[77,1951,1952,1958,1964,1970,1976,1982],{},[35,1953,1954,1957],{},[38,1955,1956],{},"Context:"," explain the problem and when it happens.",[35,1959,1960,1963],{},[38,1961,1962],{},"Prerequisites:"," list anything the reader needs before starting.",[35,1965,1966,1969],{},[38,1967,1968],{},"Steps:"," show the solution in a clear, numbered order.",[35,1971,1972,1975],{},[38,1973,1974],{},"Explanation:"," describe why the important steps work.",[35,1977,1978,1981],{},[38,1979,1980],{},"Verification:"," tell the reader how to confirm the result.",[35,1983,1984,1987],{},[38,1985,1986],{},"Caveats and takeaway:"," mention relevant limits and summarize the main lesson.",[11,1989,1990],{},"For an experience report, explain what happened, what you tried, what changed, and what you learned. Choose headings that describe the section instead of relying on generic headings such as “Part 1.”",[18,1992,1994],{"id":1993},"_3-write-for-clarity","3. Write for clarity",[11,1996,1997],{},"Use direct language and short paragraphs. Introduce technical terms before relying on them, and prefer concrete examples over abstract claims. Include only details that help the reader understand or apply the point.",[11,1999,2000],{},"When sharing code, use a fenced block with the correct language label:",[564,2002,2004],{"className":808,"code":2003,"language":810,"meta":230,"style":230},"const greeting = 'Hello, reader'\n",[289,2005,2006],{"__ignoreMap":230},[572,2007,2008,2010,2013,2015,2017,2020],{"class":574,"line":575},[572,2009,965],{"class":817},[572,2011,2012],{"class":968}," greeting",[572,2014,972],{"class":817},[572,2016,1294],{"class":602},[572,2018,2019],{"class":605},"Hello, reader",[572,2021,1322],{"class":602},[11,2023,2024],{},"Explain what a meaningful code example demonstrates, and identify any assumptions. For commands or configuration, show the relevant context and avoid presenting an unverified snippet as a complete solution. Link to primary documentation when readers may need current or deeper details.",[18,2026,2028],{"id":2027},"_4-add-the-post-to-the-repository","4. Add the post to the repository",[11,2030,2031,2032,2035],{},"Create a descriptive, URL-friendly Markdown filename under ",[289,2033,2034],{},"content\u002Fblogs\u002F",", for example:",[564,2037,2042],{"className":2038,"code":2040,"language":2041,"meta":230},[2039],"language-text","content\u002Fblogs\u002F9. how-to-write-a-blog-post.md\n","text",[289,2043,2040],{"__ignoreMap":230},[11,2045,2046],{},"The filename contributes to the post URL, so keep it specific and avoid spaces when choosing a new filename. Start the file with all required frontmatter fields:",[564,2048,2052],{"className":2049,"code":2050,"language":2051,"meta":230,"style":230},"language-yaml shiki shiki-themes github-light dracula","---\ntitle: 'A practical guide to a focused topic'\ndate: 29th Sep 2026\ndescription: A concise, complete summary of what readers will learn.\nimage: \u002Fblogs-img\u002Fblog9.png\nalt: A meaningful description of the post image\nogImage: \u002Fblogs-img\u002Fblog9.png\ntags: [topic, technology]\npublished: true\n---\n","yaml",[289,2053,2054,2059,2074,2084,2094,2104,2114,2123,2142,2152],{"__ignoreMap":230},[572,2055,2056],{"class":574,"line":575},[572,2057,878],{"class":2058},"sgEbo",[572,2060,2061,2065,2067,2069,2072],{"class":574,"line":231},[572,2062,2064],{"class":2063},"sW4bl","title",[572,2066,596],{"class":595},[572,2068,1294],{"class":602},[572,2070,2071],{"class":605},"A practical guide to a focused topic",[572,2073,1322],{"class":602},[572,2075,2076,2079,2081],{"class":574,"line":333},[572,2077,2078],{"class":2063},"date",[572,2080,596],{"class":595},[572,2082,2083],{"class":605}," 29th Sep 2026\n",[572,2085,2086,2089,2091],{"class":574,"line":891},[572,2087,2088],{"class":2063},"description",[572,2090,596],{"class":595},[572,2092,2093],{"class":605}," A concise, complete summary of what readers will learn.\n",[572,2095,2096,2099,2101],{"class":574,"line":897},[572,2097,2098],{"class":2063},"image",[572,2100,596],{"class":595},[572,2102,2103],{"class":605}," \u002Fblogs-img\u002Fblog9.png\n",[572,2105,2106,2109,2111],{"class":574,"line":903},[572,2107,2108],{"class":2063},"alt",[572,2110,596],{"class":595},[572,2112,2113],{"class":605}," A meaningful description of the post image\n",[572,2115,2116,2119,2121],{"class":574,"line":908},[572,2117,2118],{"class":2063},"ogImage",[572,2120,596],{"class":595},[572,2122,2103],{"class":605},[572,2124,2125,2128,2130,2132,2135,2137,2140],{"class":574,"line":1058},[572,2126,2127],{"class":2063},"tags",[572,2129,596],{"class":595},[572,2131,599],{"class":578},[572,2133,2134],{"class":605},"topic",[572,2136,611],{"class":578},[572,2138,2139],{"class":605},"technology",[572,2141,648],{"class":578},[572,2143,2144,2147,2149],{"class":574,"line":1084},[572,2145,2146],{"class":2063},"published",[572,2148,596],{"class":595},[572,2150,2151],{"class":1310}," true\n",[572,2153,2154],{"class":574,"line":1094},[572,2155,878],{"class":2058},[11,2157,2158],{},"Use these fields consistently:",[32,2160,2161,2166,2173,2178,2190,2195,2202,2207],{},[35,2162,2163,2165],{},[289,2164,2064],{}," is the post title shown to readers.",[35,2167,2168,2170,2171,228],{},[289,2169,2078],{}," follows the site's human-readable style, such as ",[289,2172,241],{},[35,2174,2175,2177],{},[289,2176,2088],{}," is a short, complete summary kept on one line.",[35,2179,2180,2182,2183,2186,2187,228],{},[289,2181,2098],{}," is the main image URL, rooted under ",[289,2184,2185],{},"\u002F"," and backed by a file in ",[289,2188,2189],{},"public\u002F",[35,2191,2192,2194],{},[289,2193,2108],{}," describes the image for readers using assistive technology. Describe the image, not just the post topic.",[35,2196,2197,2199,2200,228],{},[289,2198,2118],{}," is the social sharing image URL; it can use the same image as ",[289,2201,2098],{},[35,2203,2204,2206],{},[289,2205,2127],{}," is a YAML list of relevant, concise categories.",[35,2208,2209,2211,2212,2215],{},[289,2210,2146],{}," controls whether the post is public. Set it to ",[289,2213,2214],{},"false"," while the post is a draft.",[11,2217,2218,2219,2221],{},"Keep the metadata accurate. Do not claim an image exists unless the corresponding file is present in ",[289,2220,2189],{},". If you do not have a suitable image yet, prepare one before publishing.",[263,2223,2225],{"id":2224},"important-quote-titles-with-colons","Important: quote titles with colons",[11,2227,2228],{},"YAML treats a colon followed by a space as mapping syntax. Always quote a title that contains a colon, for example:",[564,2230,2232],{"className":2049,"code":2231,"language":2051,"meta":230,"style":230},"title: 'Durable Execution: The Problem It Solves and How Temporal Works'\n",[289,2233,2234],{"__ignoreMap":230},[572,2235,2236,2238,2240,2242,2244],{"class":574,"line":575},[572,2237,2064],{"class":2063},[572,2239,596],{"class":595},[572,2241,1294],{"class":602},[572,2243,5],{"class":605},[572,2245,1322],{"class":602},[11,2247,2248,2249,2251],{},"If you leave this value unquoted, the parser may treat it as an object. Nuxt Content can then store the page title as ",[289,2250,1656],{},", which appears literally in the page heading and metadata. After adding a title with punctuation, inspect the parsed content or generated page to confirm it remains the intended string.",[263,2253,2255],{"id":2254},"important-use-nuxt-contents-actual-field-mapping","Important: use Nuxt Content's actual field mapping",[11,2257,2258,2259,222,2262,2265,2266,611,2268,611,2270,611,2272,611,2274,2276,2277,2279,2280,2282,2283,228],{},"In this repository, Nuxt Content query results put the Markdown title and description in ",[289,2260,2261],{},"seo.title",[289,2263,2264],{},"seo.description",". Other frontmatter fields—",[289,2267,2078],{},[289,2269,2098],{},[289,2271,2108],{},[289,2273,2118],{},[289,2275,2127],{},", and ",[289,2278,2146],{},"—are top-level. The built-in top-level ",[289,2281,2064],{}," can be object-valued, so passing it directly to Vue can render as ",[289,2284,1656],{},[11,2286,2287,2288,2291,2292,2295],{},"When adding or changing blog rendering code, use the shared ",[289,2289,2290],{},"toBlogCardPost"," helper in ",[289,2293,2294],{},"app\u002Futils\u002Fblog.ts"," to map a content result to display fields. Use it on every page that displays a post, including recent posts and the blog detail page. Avoid passing raw query values directly to text, SEO metadata, or OG image components. After the change, inspect the rendered title, description, date, and image and confirm no object values or fallback content appear.",[18,2297,2299],{"id":2298},"_5-review-before-publishing","5. Review before publishing",[11,2301,2302],{},"Read the post once for meaning and once for details. Check that:",[32,2304,2305,2308,2311,2314,2317,2320,2326],{},[35,2306,2307],{},"The title, opening, headings, and conclusion all support the same main point.",[35,2309,2310],{},"Every step is actionable and appears in the right order.",[35,2312,2313],{},"Code, commands, dates, and technical claims are accurate and explained.",[35,2315,2316],{},"Markdown fences are closed, links work, and lists render as intended.",[35,2318,2319],{},"The frontmatter includes every required field, with valid YAML values.",[35,2321,2322,2323,2325],{},"Image URLs point to files in ",[289,2324,2189],{},", and the alt text is meaningful.",[35,2327,2328,2329,2331],{},"The description is complete and ",[289,2330,2146],{}," reflects the intended status.",[11,2333,2334,2335,2338],{},"For a Markdown-only change, review the frontmatter and links. If the change affects content structure or rendering, run the site build as well. Keep drafts marked ",[289,2336,2337],{},"published: false"," until they are ready for readers.",[18,2340,2342],{"id":2341},"a-reusable-checklist","A reusable checklist",[11,2344,2345],{},"Before publishing, make sure you can answer “yes” to each question:",[32,2347,2348,2351,2354,2357,2360],{},[35,2349,2350],{},"Does the post solve one clear problem or teach one focused lesson?",[35,2352,2353],{},"Can a reader follow the explanation without guessing at missing steps?",[35,2355,2356],{},"Are examples and claims accurate, with sources where needed?",[35,2358,2359],{},"Does the post have complete metadata and a real, accessible image?",[35,2361,2362],{},"Have you reviewed the rendered Markdown and publication status?",[11,2364,2365],{},"A well-written post respects the reader's time: it gives enough context to understand the topic, enough detail to act, and a clear way to know what to do next.",[658,2367,2368],{},"html pre.shiki code .szJfE, html code.shiki .szJfE{--shiki-default:#D73A49;--shiki-dark:#FF79C6}html pre.shiki code .sZIln, html code.shiki .sZIln{--shiki-default:#005CC5;--shiki-dark:#F8F8F2}html pre.shiki code .sMWOi, html code.shiki .sMWOi{--shiki-default:#032F62;--shiki-dark:#E9F284}html pre.shiki code .sEzAm, html code.shiki .sEzAm{--shiki-default:#032F62;--shiki-dark:#F1FA8C}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 .sgEbo, html code.shiki .sgEbo{--shiki-default:#6F42C1;--shiki-dark:#F8F8F2}html pre.shiki code .sW4bl, html code.shiki .sW4bl{--shiki-default:#22863A;--shiki-dark:#8BE9FD}html pre.shiki code .sDoOe, html code.shiki .sDoOe{--shiki-default:#24292E;--shiki-dark:#FF79C6}html pre.shiki code .scbbO, html code.shiki .scbbO{--shiki-default:#24292E;--shiki-dark:#F8F8F2}html pre.shiki code .soDru, html code.shiki .soDru{--shiki-default:#005CC5;--shiki-dark:#BD93F9}",{"title":230,"searchDepth":231,"depth":231,"links":2370},[2371,2372,2373,2374,2378,2379],{"id":1915,"depth":231,"text":1916},{"id":1945,"depth":231,"text":1946},{"id":1993,"depth":231,"text":1994},{"id":2027,"depth":231,"text":2028,"children":2375},[2376,2377],{"id":2224,"depth":333,"text":2225},{"id":2254,"depth":333,"text":2255},{"id":2298,"depth":231,"text":2299},{"id":2341,"depth":231,"text":2342},"Follow this practical guide to plan, write, format, and publish a blog post in this Nuxt site's content\u002Fblogs directory.","\u002Fblogs-img\u002Fblog9.png",{},"\u002Fblogs\u002Fhow-to-write-a-blog-post",{"title":1906,"description":2380},"blogs\u002F9. how-to-write-a-blog-post",[2387,2388,674],"writing","blogging","L5eP-ZCjPR4PO2uyjDu6fD1o7gZZlTEFDYcXmcEQtpc",1790657043476]