Skip to content

Performance

SwiftAgency is measured, not just described as fast. These are Lighthouse 13.5 results on the production build with the demo content, the Signal preset and the light theme.

Page Desktop Mobile performance Mobile LCP Mobile CLS
/ 100 / 100 / 100 / 100 97 2.2 s 0.047
/work 100 / 100 / 100 / 100 98 2.3 s 0.000
/case-study/northgate-architects 100 / 100 / 100 / 100 99 1.9 s 0.000
/case-study/halden-rail 100 / 100 / 100 / 100 98 2.1 s 0.000
/case-study/tessellate-festival 100 / 100 / 100 / 100 97 2.3 s 0.000
/services 100 / 100 / 100 / 100 98 1.8 s 0.000
/studio 100 / 100 / 100 / 100 99 2.1 s 0.022
/careers 100 / 100 / 100 / 100 98 1.8 s 0.005
/journal 100 / 100 / 100 / 100 98 2.4 s 0.000
/journal/two-languages-one-sign 100 / 100 / 100 / 100 97 2.3 s 0.000
/de/contact 100 / 100 / 100 / 100 98 1.8 s 0.015
/id/privacy 100 / 100 / 100 / 100 99 1.8 s 0.003

Desktop is Performance, Accessibility, Best Practices and SEO. On mobile, Accessibility, Best Practices and SEO are 100 on every page, and Total Blocking Time is 0 ms everywhere: the whole site ships about 20 KB of JavaScript.

Mobile uses Lighthouse’s default simulation of a mid-range phone on a throttled 4G connection. What remains of mobile LCP is mostly the 88 KB variable font behind the width-axis effect; text never waits for it, but it shares bandwidth with the hero image.

The full tables are in docs/LIGHTHOUSE.md in the theme.

Terminal window
npm run build
npm run preview # http://localhost:4321
npx lighthouse http://localhost:4321/ --preset=desktop --view
npx lighthouse http://localhost:4321/ --view # mobile

Or run the same checks as CI, seven pages three times each:

Terminal window
npm run lighthouse

Measure the production build, never npm run dev. The dev server skips optimisation and loads extra tooling.

GitHub Actions runs Lighthouse CI on every push and pull request. The job fails when a page drops below:

Category Minimum (desktop)
Performance 95
Accessibility 100
Best practices 100
SEO 100

The pages and thresholds are in lighthouserc.json. Reports are saved as a lighthouse-reports artifact on each run, so you can open a failing report and see exactly what changed.

  • Static HTML with CSS inlined into each page, so the first paint needs no extra request.
  • Images through astro:assets: WebP, a responsive srcset, explicit dimensions, lazy loading below the fold and fetchpriority="high" on the hero.
  • Self-hosted variable fonts with metric-matched fallbacks, so the font swap doesn’t move the layout.
  • No framework. Interaction is a handful of small TypeScript modules. Keystatic’s React is loaded in development only.
  • No scroll listeners. Scroll effects use CSS scroll-driven animations and IntersectionObserver.
  • Export large, don’t pre-compress. Astro makes the sizes. A 2400px JPEG is a good source; a 12 MB PNG makes builds slow but pages still fast.
  • One priority image per page, the one at the top. See Media.
  • Don’t fade in the hero. Keep data-reveal off the largest element on screen at load.
  • Think before adding scripts. An analytics or chat widget can cost more than the whole theme. Load it with defer, or after the page has loaded, and measure again.
  • Turn off the preset switcher (theme.switcher: false). Then only one preset’s CSS ships.