[{"data":1,"prerenderedAt":406},["ShallowReactive",2],{"blog-index":3},[4,232],{"id":5,"title":6,"author":7,"body":8,"description":218,"draft":219,"extension":220,"meta":221,"navigation":222,"ogImage":223,"path":224,"publishedAt":225,"seo":226,"stem":227,"tags":228,"updatedAt":223,"__hash__":231},"blog\u002Fblog\u002F2026-04-why-we-ship-static.md","Why we ship static","callum-peers",{"type":9,"value":10,"toc":203},"minimark",[11,15,18,23,45,52,56,61,64,72,76,79,82,86,89,92,95,99,102,129,133,136,156,160,173,180,184,187,190,193],[12,13,14],"p",{},"The Vantara Labs company site is, by design, a pile of prerendered HTML files on a CDN. No server rendering, no edge functions for anything reader-facing, no database. One Cloud Function exists for contact-form submissions, and that is the full dynamic surface.",[12,16,17],{},"That sounds austere, and in 2026 it probably reads as a little old-fashioned. A lot of the tooling ecosystem has moved towards server-rendered, edge-first, \"resumable\" frameworks that do impressive things. We looked at that end of the dial and chose the quiet end on purpose. Here is the reasoning.",[19,20,22],"h2",{"id":21},"what-ship-static-actually-means-for-us","What \"ship static\" actually means for us",[12,24,25,26,36,37,40,41,44],{},"Concretely: every page on this site is generated at build time by ",[27,28,32],"a",{"href":29,"rel":30},"https:\u002F\u002Fnuxt.com\u002Fdocs\u002Fapi\u002Fcommands\u002Fgenerate",[31],"nofollow",[33,34,35],"code",{},"nuxt generate",", uploaded to Firebase Hosting, and served from the nearest edge PoP to the reader. When you hit ",[33,38,39],{},"vantaralabs.co.uk\u002Fabout",", you are getting a prebuilt ",[33,42,43],{},"about\u002Findex.html",", not calling a function.",[12,46,47,48,51],{},"We keep one tiny dynamic bit, the ",[33,49,50],{},"\u002Fapi\u002Fcontact"," Cloud Function, but that is gated behind a form submission, not on every pageview. The blog, the product pages, the RSS feed, the sitemap, the Open Graph images: all built once, served many times.",[19,53,55],{"id":54},"why-in-order-of-importance","Why, in order of importance",[57,58,60],"h3",{"id":59},"_1-the-site-is-read-far-more-often-than-it-is-written","1. The site is read far more often than it is written",[12,62,63],{},"We will update this site a few times a week at most. It is read thousands of times between updates. Rebuilding on every request (even with caching in front) is paying for something the reader never benefits from.",[12,65,66,67,71],{},"Build-time rendering inverts the cost: we pay once, during the push, and every subsequent reader gets a file off a CDN. The only time a reader waits for compute is when the ",[68,69,70],"em",{},"author"," did something new.",[57,73,75],{"id":74},"_2-the-failure-modes-are-smaller","2. The failure modes are smaller",[12,77,78],{},"When a static site breaks, it breaks during CI. Our worst-case deployment failure is \"the build fails and the previous version stays live\", which is a normal day. We cannot push a regression that only shows up for one in a thousand visitors because our infrastructure doesn't have thousand-visitor variance. Every reader gets the same HTML.",[12,80,81],{},"No database means no database outage. No server runtime means no runtime upgrade breaking a library at 03:00. No regional failover complexity because CDN PoPs do that for us.",[57,83,85],{"id":84},"_3-it-costs-approximately-nothing","3. It costs approximately nothing",[12,87,88],{},"Firebase Hosting's free tier serves 10GB of egress per month before any cost kicks in. Our site is a few hundred KB of HTML, images, and fonts per pageview. Back-of-envelope: we would need to serve roughly 50,000 pageviews a month before we pay a penny.",[12,90,91],{},"The Cloud Function for the contact form is the only thing metered on invocations, and that is a handful of form submissions a day at most.",[12,93,94],{},"A small studio's website budget should be \"the domain renewal and nothing else\" until we are at a size where that assumption breaks.",[57,96,98],{"id":97},"_4-determinism-makes-compliance-boring","4. Determinism makes compliance boring",[12,100,101],{},"UK GDPR, the Companies Act 2006 disclosure requirement, ICO guidance on cookies: all easier to comply with on a static site, because:",[103,104,105,113,119],"ul",{},[106,107,108,112],"li",{},[109,110,111],"strong",{},"There is no server-side personal data processing."," We know this because there is no server-side anything on page loads.",[106,114,115,118],{},[109,116,117],{},"Consent Mode v2 can default to \"denied\" without the analytics ever having loaded",", because no third-party script runs until the reader opts in. Which is the whole point of Consent Mode v2.",[106,120,121,124,125,128],{},[109,122,123],{},"Auditing is literally reading the files we ship."," The HTML shipped to readers is identical to the HTML in the repo's ",[33,126,127],{},".output\u002Fpublic"," folder. No hidden runtime branch.",[19,130,132],{"id":131},"what-we-give-up","What we give up",[12,134,135],{},"We are not pretending the trade-off is free. The things we cannot do on a static site:",[103,137,138,144,150],{},[106,139,140,143],{},[109,141,142],{},"Personalisation on pageload."," The same HTML goes to everyone. If we needed per-reader content (e.g. a logged-in dashboard), the products would need server rendering. They do, and they live on their own domains with their own frameworks.",[106,145,146,149],{},[109,147,148],{},"True real-time content."," If something breaks into the news and we want a blog post up in 90 seconds, we wait on a build. For a company site, this is a feature, not a bug.",[106,151,152,155],{},[109,153,154],{},"Runtime A\u002FB testing."," We do not need it yet. When we do, we will reach for static edge rewrites before anything heavier.",[19,157,159],{"id":158},"where-static-stops-being-the-answer","Where static stops being the answer",[12,161,162,163,167,168,172],{},"For the portfolio's actual products, ",[27,164,166],{"href":165},"\u002Fproducts\u002Fpelosi-tracker","Pelosi Tracker"," and ",[27,169,171],{"href":170},"\u002Fproducts\u002Fleyden","Leyden",", static-only would be wrong. Those products serve live-updating data, process payments, gate features behind auth. They need server runtime and we give them one.",[12,174,175,176,179],{},"But the ",[68,177,178],{},"company website"," is a brochure and a blog. We would have to invent requirements to justify running a server for it.",[19,181,183],{"id":182},"the-boring-recommendation","The boring recommendation",[12,185,186],{},"Most small-studio and freelance websites are over-engineered. Nuxt, Next, Astro, SvelteKit all have \"generate static\" as a first-class target. Pick your favourite framework, generate the site, host it on Cloudflare Pages, Netlify, Firebase Hosting, or GitHub Pages, and go build the product.",[12,188,189],{},"The exciting frameworks will still be there when you actually need them.",[191,192],"hr",{},[12,194,195],{},[68,196,197,198,202],{},"Part of a short series on how the Vantara Labs site is put together. Next one: how we manage the GCP side of things with Terraform. Subscribe via the ",[27,199,201],{"href":200},"\u002Fblog\u002Frss.xml","RSS feed"," if that is your thing.",{"title":204,"searchDepth":205,"depth":205,"links":206},"",2,[207,208,215,216,217],{"id":21,"depth":205,"text":22},{"id":54,"depth":205,"text":55,"children":209},[210,212,213,214],{"id":59,"depth":211,"text":60},3,{"id":74,"depth":211,"text":75},{"id":84,"depth":211,"text":85},{"id":97,"depth":211,"text":98},{"id":131,"depth":205,"text":132},{"id":158,"depth":205,"text":159},{"id":182,"depth":205,"text":183},"This site is prerendered HTML on a CDN. Here is the reasoning, and why we think most small-studio websites should be the same.",false,"md",{},true,null,"\u002Fblog\u002F2026-04-why-we-ship-static","2026-04-17",{"title":6,"description":218},"blog\u002F2026-04-why-we-ship-static",[229,230],"engineering","infrastructure","MoK7sWXNzCrkiRRFBe2ilYWb_x7PgG9gy71jf383J5I",{"id":233,"title":234,"author":7,"body":235,"description":396,"draft":219,"extension":220,"meta":397,"navigation":222,"ogImage":223,"path":398,"publishedAt":399,"seo":400,"stem":401,"tags":402,"updatedAt":223,"__hash__":405},"blog\u002Fblog\u002F2026-04-hello-vantara-labs.md","Hello, Vantara Labs",{"type":9,"value":236,"toc":390},[237,240,246,250,257,260,267,270,281,285,288,310,313,317,325,346,350,353,373,379,387],[12,238,239],{},"This is the first post on a brand-new blog, so the opening has to do a bit of work. Let's start here:",[12,241,242,245],{},[109,243,244],{},"Vantara Labs is a UK software studio."," We are registered in England and Wales, based in Stafford, and we ship small, sharp web apps. Some of them turn messy public datasets into something you can read without a statistics degree. Some of them help you think better about your own work.",[19,247,249],{"id":248},"why-the-world-needs-another-studio","Why the world needs another studio",[12,251,252,253,256],{},"It doesn't. What it does need, in our opinion, are more ",[68,254,255],{},"tiny"," studios that care about a specific kind of craft and commit to it long enough to get good.",[12,258,259],{},"A huge amount of publicly-valuable data is hiding behind bad interfaces. US congressional stock disclosures live in PDF. UK parliamentary registers live in semi-structured HTML. Company filings live in XBRL. Reading any of it well is a job, not a browsing experience, and the commercial incentive to fix that is usually owned by organisations whose business model doesn't reward readability.",[12,261,262,263,266],{},"At the same time, a lot of valuable ",[68,264,265],{},"private"," work lives in bad interfaces too. The half-formed thought you had on a walk, the connection you didn't make between two ideas you had three months apart, the note you can't find when you actually need it. These are workflow problems that modern AI is genuinely good at solving, provided somebody builds a calm, focused tool rather than another productivity dashboard.",[12,268,269],{},"We think both categories deserve web apps that:",[103,271,272,275,278],{},[106,273,274],{},"render in under a second on a phone,",[106,276,277],{},"read like a newspaper article, and",[106,279,280],{},"put the answer on the first screen.",[19,282,284],{"id":283},"what-were-actually-shipping","What we're actually shipping",[12,286,287],{},"Two products, one brand:",[103,289,290,303],{},[106,291,292,296,297,302],{},[27,293,294],{"href":165},[109,295,166],{},", our first product, live at ",[27,298,301],{"href":299,"rel":300},"https:\u002F\u002Fpelositracker.app",[31],"pelositracker.app",". Every STOCK Act disclosure, normalised and rendered as a dashboard instead of a PDF, with real-time alerts, historical analytics, and CSV export built in.",[106,304,305,309],{},[27,306,307],{"href":170},[109,308,171],{},", our second product, currently in private beta. AI-powered idea capture for web and mobile: type a thought as soon as you have it, and the app auto-titles, auto-tags, and connects it to your existing notes. Public launch later this year.",[12,311,312],{},"Both products live on their own domains with their own focus. The studio exists to keep each one small without having to re-invent infrastructure, design, or legal every time.",[19,314,316],{"id":315},"how-we-work","How we work",[12,318,319,320,324],{},"We have written down ",[27,321,323],{"href":322},"\u002Fabout","how we build"," in a bit more detail on the about page, but the short version is:",[326,327,328,334,340],"ol",{},[106,329,330,333],{},[109,331,332],{},"One job per product."," Each tool earns its keep by doing one thing well.",[106,335,336,339],{},[109,337,338],{},"Boring infrastructure."," Static-first hosting, deterministic builds, Infrastructure as Code. Every hour saved on maintenance goes straight into product features you can see.",[106,341,342,345],{},[109,343,344],{},"Clear by default."," Plain English, sensible defaults, and answers on the first screen. The dashboard should make sense before you reach for the docs.",[19,347,349],{"id":348},"what-the-blog-will-cover","What the blog will cover",[12,351,352],{},"Three kinds of post, roughly:",[103,354,355,361,367],{},[106,356,357,360],{},[109,358,359],{},"Product updates."," When something ships, how it works, what's next.",[106,362,363,366],{},[109,364,365],{},"Engineering write-ups."," The less-glamorous-but-useful stuff, such as how we run a static Nuxt site on Firebase, how we manage GCP with Terraform, and how we think about cookie consent on a UK-registered site. We benefit from other people's write-ups; fair's fair.",[106,368,369,372],{},[109,370,371],{},"Takes on the categories we work in."," Occasional opinions on public-data tooling and on AI-assisted knowledge work.",[12,374,375,376,378],{},"The canonical way to follow along is the ",[27,377,201],{"href":200},". Subscribe once and new posts arrive in whatever reader you already use.",[12,380,381,382,386],{},"Thanks for reading the first one. If you would like to talk to us about any of the above, whether press, early access to Leyden, product feedback, or just a question, the ",[27,383,385],{"href":384},"\u002Fcontact","contact form"," reaches a real person.",[12,388,389],{},"Callum, Vantara Labs",{"title":204,"searchDepth":205,"depth":205,"links":391},[392,393,394,395],{"id":248,"depth":205,"text":249},{"id":283,"depth":205,"text":284},{"id":315,"depth":205,"text":316},{"id":348,"depth":205,"text":349},"Why we started a UK software studio to do a few unfashionable things well.",{},"\u002Fblog\u002F2026-04-hello-vantara-labs","2026-04-16",{"title":234,"description":396},"blog\u002F2026-04-hello-vantara-labs",[403,404],"announcement","company","ww4PVF3d-D3Lns15TCvC2jwre3zcCdC01-YqSq_35ng",1776592126207]