The Performance Stack
Let's start with the numbers, because they're the point. Running the site through Google's PageSpeed Insights confirms what the architecture was designed to achieve, every metric lands in the "good" range and two of them hit the absolute floor:
| Metric | Score | Google's "Good" Threshold |
|---|---|---|
| First Contentful Paint | 0.8s | < 1.8s |
| Largest Contentful Paint | 0.8s | < 2.5s |
| Total Blocking Time | 0ms | < 200ms |
| Cumulative Layout Shift | 0 | < 0.1 |
| Speed Index | 2.1s | < 3.4s |
These aren't the result of a single clever optimization. They're the cumulative effect of several decisions that compound. This post walks through each one.
No JavaScript
The most impactful performance decision on this site wasn't something added. It was something left out.
JavaScript is the single biggest source of Total Blocking Time and Cumulative Layout Shift on modern websites. TBT measures how long the main thread is blocked and unavailable for user input. CLS measures how much content shifts after initial render due to fonts loading late, images reflowing or dynamically injected elements pushing things around.
Both scores on this site are zero. That's not the result of careful JavaScript optimization. It's the result of not having any JavaScript to optimize. A Django-rendered portfolio doesn't need it. The content is server-side HTML; there's nothing to hydrate, no bundle to parse, no framework to initialize.
If you're reaching for a JavaScript framework for a portfolio site, it's worth asking what problem it's actually solving.
ManifestStaticFilesStorage: Cache Busting Without the Headache
Static files are typically the heaviest part of a page load. The Django setting that addresses this is easy to overlook:
STORAGES = {
"staticfiles": {
"BACKEND": "django.contrib.staticfiles.storage.ManifestStaticFilesStorage",
},
}
During collectstatic, ManifestStaticFilesStorage appends a content hash to every static file. Your main.css becomes main.a3b2c1.css. The filename changes when the content changes, and stays the same when it doesn't.
This matters because of what it unlocks at the Caddy level:
Cache-Control "public, max-age=31536000, immutable"
The immutable directive tells browsers not to revalidate this file, ever. It will never change at this URL. If the content changes, the URL changes. Returning visitors load CSS and fonts directly from disk cache, with zero network round-trips. First visit pays the cost once. Every subsequent visit pays nothing.
Caddy: Compression Without Configuration
Caddy handles compression automatically. Every response is gzip or Brotli compressed on the fly, with no additional configuration required beyond enabling it. Brotli typically achieves 15–25% better compression than gzip on text content, which matters for HTML responses that can't be cached the way static assets can.
The combination of immutable caching for static assets and compression for all responses, means the site minimizes both the number of network requests and the size of the ones that do happen.
Gunicorn Worker Recycling
One performance factor that rarely comes up in SEO discussions is application server consistency. Time to First Byte is a real ranking signal, and TTFB degrades gradually on long-running Python workers as memory use grows.
This site runs Gunicorn with periodic worker recycling. After a configured number of requests, workers are replaced with fresh ones. Response times stay predictable. There are no occasional slow outliers caused by a worker that's been running for hours. Crawlers see a server that consistently responds quickly, rather than one that spikes unpredictably.
Why FCP and LCP Are Identical
The fact that First Contentful Paint and Largest Contentful Paint both measure 0.8s is the most telling detail in the results. It means the largest element on the page renders at the same moment as the first piece of content. There's no second paint phase where a hero image or large block finally appears.
That's what happens when you remove everything that isn't the content itself. No render-blocking scripts, no late-loading web fonts pushing layout around, no framework initialization delaying first paint. The page is visually complete on the first render, because there's nothing competing with it.
When you strip away everything that isn't the content itself, performance stops being a target and starts being the default state.