Astro Incremental Content Update Without Full Rebuild

How to ship a single article update on an Astro site without rebuilding 3,000 pages: islands, on-demand rendering, content-layer hashing, and a hybrid workflow that scales.

Once an Astro site crosses 1,000 pages, a “fix a typo” task triggers a 6-minute full rebuild and a CDN cache invalidation that touches every URL. This is wasteful, slow, and risky. Astro does not ship a true incremental build out of the box, but there is a practical pattern that gets most of the way there.

Background

Astro builds are designed to be deterministic and fast on cold start. That makes them slow on hot edits, because every page is regenerated whether or not its inputs changed. On large content sites with frequent small edits, full rebuilds become the bottleneck — both wall-clock and emotional. The fix is not a magic flag; it is a combination of build-time scoping, hybrid rendering for the few pages you really do not want to rebuild, and CDN-level partial invalidation.

How to tell

  • Your npm run build takes more than 90 seconds.
  • You hold back small content fixes because “I will batch them this weekend”.
  • Your CDN purges all URLs after every deploy, costing free-tier quota.
  • Your CI minutes are dominated by Astro generation, not by tests or lint.
  • You have started writing skip-build hacks in pre-deploy scripts.

Quick verdict

For sites under 500 pages, just rebuild — it is not worth the complexity. For 500-5,000 pages, scope your build via content hashing and a --changed flag. Past 5,000 pages, move the hot edges to on-demand or ISR.

Pattern 1: hash-based skip on unchanged content

The cheapest win is detecting that nothing actually changed and short-circuiting. Hash each content file plus its layout dependencies, store the hashes in dist-cache/, and skip the build when the manifest matches:

// scripts/build-if-changed.mjs
import { createHash } from 'node:crypto';
import { readdirSync, readFileSync, existsSync, writeFileSync } from 'node:fs';

const files = readdirSync('src/content/articles/en', { recursive: true })
  .filter(f => f.endsWith('.mdx'));
const hash = createHash('sha256');
for (const f of files.sort()) hash.update(readFileSync(`src/content/articles/en/${f}`));
const digest = hash.digest('hex');

const last = existsSync('.build-hash') ? readFileSync('.build-hash', 'utf8') : '';
if (digest === last) {
  console.log('No content changes; skipping build.');
  process.exit(0);
}
writeFileSync('.build-hash', digest);
process.exit(1); // signal CI to continue to build step

This will not help your single-typo case, but it will catch the half of CI runs that are doc-only or workflow-only commits.

Pattern 2: hybrid rendering for hot pages

Mark the 50 URLs that change daily (sitemap, latest list, RSS, homepage) as on-demand. Everything else stays static. In astro.config.mjs:

import { defineConfig } from 'astro';
import vercel from '@astrojs/vercel/serverless';

export default defineConfig({
  output: 'hybrid',
  adapter: vercel(),
  prefetch: { defaultStrategy: 'viewport' },
});

Then per-page, opt in with export const prerender = false; on the routes you do want server-rendered. Now a content edit only invalidates the static page that changed plus your handful of on-demand routes, not the whole site.

Pattern 3: CDN-level partial invalidation

After a build, parse the Astro build manifest to find which output files actually changed, then purge only those paths from your CDN:

# diff dist/ between deploys, then purge only changed
git diff --name-only HEAD~1 HEAD -- 'dist/**/*.html' \
  | xargs -I{} curl -X POST "https://api.cloudflare.com/.../purge_cache" \
      -H "Authorization: Bearer $CF_TOKEN" \
      -d "{\"files\":[\"https://yourdomain.com/{}\"]}"

Most hosts (Vercel, Cloudflare Pages, Netlify) do this automatically by content hash, but Firebase Hosting and S3 do not — there you must drive it yourself.

Common mistakes

  • Reaching for hybrid mode on a 200-page site. The complexity is not worth it; just rebuild.
  • Purging the entire CDN cache after every deploy out of habit. Most hosts already do per-file invalidation.
  • Writing a custom incremental builder that re-implements Astro internals. It will break at the next minor version.
  • Skipping the build hash check when frontmatter-only changes happen — they still affect generated HTML.
  • Treating dev-mode HMR as a substitute for prod incremental builds. Dev mode bypasses content-collection compilation entirely.

FAQ

  • Does Astro have an official incremental build mode?: Not as of 2026. The team is exploring it (search “Astro Content Layer” RFC), but the production answer is the patterns above.
  • Will Astro 5’s Content Layer fix this?: Partially. Content Layer makes data loading more granular but does not change the static generation step itself. You still rebuild every page on every deploy.
  • What about persistent caching in CI?: Caching node_modules and .astro/ shaves seconds, not minutes. The bottleneck is page generation, not dependency install.
  • Can I serve hybrid pages from Firebase Hosting?: Yes, via Cloud Functions or Cloud Run, but the cold-start overhead often defeats the purpose. Hybrid mode pairs best with Vercel, Netlify, or Cloudflare Workers.
  • Do I need to invalidate the sitemap on every edit?: Yes if lastmod matters to your SEO. Make it on-demand so it always reflects current data without rebuilding.

Tags: #Indie dev #Astro #build-performance #Content ops