{"id":3094,"date":"2026-06-22T04:42:19","date_gmt":"2026-06-22T04:42:19","guid":{"rendered":"https:\/\/tucumandevelopers.com\/index.php\/2026\/06\/22\/three-post-deploy-checks-i-run-after-every-cloudflare-pages-build\/"},"modified":"2026-06-22T04:42:19","modified_gmt":"2026-06-22T04:42:19","slug":"three-post-deploy-checks-i-run-after-every-cloudflare-pages-build","status":"publish","type":"post","link":"https:\/\/tucumandevelopers.com\/index.php\/2026\/06\/22\/three-post-deploy-checks-i-run-after-every-cloudflare-pages-build\/","title":{"rendered":"Three post-deploy checks I run after every Cloudflare Pages build"},"content":{"rendered":"<div>\n<div><\/div>\n<div data-article-id=\"3959206\" id=\"article-body\">\n<p>After spending two weeks debugging issues that only showed up in production \u2014 a <a href=\"https:\/\/dev.to\/morinaga\/astrojssitemap-generates-sitemap-0xml-not-sitemap-indexxml-on-small-sites-5c7d\">sitemap _redirects rule that was blocking my own sitemap-index.xml<\/a> and a <a href=\"https:\/\/dev.to\/morinaga\/how-i-fixed-a-bluesky-image-upload-race-against-cloudflare-pages-deploy-lag-5ahk\">Bluesky image upload race against Cloudflare Pages deploy lag<\/a> \u2014 I added three post-deploy checks to my workflow. They&#8217;re fast and specific to the failure modes I&#8217;ve actually hit, not a full end-to-end test suite.<\/p>\n<p>Three sites (aiappdex.com, findindiegame.com, ossfind.com) on Cloudflare Pages with Astro 5 SSG. Here&#8217;s what I check.<\/p>\n<h2> <a name=\"check-1-sitemap-reachability\" href=\"#check-1-sitemap-reachability\"> <\/a> Check 1: Sitemap reachability <\/h2>\n<p>The simplest check and the one I should have had from day one. After a Cloudflare Pages deploy, I verify that <code>sitemap-index.xml<\/code> is reachable and returning 200 on all three domains: <\/p>\n<div>\n<pre><code><span>for <\/span>domain <span>in <\/span>aiappdex.com findindiegame.com ossfind.com<span>;<\/span> <span>do <\/span><span>status<\/span><span>=<\/span><span>$(<\/span>curl <span>-s<\/span> <span>-o<\/span> \/dev\/null <span>-w<\/span> <span>\"%{http_code}\"<\/span> <span>\"https:\/\/<\/span><span>$domain<\/span><span>\/sitemap-index.xml\"<\/span><span>)<\/span> <span>echo<\/span> <span>\"<\/span><span>$domain<\/span><span>\/sitemap-index.xml \u2192 <\/span><span>$status<\/span><span>\"<\/span> <span>if<\/span> <span>[<\/span> <span>\"<\/span><span>$status<\/span><span>\"<\/span> <span>!=<\/span> <span>\"200\"<\/span> <span>]<\/span><span>;<\/span> <span>then <\/span><span>echo<\/span> <span>\"FAIL: <\/span><span>$domain<\/span><span> sitemap unreachable\"<\/span> <span>fi done<\/span> <\/code><\/pre>\n<div>\n<\/p><\/div>\n<\/p><\/div>\n<p>I also check <code>sitemap-0.xml<\/code> \u2014 the actual URL sub-sitemap that <code>@astrojs\/sitemap<\/code> generates \u2014 and assert that it contains at least a minimum expected URL count. For aiappdex.com that threshold is 1,000; if it drops below that after a deploy, the ETL data pipeline probably broke silently.<\/p>\n<p>The reason this check exists: I had a <code>_redirects<\/code> rule rewriting <code>sitemap-index.xml<\/code> \u2192 <code>sitemap-0.xml<\/code> as an emergency workaround that turned out to be wrong. It was live for five days before I found it. The rule was blocking the real <code>sitemap-index.xml<\/code> from reaching crawlers while appearing fine in the browser (which followed the redirect). Curl with <code>-o \/dev\/null -w \"%{http_code}\"<\/code> doesn&#8217;t follow redirects by default, so it would have caught this immediately.<\/p>\n<h2> <a name=\"check-2-indexnow-batch-submission\" href=\"#check-2-indexnow-batch-submission\"> <\/a> Check 2: IndexNow batch submission <\/h2>\n<p>After every successful sitemap check, I run <code>node scripts\/indexnow.mjs<\/code>. The script reads the live sitemap XML from each domain, collects all URLs, and POSTs them to the IndexNow endpoint for Bing, Yandex, Naver, and Seznam using site-specific keys.<\/p>\n<p>Output looks like: <\/p>\n<div>\n<pre><code>aiappdex.com: submitted 1179 URLs \u2192 200 OK findindiegame.com: submitted 139 URLs \u2192 200 OK ossfind.com: submitted 144 URLs \u2192 200 OK <\/code><\/pre>\n<div>\n<\/p><\/div>\n<\/p><\/div>\n<p>If a site returns 403 from IndexNow it usually means the key verification file (<code>\/&lt;key&gt;.txt<\/code>) wasn&#8217;t deployed correctly or a <code>_redirects<\/code> rule is mangling the path. Catching this right after deploy matters because the IndexNow key-verification window isn&#8217;t instantaneous \u2014 letting it sit in a broken state delays indexing. I wrote more about the IndexNow setup in <a href=\"https:\/\/dev.to\/morinaga\/indexnow-libsql-and-three-other-tools-i-reached-for-this-week-5c4m\">this week&#8217;s tools post<\/a>.<\/p>\n<p>I run this manually after deploy rather than inline in the GitHub Actions workflow because the Cloudflare Pages build takes 2-3 minutes, and IndexNow works best with live URLs. Running it as a separate <code>workflow_dispatch<\/code> trigger after the deployment succeeds means I&#8217;m submitting URLs that are actually live rather than ones that might still be deploying.<\/p>\n<h2> <a name=\"check-3-weekly-lighthouse-spotcheck\" href=\"#check-3-weekly-lighthouse-spotcheck\"> <\/a> Check 3: Weekly Lighthouse spot-check <\/h2>\n<p>The third check runs on a cron \u2014 Monday 04:30 UTC \u2014 not after every deploy. It&#8217;s slower (3-4 minutes per site, nine URLs total), so daily would be wasteful for a static site that doesn&#8217;t change at runtime.<\/p>\n<p>The workflow uses <code>treosh\/lighthouse-ci-action<\/code> with one homepage and one deep entry page per site: <\/p>\n<div>\n<pre><code><span>matrix<\/span><span>:<\/span> <span>site<\/span><span>:<\/span> <span>-<\/span> <span>{<\/span> <span>domain<\/span><span>:<\/span> <span>aiappdex.com<\/span><span>,<\/span> <span>sample<\/span><span>:<\/span> <span>\/models\/timm-vit-base-patch16-clip-224-openai\/<\/span> <span>}<\/span> <span>-<\/span> <span>{<\/span> <span>domain<\/span><span>:<\/span> <span>findindiegame.com<\/span><span>,<\/span> <span>sample<\/span><span>:<\/span> <span>\/games\/dredge-1562430\/<\/span> <span>}<\/span> <span>-<\/span> <span>{<\/span> <span>domain<\/span><span>:<\/span> <span>ossfind.com<\/span><span>,<\/span> <span>sample<\/span><span>:<\/span> <span>\/alternatives\/ghost\/<\/span> <span>}<\/span> <\/code><\/pre>\n<div>\n<\/p><\/div>\n<\/p><\/div>\n<p>I&#8217;m watching for Performance below 80, CLS above 0.1, or accessibility score regression. Astro SSG with no client-side JS should hold steady on all three \u2014 if they slip it means something in Tailwind v4 config or the ad slot component changed the layout paint behavior. The results upload to <code>temporaryPublicStorage<\/code> so I can diff before\/after on regressions.<\/p>\n<p>I don&#8217;t set hard failure thresholds that block deploys. These sites are pre-revenue with essentially zero traffic right now; blocking a deploy because a Lighthouse score dropped from 94 to 88 would be disproportionate. I treat Lighthouse as a trend monitor, not a gate.<\/p>\n<h2> <a name=\"what-im-deliberately-not-checking\" href=\"#what-im-deliberately-not-checking\"> <\/a> What I&#8217;m deliberately not checking <\/h2>\n<p>No uptime monitoring \u2014 I&#8217;m relying on Cloudflare&#8217;s own infrastructure status. No end-to-end user flow tests. No API availability checks \u2014 the Turso DB is only queried at build time in SSG mode, so there&#8217;s nothing to check at runtime.<\/p>\n<p>For a dynamically rendered site, those gaps would matter. For a static CDN deployment where the entire runtime is pre-built HTML, CSS, and a handful of JSON files, the three checks above cover the actual failure surface I&#8217;ve encountered.<\/p>\n<p>The publish pipeline has its own idempotency layer (it reads <code>published_urls<\/code> from article frontmatter and skips already-distributed posts), so I don&#8217;t need to verify cross-posting state after each deploy. That&#8217;s a separate concern.<\/p>\n<hr>\n<p><em>Part of an ongoing 6-month experiment running three AI-curated directory sites. The technical claims here are real; this article was AI-assisted.<\/em><\/p>\n<\/p><\/div>\n<\/div>\n<\/div>\n<\/div>\n<p>Fuente: <a href=\"https:\/\/dev.to\/morinaga\/three-post-deploy-checks-i-run-after-every-cloudflare-pages-build-48b4\">Art\u00edculo original<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>After spending two weeks debugging issues that only showed up in production \u2014 a sitemap _redirects rule that was blocking my own sitemap-index.xml and a Bluesky image upload race against Cloudflare Pages deploy lag \u2014 I added three post-deploy checks to my workflow. They&#8217;re fast and specific to the failure modes I&#8217;ve actually hit, not [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":3093,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[41],"tags":[],"class_list":["post-3094","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-devto"],"jetpack_publicize_connections":[],"_links":{"self":[{"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/posts\/3094","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/comments?post=3094"}],"version-history":[{"count":0,"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/posts\/3094\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/media\/3093"}],"wp:attachment":[{"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/media?parent=3094"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/categories?post=3094"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tucumandevelopers.com\/index.php\/wp-json\/wp\/v2\/tags?post=3094"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}