[{"data":1,"prerenderedAt":899},["ShallowReactive",2],{"i-base:github-white":3,"i-base:linkedin":9,"i-base:x":11,"i-base:instagram":15,"store-add-dynamic-features-to-static-sites-with-cloudflare-kv-and-workers":17,"i-base:like":894,"i-base:share":897},{"left":4,"top":4,"width":5,"height":6,"rotate":4,"vFlip":7,"hFlip":7,"body":8},0,25,24,false,"\u003Cdefs>\u003CclipPath id=\"clip0_128_103\">\n\u003Crect width=\"23.8858\" height=\"23.8858\" fill=\"white\" transform=\"translate(0.771423)\"/>\n\u003C/clipPath>\u003C/defs>\u003Cg fill=\"none\">\u003Cg clip-path=\"url(#clip0_128_103)\">\n\u003Cpath fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M12.7143 0.000976562C6.11914 0.000976562 0.771515 5.48326 0.771515 12.2463C0.771515 17.6564 4.19368 22.2465 8.93851 23.8656C9.53561 23.9791 9.7549 23.6 9.7549 23.2767C9.7549 22.9847 9.74382 22.02 9.73844 20.9967C6.41595 21.7376 5.71507 19.5521 5.71507 19.5521C5.1716 18.1369 4.38892 17.7604 4.38892 17.7604C3.30515 17.0004 4.47056 17.0158 4.47056 17.0158C5.66982 17.1024 6.30109 18.2779 6.30109 18.2779C7.3665 20.1499 9.09515 19.6087 9.77673 19.2958C9.884 18.5045 10.1933 17.964 10.5349 17.6583C7.88228 17.3491 5.09392 16.2989 5.09392 11.6068C5.09392 10.2701 5.56033 9.17754 6.32419 8.3202C6.20031 8.01165 5.79148 6.76611 6.44016 5.07949C6.44016 5.07949 7.44292 4.75018 9.72468 6.3346C10.6776 6.06337 11.6992 5.92743 12.7141 5.92256C13.7291 5.92743 14.7516 6.06337 15.706 6.3346C17.9855 4.75035 18.987 5.07933 18.987 5.07933C19.6369 6.76579 19.2283 8.01133 19.1041 8.31971C19.8698 9.17722 20.3331 10.2696 20.3331 11.6063C20.3331 16.3099 17.5393 17.3452 14.8801 17.6484C15.3084 18.0287 15.6901 18.7738 15.6901 19.9163C15.6901 21.5547 15.6765 22.8736 15.6765 23.2767C15.6765 23.6028 15.8912 23.9843 16.4965 23.8643C21.2398 22.2434 24.6572 17.6549 24.6572 12.2465C24.6572 5.48326 19.3094 0.000976562 12.7143 0.000976562Z\" fill=\"#EDEDED\"/>\n\u003Cpath d=\"M5.29598 17.581C5.26955 17.642 5.17621 17.6605 5.09125 17.6184C5.00423 17.5784 4.95597 17.4954 4.98398 17.4344C5.00976 17.3719 5.10311 17.3546 5.18966 17.3963C5.27636 17.4363 5.32572 17.52 5.29598 17.581ZM5.77838 18.1345C5.72142 18.1887 5.60988 18.1637 5.53472 18.0781C5.45625 17.9926 5.44185 17.8782 5.4996 17.8234C5.55814 17.7694 5.66636 17.7947 5.74436 17.8802C5.82268 17.9665 5.83802 18.0797 5.77838 18.1345ZM6.24923 18.8402C6.17597 18.8926 6.0562 18.8438 5.98216 18.7348C5.90891 18.6258 5.90891 18.4952 5.98374 18.4428C6.0581 18.3905 6.17597 18.4379 6.25113 18.5456C6.32391 18.6564 6.32391 18.7869 6.24923 18.8402ZM6.89586 19.5217C6.83035 19.5957 6.69097 19.5757 6.58892 19.4747C6.48449 19.376 6.45538 19.2359 6.52088 19.1619C6.58733 19.0878 6.72751 19.1084 6.83035 19.209C6.93399 19.3073 6.96547 19.4484 6.89586 19.5217ZM7.78582 19.9171C7.75671 20.0128 7.62286 20.0566 7.48743 20.0155C7.35215 19.9737 7.26371 19.8614 7.29124 19.7646C7.31908 19.6681 7.4542 19.6226 7.59027 19.6663C7.72522 19.708 7.81398 19.8196 7.78582 19.9171ZM8.7628 19.9901C8.76597 20.0911 8.65142 20.175 8.50966 20.1766C8.36663 20.1799 8.25097 20.0981 8.24939 19.9988C8.24939 19.8966 8.36173 19.8139 8.50412 19.8115C8.64651 19.8082 8.7628 19.8898 8.7628 19.9899M9.67254 19.8319C9.68947 19.9302 9.5909 20.0314 9.44978 20.0584C9.31118 20.0846 9.18287 20.0236 9.1653 19.9261C9.1479 19.8251 9.24837 19.724 9.38681 19.6979C9.52809 19.6726 9.65451 19.7318 9.67254 19.8319Z\" fill=\"#EDEDED\"/>\n\u003C/g>\u003C/g>",{"left":4,"top":4,"width":5,"height":6,"rotate":4,"vFlip":7,"hFlip":7,"body":10},"\u003Cg fill=\"none\">\u003Cpath d=\"M7.01767 4.80176C6.03367 4.80176 5.38492 5.47376 5.38492 6.36176C5.38492 7.22576 6.00929 7.92101 6.96929 7.92101C8.00129 7.92101 8.64929 7.22576 8.62529 6.36176C8.62529 5.47376 8.00167 4.80176 7.01767 4.80176ZM16.2329 8.92976C14.5769 8.92976 13.5693 9.88938 13.1613 10.5614H13.1137L12.9693 9.14576H10.3057C10.3297 10.0578 10.3773 11.1138 10.3773 12.3618V19.201H13.4489V13.417C13.4489 13.129 13.4729 12.8414 13.5449 12.6254C13.7849 12.0494 14.2893 11.449 15.1293 11.449C16.2573 11.449 16.6893 12.3374 16.6893 13.6334V19.201H19.7853V13.2738C19.7853 10.2978 18.2489 8.92976 16.2329 8.92976ZM5.45767 9.14576V19.201H8.52929V9.14576H5.45767Z\" fill=\"#EDEDED\"/>\u003C/g>",{"left":4,"top":4,"width":12,"height":13,"rotate":4,"vFlip":7,"hFlip":7,"body":14},20,19,"\u003Cg fill=\"none\">\u003Cpath d=\"M11.7011 8.12223L18.531 0.183105H16.9125L10.9823 7.07673L6.24563 0.183105H0.782257L7.94476 10.6074L0.782257 18.9331H2.40076L8.66326 11.6529L13.6658 18.9331H19.1291L11.7004 8.12223H11.7011ZM9.48413 10.6992L8.75851 9.66123L2.98388 1.40148H5.47013L10.1303 8.06711L10.8559 9.10511L16.9133 17.7699H14.427L9.48413 10.6992Z\" fill=\"#EDEDED\"/>\u003C/g>",{"left":4,"top":4,"width":5,"height":6,"rotate":4,"vFlip":7,"hFlip":7,"body":16},"\u003Cdefs>\u003CclipPath id=\"clip0_128_113\">\n\u003Crect width=\"23.5714\" height=\"23.5714\" fill=\"white\" transform=\"translate(0.657288)\"/>\n\u003C/clipPath>\u003C/defs>\u003Cg fill=\"none\">\u003Cg clip-path=\"url(#clip0_128_113)\">\n\u003Cpath d=\"M7.56183 0.0825165C6.30783 0.141641 5.4515 0.341802 4.70281 0.635856C3.9281 0.937865 3.27134 1.343 2.61792 1.99878C1.9646 2.65455 1.56212 3.3117 1.26237 4.08779C0.972243 4.83795 0.775618 5.69507 0.720225 6.94976C0.664832 8.20445 0.652555 8.60781 0.658743 11.8084C0.664832 15.0088 0.678975 15.41 0.73977 16.6674C0.79968 17.9211 0.999055 18.7772 1.29321 19.5261C1.59571 20.3009 2.00035 20.9574 2.65642 21.611C3.31239 22.2646 3.96906 22.6661 4.74691 22.9663C5.49648 23.2561 6.3538 23.4536 7.60829 23.5085C8.86278 23.5635 9.26654 23.5763 12.4662 23.5701C15.6658 23.564 16.0687 23.5497 17.3256 23.4901C18.5828 23.4305 19.4343 23.2297 20.1834 22.9369C20.9583 22.6338 21.6152 22.2297 22.2683 21.5736C22.9215 20.9173 23.3237 20.2597 23.6232 19.4832C23.9136 18.7336 24.1109 17.8764 24.1653 16.6228C24.2203 15.3648 24.2333 14.9632 24.2272 11.7631C24.221 8.56303 24.2066 8.16182 24.147 6.90497C24.0874 5.64812 23.8877 4.79464 23.5937 4.04527C23.2908 3.27045 22.8866 2.61448 22.2309 1.96037C21.5751 1.30627 20.9169 0.904374 20.1408 0.605508C19.3907 0.315284 18.5339 0.117579 17.2794 0.0633647C16.025 0.00915041 15.6212 -0.00489422 12.4204 0.00139149C9.21959 0.00748078 8.81888 0.0212308 7.56183 0.0825165ZM7.69953 21.3882C6.55042 21.3382 5.92647 21.1473 5.51063 20.9875C4.96004 20.7754 4.56777 20.5189 4.1534 20.1085C3.73894 19.6982 3.48447 19.3045 3.26947 18.7551C3.10801 18.3393 2.91355 17.716 2.85982 16.5669C2.80139 15.325 2.78911 14.9521 2.78223 11.8055C2.77536 8.65898 2.78744 8.28645 2.84185 7.04404C2.89096 5.89592 3.08306 5.27128 3.24256 4.85563C3.45471 4.30436 3.71026 3.91278 4.12158 3.4987C4.5329 3.08453 4.92537 2.82947 5.47527 2.61448C5.89072 2.45233 6.51389 2.25953 7.6625 2.20483C8.9054 2.1459 9.27783 2.13411 12.4239 2.12724C15.57 2.12036 15.9434 2.13215 17.1868 2.18695C18.335 2.23685 18.9599 2.42709 19.375 2.58767C19.9258 2.79981 20.3179 3.05458 20.732 3.46669C21.1461 3.8786 21.4014 4.26969 21.6164 4.82077C21.7787 5.23494 21.9716 5.85791 22.0258 7.00731C22.085 8.25021 22.0984 8.62294 22.104 11.7687C22.1097 14.9145 22.0986 15.2882 22.0441 16.5302C21.994 17.6793 21.8035 18.3034 21.6434 18.7198C21.4313 19.2702 21.1756 19.6626 20.764 20.0765C20.3525 20.4905 19.9605 20.7454 19.4103 20.9604C18.9954 21.1224 18.3715 21.3157 17.2239 21.3704C15.9809 21.4288 15.6084 21.4411 12.4612 21.448C9.31388 21.4548 8.94243 21.4421 7.69953 21.3882ZM17.3075 5.48666C17.308 5.7664 17.3914 6.03973 17.5472 6.27206C17.7031 6.50439 17.9243 6.68529 18.1829 6.79189C18.4416 6.89848 18.726 6.92598 19.0003 6.8709C19.2745 6.81583 19.5263 6.68065 19.7237 6.48247C19.9212 6.28429 20.0554 6.03201 20.1095 5.75754C20.1635 5.48307 20.1349 5.19873 20.0274 4.94049C19.9198 4.68225 19.7381 4.46172 19.5052 4.30677C19.2723 4.15183 18.9986 4.06943 18.7189 4.07002C18.3439 4.0708 17.9846 4.22047 17.7199 4.48613C17.4552 4.75178 17.3069 5.11167 17.3075 5.48666ZM6.39151 11.7975C6.39809 15.1399 9.11264 17.8433 12.4543 17.837C15.7961 17.8306 18.5013 15.1164 18.495 11.7739C18.4887 8.43152 15.7735 5.72738 12.4313 5.73396C9.08906 5.74054 6.38522 8.45548 6.39151 11.7975ZM8.51441 11.7933C8.51288 11.0163 8.74178 10.2563 9.17218 9.60941C9.60258 8.96251 10.2151 8.45776 10.9324 8.159C11.6497 7.86024 12.4394 7.78087 13.2018 7.93095C13.9641 8.08102 14.6649 8.45378 15.2154 9.00211C15.7659 9.55043 16.1414 10.2497 16.2945 11.0114C16.4476 11.7732 16.3714 12.5633 16.0755 13.2817C15.7796 14.0001 15.2773 14.6147 14.6321 15.0477C13.9869 15.4806 13.2278 15.7126 12.4508 15.7141C11.9349 15.7152 11.4238 15.6146 10.9468 15.4182C10.4697 15.2217 10.036 14.9332 9.67047 14.5691C9.30493 14.205 9.01469 13.7725 8.81633 13.2962C8.61797 12.8199 8.51538 12.3092 8.51441 11.7933Z\" fill=\"#EDEDED\"/>\n\u003C/g>\u003C/g>",{"story":18,"related":462},{"data":19,"headers":440},{"story":20,"cv":437,"rels":438,"links":439},{"name":21,"created_at":22,"published_at":23,"updated_at":24,"id":25,"uuid":26,"content":27,"slug":428,"full_slug":429,"sort_by_date":41,"position":430,"tag_list":431,"is_startpage":7,"parent_id":432,"meta_data":41,"group_id":433,"first_published_at":434,"release_id":41,"lang":435,"path":41,"alternates":436,"default_full_slug":41,"translated_slugs":41},"Add Dynamic Features to Static Sites with Cloudflare KV and Workers","2025-06-29T21:23:54.444Z","2026-04-13T16:36:56.728Z","2026-04-13T16:36:56.745Z",63662630706919,"cdd41db7-41ba-4140-ac8f-53565868104a",{"_uid":28,"tags":29,"intro":33,"title":21,"author":34,"content":35,"component":424,"cover_image":425,"publish_date":226},"bfccf71b-28fe-4ba6-99a8-1e751812082c",[30,31,32],"how-to","tools","tutorial","Learn how to add dynamic behaviour to static sites with Cloudflare Workers and KV by building a lightweight page view counter that runs entirely at the edge.","37991366-dfa5-45d6-bb0d-259aa79b74d3",{"type":36,"content":37},"doc",[38,46,51,56,64,69,101,106,113,118,160,165,172,179,184,189,194,199,211,217,228,239,245,254,264,270,275,280,302,307,312,321,326,331,342,347,356,361,372,379,384,414,419],{"type":39,"attrs":40,"content":42},"paragraph",{"textAlign":41},null,[43],{"text":44,"type":45},"Static sites are fast, secure, and easy to deploy. However, they’ve traditionally lacked dynamic capabilities, often relying on external APIs or backend infrastructure. Cloudflare KV offers a compelling middle ground: a globally distributed key-value store that enables lightweight, persistent state to be directly stored at the edge.","text",{"type":39,"attrs":47,"content":48},{"textAlign":41},[49],{"text":50,"type":45},"By combining KV with Cloudflare Workers, developers can introduce dynamic features such as page view counters, feedback widgets, poll voting, and feature toggles to static or JAMstack applications. All of this is possible without requiring a database or server.",{"type":39,"attrs":52,"content":53},{"textAlign":41},[54],{"text":55,"type":45},"This blog post demonstrates how to build a dynamic page view counter using Cloudflare Workers and KV. The pattern shown here can be adapted for other dynamic features in static or serverless web applications.",{"type":39,"attrs":57,"content":58},{"textAlign":41},[59],{"text":60,"type":45,"marks":61},"What You’ll Build",[62],{"type":63},"bold",{"type":39,"attrs":65,"content":66},{"textAlign":41},[67],{"text":68,"type":45},"The goal is to create a lightweight page view counter that runs entirely at the edge. Each time a user visits a page:",{"type":70,"content":71},"bullet_list",[72,80,87,94],{"type":73,"content":74},"list_item",[75],{"type":39,"attrs":76,"content":77},{"textAlign":41},[78],{"text":79,"type":45},"The Worker receives the request and extracts the path.",{"type":73,"content":81},[82],{"type":39,"attrs":83,"content":84},{"textAlign":41},[85],{"text":86,"type":45},"A value associated with that path is fetched from Cloudflare KV.",{"type":73,"content":88},[89],{"type":39,"attrs":90,"content":91},{"textAlign":41},[92],{"text":93,"type":45},"The view count is incremented and stored again.",{"type":73,"content":95},[96],{"type":39,"attrs":97,"content":98},{"textAlign":41},[99],{"text":100,"type":45},"The updated count is returned in the response.",{"type":39,"attrs":102,"content":103},{"textAlign":41},[104],{"text":105,"type":45},"This dynamic logic runs on Cloudflare’s global network without requiring a traditional backend or database.",{"type":39,"attrs":107,"content":108},{"textAlign":41},[109],{"text":110,"type":45,"marks":111},"What You’ll Need",[112],{"type":63},{"type":39,"attrs":114,"content":115},{"textAlign":41},[116],{"text":117,"type":45},"Before getting started, ensure the following tools and services are available:",{"type":70,"content":119},[120,135,142,149],{"type":73,"content":121},[122],{"type":39,"attrs":123,"content":124},{"textAlign":41},[125,127],{"text":126,"type":45},"A ",{"text":128,"type":45,"marks":129},"Cloudflare account",[130],{"type":131,"attrs":132},"link",{"href":133,"uuid":41,"anchor":41,"target":41,"linktype":134},"https://dash.cloudflare.com/","url",{"type":73,"content":136},[137],{"type":39,"attrs":138,"content":139},{"textAlign":41},[140],{"text":141,"type":45},"Node.js installed on your machine",{"type":73,"content":143},[144],{"type":39,"attrs":145,"content":146},{"textAlign":41},[147],{"text":148,"type":45},"Access to a terminal",{"type":73,"content":150},[151],{"type":39,"attrs":152,"content":153},{"textAlign":41},[154],{"text":155,"type":45,"marks":156},"Wrangler",[157],{"type":131,"attrs":158},{"href":159,"uuid":41,"anchor":41,"target":41,"linktype":134},"https://developers.cloudflare.com/workers/wrangler/",{"type":39,"attrs":161,"content":162},{"textAlign":41},[163],{"text":164,"type":45},"Install Wrangler, Cloudflare’s CLI tool for building and deploying Workers, as a local development dependency:",{"type":166,"attrs":167,"content":169},"code_block",{"class":168},"language-bash",[170],{"text":171,"type":45},"npm install --save-dev wrangler@latest",{"type":39,"attrs":173,"content":174},{"textAlign":41},[175],{"text":176,"type":45,"marks":177},"Project Setup",[178],{"type":63},{"type":39,"attrs":180,"content":181},{"textAlign":41},[182],{"text":183,"type":45},"Create a new folder and initialise your project:",{"type":166,"attrs":185,"content":186},{"class":168},[187],{"text":188,"type":45},"mkdir page-view-counter\ncd page-view-counter\nnpm init -y\nnpm install --save-dev wrangler@latest",{"type":39,"attrs":190,"content":191},{"textAlign":41},[192],{"text":193,"type":45},"Install TypeScript and Cloudflare Worker types:",{"type":166,"attrs":195,"content":196},{"class":168},[197],{"text":198,"type":45},"npm install --save-dev typescript @cloudflare/workers-types",{"type":39,"attrs":200,"content":201},{"textAlign":41},[202,204,209],{"text":203,"type":45},"Create a minimal ",{"text":205,"type":45,"marks":206},"tsconfig.json",[207],{"type":208},"code",{"text":210,"type":45},":",{"type":166,"attrs":212,"content":214},{"class":213},"language-json",[215],{"text":216,"type":45},"{\n  \"compilerOptions\": {\n    \"target\": \"ES2022\",\n    \"module\": \"ESNext\",\n    \"lib\": [\"ES2022\", \"WebWorker\"],\n    \"moduleResolution\": \"Node\",\n    \"types\": [\"@cloudflare/workers-types\"],\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"skipLibCheck\": true\n  },\n  \"include\": [\"src\"]\n}",{"type":39,"attrs":218,"content":219},{"textAlign":41},[220],{"text":221,"type":45,"marks":222},"Worker Logic",[223,227],{"type":224,"attrs":225},"textStyle",{"color":226},"",{"type":63},{"type":39,"attrs":229,"content":230},{"textAlign":41},[231,233,237],{"text":232,"type":45},"Create a ",{"text":234,"type":45,"marks":235},"src/index.ts",[236],{"type":208},{"text":238,"type":45}," file with the following content:",{"type":166,"attrs":240,"content":242},{"class":241},"language-typescript",[243],{"text":244,"type":45},"export default {\n  async fetch(request: Request, env: Env): Promise\u003CResponse> {\n    const url = new URL(request.url);\n    const key = url.pathname;\n\n    const current = await env.METRICS.get(key);\n    const views = current ? parseInt(current) + 1 : 1;\n\n    await env.METRICS.put(key, views.toString());\n\n    return new Response(`This page (${key}) has been viewed ${views} times.`, {\n      headers: { 'Content-Type': 'text/plain' },\n    });\n  },\n};\n\ninterface Env {\n  METRICS: KVNamespace;\n}",{"type":39,"attrs":246,"content":247},{"textAlign":41},[248],{"text":249,"type":45,"marks":250},"Configure Wrangler",[251,253],{"type":224,"attrs":252},{"color":226},{"type":63},{"type":39,"attrs":255,"content":256},{"textAlign":41},[257,258,262],{"text":232,"type":45},{"text":259,"type":45,"marks":260},"wrangler.toml",[261],{"type":208},{"text":263,"type":45}," file in the root of the project:",{"type":166,"attrs":265,"content":267},{"class":266},"language-plaintext",[268],{"text":269,"type":45},"name = \"page-view-counter\"\nmain = \"src/index.ts\"\ncompatibility_date = \"2025-06-29\"",{"type":39,"attrs":271,"content":272},{"textAlign":41},[273],{"text":274,"type":45},"Next, create two KV namespaces—one for production and one for preview:",{"type":166,"attrs":276,"content":277},{"class":168},[278],{"text":279,"type":45},"npx wrangler kv namespace create \"METRICS\"\nnpx wrangler kv namespace create \"METRICS\" --preview",{"type":39,"attrs":281,"content":282},{"textAlign":41},[283,285,289,291,295,297,300],{"text":284,"type":45},"Copy the ",{"text":286,"type":45,"marks":287},"id",[288],{"type":208},{"text":290,"type":45}," and ",{"text":292,"type":45,"marks":293},"preview_id",[294],{"type":208},{"text":296,"type":45}," into your ",{"text":259,"type":45,"marks":298},[299],{"type":208},{"text":301,"type":45}," like so:",{"type":166,"attrs":303,"content":304},{"class":266},[305],{"text":306,"type":45},"[[kv_namespaces]]\nbinding = \"METRICS\"\nid = \"your-production-namespace-id\"\npreview_id = \"your-preview-namespace-id\"",{"type":39,"attrs":308,"content":309},{"textAlign":41},[310],{"text":311,"type":45},"This ensures that Wrangler uses the correct KV binding when testing remotely or deploying to production.",{"type":39,"attrs":313,"content":314},{"textAlign":41},[315],{"text":316,"type":45,"marks":317},"Test the Worker Remotely",[318,320],{"type":224,"attrs":319},{"color":226},{"type":63},{"type":39,"attrs":322,"content":323},{"textAlign":41},[324],{"text":325,"type":45},"Local development using Cloudflare KV requires remote execution. Run:",{"type":166,"attrs":327,"content":328},{"class":168},[329],{"text":330,"type":45},"npx wrangler dev --remote",{"type":39,"attrs":332,"content":333},{"textAlign":41},[334,336,340],{"text":335,"type":45},"Wrangler will print a preview URL similar to ",{"text":337,"type":45,"marks":338},"https://page-view-counter.demo-account.workers.dev",[339],{"type":208},{"text":341,"type":45},". Visit that URL in a browser. Refresh the page multiple times to see the view count increase.",{"type":39,"attrs":343,"content":344},{"textAlign":41},[345],{"text":346,"type":45},"Each route (e.g. /, /about) is counted independently in KV storage.",{"type":39,"attrs":348,"content":349},{"textAlign":41},[350],{"text":351,"type":45,"marks":352},"Deploy the Worker",[353,355],{"type":224,"attrs":354},{"color":226},{"type":63},{"type":166,"attrs":357,"content":358},{"class":168},[359],{"text":360,"type":45},"npx wrangler deploy",{"type":39,"attrs":362,"content":363},{"textAlign":41},[364,366,370],{"text":365,"type":45},"You’ll receive a public ",{"text":367,"type":45,"marks":368},"*.workers.dev",[369],{"type":208},{"text":371,"type":45}," URL where the Worker is live and KV-backed view counts persist across sessions and regions.",{"type":39,"attrs":373,"content":374},{"textAlign":41},[375],{"text":376,"type":45,"marks":377},"Extending the Pattern",[378],{"type":63},{"type":39,"attrs":380,"content":381},{"textAlign":41},[382],{"text":383,"type":45},"This page view counter can serve as a foundation for more dynamic features, including:",{"type":70,"content":385},[386,393,400,407],{"type":73,"content":387},[388],{"type":39,"attrs":389,"content":390},{"textAlign":41},[391],{"text":392,"type":45},"Like buttons or upvotes",{"type":73,"content":394},[395],{"type":39,"attrs":396,"content":397},{"textAlign":41},[398],{"text":399,"type":45},"Feature toggles using booleans in KV",{"type":73,"content":401},[402],{"type":39,"attrs":403,"content":404},{"textAlign":41},[405],{"text":406,"type":45},"Simple poll voting",{"type":73,"content":408},[409],{"type":39,"attrs":410,"content":411},{"textAlign":41},[412],{"text":413,"type":45},"Capturing short-form feedback (e.g. comments or ratings)",{"type":39,"attrs":415,"content":416},{"textAlign":41},[417],{"text":418,"type":45},"Cloudflare KV is optimised for lightweight reads and writes and integrates seamlessly with Workers for edge-first development. For more complex use cases that require atomic writes or strong consistency, consider Durable Objects.",{"type":39,"attrs":420,"content":421},{"textAlign":41},[422],{"text":423,"type":45},"Cloudflare KV opens up a wide range of possibilities for adding dynamic behaviour to static sites. Combined with Workers, it allows developers to build fast, distributed applications without managing traditional infrastructure. The example in this blog post offers one way to get started, but the same approach applies to many other edge-powered use cases.","blog-post",{"id":41,"alt":41,"name":226,"focus":41,"title":41,"source":41,"filename":226,"copyright":41,"fieldtype":426,"meta_data":427},"asset",{},"add-dynamic-features-to-static-sites-with-cloudflare-kv-and-workers","blog/add-dynamic-features-to-static-sites-with-cloudflare-kv-and-workers",-30,[],681959112,"b3701c28-cab1-4039-b185-0f88a6f865e4","2025-06-29T21:42:05.202Z","default",[],1776388611,[],[],{"cache-control":441,"connection":442,"content-encoding":443,"content-type":444,"date":445,"etag":446,"referrer-policy":447,"sb-be-version":448,"server":449,"transfer-encoding":450,"vary":451,"via":452,"x-amz-cf-id":453,"x-amz-cf-pop":454,"x-cache":455,"x-content-type-options":456,"x-frame-options":457,"x-permitted-cross-domain-policies":458,"x-request-id":459,"x-runtime":460,"x-xss-protection":461},"max-age=0, public, s-maxage=604800, stale-if-error=3600","keep-alive","gzip","application/json; charset=utf-8","Fri, 17 Apr 2026 01:17:46 GMT","W/\"66b833e7e89df80afce0951a417fb783\"","strict-origin-when-cross-origin","5.747.1","nginx/1.29.1","chunked","Origin,Accept-Encoding","1.1 665ab06c46487fb955359d416a56449a.cloudfront.net (CloudFront)","6lqFCkG4YxamqgsapjbvdrlRFuQYMzS7NpITePCtnzB9-R8uGfRYrQ==","ORD56-P10","Miss from cloudfront","nosniff","SAMEORIGIN","none","bbf08603-57a5-4271-85d8-de8db0cd1558","0.028314","0",[463],{"name":464,"created_at":465,"published_at":466,"updated_at":467,"id":468,"uuid":469,"content":470,"slug":887,"full_slug":888,"sort_by_date":41,"position":889,"tag_list":890,"is_startpage":7,"parent_id":432,"meta_data":41,"group_id":891,"first_published_at":892,"release_id":41,"lang":435,"path":41,"alternates":893,"default_full_slug":41,"translated_slugs":41},"Automating Repetitive Tasks with Cron Jobs","2025-06-04T00:29:46.058Z","2026-04-14T00:38:06.662Z","2026-04-14T00:38:06.678Z",682046903,"7efd2432-a3a4-427b-9c6d-c3d8455d52cd",{"_uid":471,"tags":472,"intro":476,"title":464,"author":34,"content":477,"component":424,"cover_image":885,"publish_date":226},"be5cab27-ef89-48b6-8b15-d243b8895583",[473,474,30,475],"automation","devops","reference","Learn what cron jobs are, how they work, and how to automate repetitive tasks on Unix systems with real-world examples.",{"type":36,"content":478},[479,484,489,496,501,506,511,518,523,528,535,540,545,550,555,560,565,572,617,622,629,717,724,793,800,830,835,842,847,870,875,880],{"type":39,"attrs":480,"content":481},{"textAlign":41},[482],{"text":483,"type":45},"Automation in software development and system administration is not just about productivity. It is about reliability and consistency. Whether generating reports, cleaning logs, or syncing data, automating repetitive tasks keeps systems running smoothly without constant attention.",{"type":39,"attrs":485,"content":486},{"textAlign":41},[487],{"text":488,"type":45},"One of the most widely used tools for this is cron, a simple and powerful scheduler.",{"type":39,"attrs":490,"content":491},{"textAlign":41},[492],{"text":493,"type":45,"marks":494},"What Is a Cron Job?",[495],{"type":63},{"type":39,"attrs":497,"content":498},{"textAlign":41},[499],{"text":500,"type":45},"A cron job is a time-based job scheduler in Unix-like operating systems. It allows you to run scripts or commands automatically at specified times or intervals.",{"type":39,"attrs":502,"content":503},{"textAlign":41},[504],{"text":505,"type":45},"Think of it as your server’s built-in calendar for routine tasks.",{"type":39,"attrs":507,"content":508},{"textAlign":41},[509],{"text":510,"type":45},"The word cron comes from the Greek word chronos, meaning time. Cron manages when commands run, not how they run.",{"type":39,"attrs":512,"content":513},{"textAlign":41},[514],{"text":515,"type":45,"marks":516},"Understanding the Cron Syntax",[517],{"type":63},{"type":39,"attrs":519,"content":520},{"textAlign":41},[521],{"text":522,"type":45},"Cron jobs are configured in a file called the crontab, short for cron table. Each line defines a job using this format:",{"type":166,"attrs":524,"content":525},{"class":168},[526],{"text":527,"type":45},"*     *     *     *     *     command-to-run\n│     │     │     │     │\n│     │     │     │     └───── Day of the week (0–7) (Sunday = 0 or 7)\n│     │     │     └─────────── Month (1–12)\n│     │     └───────────────── Day of the month (1–31)\n│     └─────────────────────── Hour (0–23)\n└───────────────────────────── Minute (0–59)",{"type":39,"attrs":529,"content":530},{"textAlign":41},[531],{"text":532,"type":45,"marks":533},"Examples:",[534],{"type":63},{"type":166,"attrs":536,"content":537},{"class":168},[538],{"text":539,"type":45},"0 2 * * * /usr/bin/python3 /home/user/scripts/backup.py",{"type":39,"attrs":541,"content":542},{"textAlign":41},[543],{"text":544,"type":45},"Runs daily at 2:00 AM",{"type":166,"attrs":546,"content":547},{"class":168},[548],{"text":549,"type":45},"*/5 * * * * /usr/local/bin/check-health.sh",{"type":39,"attrs":551,"content":552},{"textAlign":41},[553],{"text":554,"type":45},"Runs every 5 minutes",{"type":166,"attrs":556,"content":557},{"class":168},[558],{"text":559,"type":45},"0 9 * * 1 /home/user/scripts/report.sh",{"type":39,"attrs":561,"content":562},{"textAlign":41},[563],{"text":564,"type":45},"Runs every Monday at 9:00 AM",{"type":39,"attrs":566,"content":567},{"textAlign":41},[568],{"text":569,"type":45,"marks":570},"How to Schedule a Cron Job",[571],{"type":63},{"type":573,"attrs":574,"content":576},"ordered_list",{"order":575},1,[577,589,600],{"type":73,"content":578},[579,584],{"type":39,"attrs":580,"content":581},{"textAlign":41},[582],{"text":583,"type":45},"Open the crontab editor:",{"type":166,"attrs":585,"content":586},{"class":168},[587],{"text":588,"type":45},"crontab -e",{"type":73,"content":590},[591,596],{"type":39,"attrs":592,"content":593},{"textAlign":41},[594],{"text":595,"type":45},"Add your cron job: ",{"type":166,"attrs":597,"content":598},{"class":168},[599],{"text":539,"type":45},{"type":73,"content":601},[602,607,612],{"type":39,"attrs":603,"content":604},{"textAlign":41},[605],{"text":606,"type":45},"Save and exit. Cron will automatically pick up the new job.",{"type":39,"attrs":608,"content":609},{"textAlign":41},[610],{"text":611,"type":45},"To view scheduled jobs:",{"type":166,"attrs":613,"content":614},{"class":168},[615],{"text":616,"type":45},"crontab -l",{"type":39,"attrs":618,"content":619},{"textAlign":41},[620],{"text":621,"type":45},"Cron runs in a minimal environment. Always assume nothing is preloaded. ",{"type":39,"attrs":623,"content":624},{"textAlign":41},[625],{"text":626,"type":45,"marks":627},"Real World Use Cases",[628],{"type":63},{"type":573,"attrs":630,"content":631},{"order":575},[632,649,666,683,700],{"type":73,"content":633},[634,639,644],{"type":39,"attrs":635,"content":636},{"textAlign":41},[637],{"text":638,"type":45},"Daily Backups",{"type":39,"attrs":640,"content":641},{"textAlign":41},[642],{"text":643,"type":45},"Run backups during off-peak hours:",{"type":166,"attrs":645,"content":646},{"class":168},[647],{"text":648,"type":45},"0 1 * * * /usr/local/bin/backup-db.sh >> /var/log/backup.log 2>&1",{"type":73,"content":650},[651,656,661],{"type":39,"attrs":652,"content":653},{"textAlign":41},[654],{"text":655,"type":45},"Log Rotation and Cleanup ",{"type":39,"attrs":657,"content":658},{"textAlign":41},[659],{"text":660,"type":45},"Delete old logs to prevent disk issues:",{"type":166,"attrs":662,"content":663},{"class":168},[664],{"text":665,"type":45},"0 3 * * 0 find /var/log/myapp/ -type f -name \"*.log\" -mtime +14 -delete",{"type":73,"content":667},[668,673,678],{"type":39,"attrs":669,"content":670},{"textAlign":41},[671],{"text":672,"type":45},"Sending Email Reports ",{"type":39,"attrs":674,"content":675},{"textAlign":41},[676],{"text":677,"type":45},"Send reports on a schedule: ",{"type":166,"attrs":679,"content":680},{"class":168},[681],{"text":682,"type":45},"30 6 * * 1-5 /home/analytics/send-report.sh",{"type":73,"content":684},[685,690,695],{"type":39,"attrs":686,"content":687},{"textAlign":41},[688],{"text":689,"type":45},"System Health Checks",{"type":39,"attrs":691,"content":692},{"textAlign":41},[693],{"text":694,"type":45},"Monitor system status regularly: ",{"type":166,"attrs":696,"content":697},{"class":168},[698],{"text":699,"type":45},"*/10 * * * * /usr/local/bin/health-check.sh",{"type":73,"content":701},[702,707,712],{"type":39,"attrs":703,"content":704},{"textAlign":41},[705],{"text":706,"type":45},"Syncing Data Between Services",{"type":39,"attrs":708,"content":709},{"textAlign":41},[710],{"text":711,"type":45},"Keep systems in sync:",{"type":166,"attrs":713,"content":714},{"class":168},[715],{"text":716,"type":45},"15 * * * * /usr/bin/node /scripts/fetch-inventory.js",{"type":39,"attrs":718,"content":719},{"textAlign":41},[720],{"text":721,"type":45,"marks":722},"Best Practices",[723],{"type":63},{"type":70,"content":725},[726,737,747,763,773,783],{"type":73,"content":727},[728],{"type":39,"attrs":729,"content":730},{"textAlign":41},[731,733,735],{"text":732,"type":45},"Log everything ",{"type":734},"hard_break",{"text":736,"type":45},"Capture output and errors using >> and 2>&1",{"type":73,"content":738},[739],{"type":39,"attrs":740,"content":741},{"textAlign":41},[742,744,745],{"text":743,"type":45},"Use absolute paths ",{"type":734},{"text":746,"type":45},"Cron does not resolve paths as your shell does",{"type":73,"content":748},[749],{"type":39,"attrs":750,"content":751},{"textAlign":41},[752,754,755,757,761],{"text":753,"type":45},"Avoid overlapping jobs ",{"type":734},{"text":756,"type":45},"Use tools like ",{"text":758,"type":45,"marks":759},"flock",[760],{"type":208},{"text":762,"type":45}," to prevent duplicate runs",{"type":73,"content":764},[765],{"type":39,"attrs":766,"content":767},{"textAlign":41},[768,770,771],{"text":769,"type":45},"Test scripts manually ",{"type":734},{"text":772,"type":45},"Make sure they work before scheduling",{"type":73,"content":774},[775],{"type":39,"attrs":776,"content":777},{"textAlign":41},[778,780,781],{"text":779,"type":45},"Set environment variables explicitly ",{"type":734},{"text":782,"type":45},"Cron does not load your usual environment",{"type":73,"content":784},[785],{"type":39,"attrs":786,"content":787},{"textAlign":41},[788,790,791],{"text":789,"type":45},"Monitor execution ",{"type":734},{"text":792,"type":45},"Use tools like Healthchecks.io or Dead Man’s Snitch",{"type":39,"attrs":794,"content":795},{"textAlign":41},[796],{"text":797,"type":45,"marks":798},"Common Mistakes",[799],{"type":63},{"type":70,"content":801},[802,809,816,823],{"type":73,"content":803},[804],{"type":39,"attrs":805,"content":806},{"textAlign":41},[807],{"text":808,"type":45},"Assuming your script has access to the same environment as your terminal",{"type":73,"content":810},[811],{"type":39,"attrs":812,"content":813},{"textAlign":41},[814],{"text":815,"type":45},"Forgetting to log output, which leads to silent failures ",{"type":73,"content":817},[818],{"type":39,"attrs":819,"content":820},{"textAlign":41},[821],{"text":822,"type":45},"Using relative paths that break in cron",{"type":73,"content":824},[825],{"type":39,"attrs":826,"content":827},{"textAlign":41},[828],{"text":829,"type":45},"Running long jobs without handling overlaps",{"type":39,"attrs":831,"content":832},{"textAlign":41},[833],{"text":834,"type":45},"Cron schedules jobs. Your scripts are responsible for handling errors and retries.",{"type":39,"attrs":836,"content":837},{"textAlign":41},[838],{"text":839,"type":45,"marks":840},"When Not to Use Cron",[841],{"type":63},{"type":39,"attrs":843,"content":844},{"textAlign":41},[845],{"text":846,"type":45},"Cron works well for simple, time-based tasks. It is not ideal for:",{"type":70,"content":848},[849,856,863],{"type":73,"content":850},[851],{"type":39,"attrs":852,"content":853},{"textAlign":41},[854],{"text":855,"type":45},"High frequency execution",{"type":73,"content":857},[858],{"type":39,"attrs":859,"content":860},{"textAlign":41},[861],{"text":862,"type":45},"Complex dependencies between jobs",{"type":73,"content":864},[865],{"type":39,"attrs":866,"content":867},{"textAlign":41},[868],{"text":869,"type":45},"Stateful workflows",{"type":39,"attrs":871,"content":872},{"textAlign":41},[873],{"text":874,"type":45},"In these cases, tools like Celery, Airflow, or Temporal provide better control. ",{"type":39,"attrs":876,"content":877},{"textAlign":41},[878],{"text":879,"type":45},"Cron jobs are a foundational tool for backend engineers and DevOps teams. They help you automate routine work and keep systems reliable over time.",{"type":39,"attrs":881,"content":882},{"textAlign":41},[883],{"text":884,"type":45},"Mastering cron is not just about scheduling tasks. It is about building systems that run consistently without constant intervention.",{"id":41,"alt":41,"name":226,"focus":41,"title":41,"source":41,"filename":226,"copyright":41,"fieldtype":426,"meta_data":886},{},"automating-repetitive-tasks-with-cron-jobs","blog/automating-repetitive-tasks-with-cron-jobs",-10,[],"2a6bfa98-686c-40dd-93ea-f1a1628a644a","2025-06-04T01:24:33.451Z",[],{"left":4,"top":4,"width":895,"height":895,"rotate":4,"vFlip":7,"hFlip":7,"body":896},32,"\u003Cg fill=\"none\">\u003Cpath d=\"M9.97314 24.4668L14.1065 27.6668C14.6398 28.2001 15.8398 28.4668 16.6398 28.4668H21.7065C23.3065 28.4668 25.0398 27.2668 25.4398 25.6668L28.6398 15.9335C29.3065 14.0668 28.1065 12.4668 26.1065 12.4668H20.7731C19.9731 12.4668 19.3065 11.8001 19.4398 10.8668L20.1065 6.60012C20.3731 5.40012 19.5731 4.06679 18.3731 3.66679C17.3065 3.26679 15.9731 3.80012 15.4398 4.60012L9.97314 12.7335\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-miterlimit=\"10\"/>\n\u003Cpath d=\"M3.17334 24.4667V11.4C3.17334 9.53337 3.97334 8.8667 5.84001 8.8667H7.17334C9.04001 8.8667 9.84001 9.53337 9.84001 11.4V24.4667C9.84001 26.3334 9.04001 27 7.17334 27H5.84001C3.97334 27 3.17334 26.3334 3.17334 24.4667Z\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\u003C/g>",{"left":4,"top":4,"width":895,"height":895,"rotate":4,"vFlip":7,"hFlip":7,"body":898},"\u003Cg fill=\"none\">\u003Cpath d=\"M26.12 16.0001L20 9.88008V13.1601L18.8533 13.3334C13.1067 14.1467 9.21333 17.1601 6.98667 21.7734C10.08 19.5867 13.92 18.5334 18.6667 18.5334H20V22.1201M17.3333 19.8934C11.3733 20.1734 7.10667 22.3201 4 26.6667C5.33333 20.0001 9.33333 13.3334 18.6667 12.0001V6.66675L28 16.0001L18.6667 25.3334V19.8667C18.2267 19.8667 17.7867 19.8801 17.3333 19.8934Z\" fill=\"currentColor\"/>\u003C/g>",1776388665798]