Set a Performance Budget Before Your Astro Site Gets Fast
A practical performance budget for content-heavy Astro sites, with decisions that protect LCP, CLS, and JavaScript cost.
Performance is easier to preserve when every image, font, and client-side feature must fit a budget before it is shipped.
Astro starts from a good place: server-rendered HTML and no client JavaScript unless you ask for it. That advantage can disappear quietly when a content site adds large hero images, several font files, analytics scripts, embedded media, and interactive components.
A performance budget turns “keep it fast” into a set of decisions the team can review.
Define page-type budgets
Not every route needs the same budget. A text article can be stricter than a media-heavy landing page.
For a technical publication, I start with:
| Resource | Article page | Homepage |
|---|---|---|
| Initial JavaScript | 35 KB | 60 KB |
| Above-fold images | 250 KB | 500 KB |
| Critical fonts | 2 files | 2 files |
| CLS | < 0.1 | < 0.1 |
| LCP | < 2.5 s | < 2.5 s |
The exact numbers can change, but they must be visible. A budget no one checks is only a wish.
Protect the largest contentful paint
Identify the likely LCP element for each template. On an article page it may be the heading; on a homepage it may be the featured image.
If an image is the LCP candidate, give it explicit dimensions, responsive sources, an appropriate sizes value, and high fetch priority. Do not lazy-load it. Images below the first viewport should be lazy-loaded and decoded asynchronously.
Avoid preloading multiple candidates. Every incorrect preload competes with CSS, fonts, and the actual LCP resource.
Reserve space to stop layout shift
Astro’s image tooling can provide intrinsic dimensions for imported assets. Static images in public need width and height attributes or a stable aspect ratio.
The same rule applies to advertisements, video embeds, newsletter blocks, and code examples rendered by client scripts. Reserve their final space before the content arrives.
Use islands only when interaction earns them
A theme switcher does not require a UI framework. Neither does a disclosure menu, a search form that navigates to a results page, or a copy button.
Use an island when the component has meaningful state or complex interaction. Then choose the least aggressive client directive:
client:visiblefor components below the fold.client:idlefor non-critical enhancements.client:mediafor experiences needed only at a breakpoint.client:loadonly when interaction is immediately required.
Review the generated client bundles. A small component can pull in a large dependency tree.
Treat third-party scripts as product decisions
Analytics, chat, embeds, and consent tools often cost more than the site’s own JavaScript. Record the owner, purpose, transfer size, and execution cost of every third-party script.
Load a script only on routes that need it. Prefer privacy-friendly analytics with a small payload. Use a click-to-load placeholder for expensive media embeds when immediate playback is not essential.
Test the built site
Development mode does not represent production output. Build the site, serve the generated files, and test representative routes on a throttled mobile profile.
Track both lab and field data. Lighthouse helps catch regressions before deployment; real-user Core Web Vitals show what happens across actual devices and networks.
The budget is most useful in review. When a feature exceeds it, the conversation becomes concrete: optimize it, delay it, replace it, or accept a documented tradeoff.
End of field note.