pickuma.
Meta

The Pickuma Tech Stack: Every Tool and Service We Use to Run This Site

From Astro 6 to Supabase, Bun to Cloudflare Pages — a transparent breakdown of every tool, service, and workflow that powers pickuma.com. Includes our actual monthly infrastructure costs and the automation pipeline that keeps the site publishing.

10 min read

Here is every piece of infrastructure behind pickuma.com, what it costs, and why I chose it.

I know I like reading these articles. When someone runs a site I respect and they publish a stack breakdown with real numbers, I read the whole thing. Not because I am shopping for a static site generator — I already have opinions about those — but because every stack reflects a set of decisions. You learn which problems the builder actually hit, which tools they considered and rejected, and where the friction lives. That is what this article is: the decisions, the costs, and the things I would do differently.

The Core Stack

The site is built with Astro 6, deployed to Cloudflare Pages, backed by Supabase, styled with Tailwind CSS v4, written in MDX, and run locally on Bun. Every piece of this stack was chosen for a specific reason, and each has tradeoffs worth explaining.

Astro 6 on Cloudflare Pages

I chose Astro because it ships zero JavaScript by default. The site is a content blog — there is no interactive state, no client-side routing, no reason to send a JavaScript bundle to the reader. Astro renders everything to static HTML at build time and the output is a directory of flat files. That means the site loads in under a second on a throttled connection because there is nothing to download except the HTML and a small CSS file.

Cloudflare Pages hosts the static output. I push to the main branch, Cloudflare runs bun run build, and the site deploys in about 40 seconds. Builds take roughly 25 seconds end-to-end — 18 seconds for the Astro build step, plus image optimization and asset hashing. The free tier covers everything: unlimited bandwidth, unlimited requests, and a global CDN that serves pages from within 30 milliseconds of most readers. There is no server to patch, no nginx config to maintain, and no bill at the end of the month.

The one limitation is the 500-builds-per-month cap on the free plan. At our current publishing cadence of roughly three articles per week plus occasional site updates, we run maybe 20 builds per month. If we ever hit the cap I will pay the $20 Pro plan, but so far the free tier has been more than adequate.

Supabase for the Database

The database is a Supabase PostgreSQL instance running on the free tier. I use it for three things: storing affiliate link click data, tracking cross-post engagement metrics, and maintaining a lightweight editorial queue.

The free tier gives you 500 MB of database storage and 2 GB of bandwidth per month, which is enough for the current scale. Our click tracking table has roughly 12,000 rows after six months of operation. The editorial queue — which is really just a posts table with a status column and a few metadata fields — fits in a few megabytes.

I chose Supabase over PlanetScale and Neon for two reasons. First, Supabase includes auth, real-time subscriptions, and storage in the same project — I did not want to manage separate services for the few features that need a backend. Second, Supabase’s row-level security model means I can expose a read-only API to the frontend without writing middleware. The Astro site fetches click counts and post metadata directly from the Supabase REST API during server-side rendering, and the row-level security policies ensure nothing writable is exposed to the client.

Bun as the Runtime

I switched from Node.js to Bun in March 2026, after Bun 1.2 stabilized and the Astro adapter caught up. The migration took about an hour — I changed the package.json scripts from node to bun and updated the Cloudflare Pages build command. Everything else worked.

The practical difference is install speed. bun install completes in under three seconds on a clean cache. On Node, the same install took twelve seconds. That is not a lot of time saved per build, but it adds up when you are iterating locally and running builds every few minutes. The test suite — which is small, maybe 40 tests — runs in 1.8 seconds on Bun versus 3.1 seconds on Node.

I am not a runtime zealot. If Bun introduces a breaking change that costs me an afternoon, I will switch back to Node in an hour and move on. So far that has not happened.

Tailwind CSS v4 and MDX

Tailwind v4 handles all styling. I resisted Tailwind for years because I found the class soup unreadable, and I still find it unreadable — but I write CSS maybe twice a month, and when I do, I want the feedback loop to be instant. Tailwind gives me that. The v4 release cleaned up the configuration model considerably, eliminating the tailwind.config.js file and moving all configuration into CSS. The site’s entire design system fits in about 40 lines of CSS custom properties.

MDX is the content format. Every article is an .mdx file in the src/content/posts directory. Astro’s content collections API makes this straightforward: each file declares its metadata in YAML frontmatter, Astro validates it against a Zod schema at build time, and the post pages are generated automatically. I can embed custom components — callout boxes, FAQ accordions, affiliate link cards — directly in the article body without leaving the Markdown syntax. This article you are reading is an MDX file.

The Content Pipeline

This is the part people ask about most. The site publishes several thousand words per week across multiple articles, and there is no full-time editorial staff — just me and a set of scripts.

Claude API for Drafting

The first draft of every article is generated by the Claude API (Anthropic’s claude-sonnet-4-20250514 model). I send a structured prompt that includes the article topic, target keywords, tone guidelines, structural requirements (H2 sections, word count range), and any specific tools or products to cover. The API returns a Markdown draft in roughly 15 to 30 seconds.

The prompts are not generic. I maintain a library of about 40 prompt templates, each tuned for a specific article type — tool reviews use one template, comparison articles use another, opinion pieces use a third. Each template includes the editorial voice guidelines, formatting rules, and component usage requirements. The system prompt alone is about 2,000 tokens. The per-article cost is roughly $0.08 to $0.15 depending on output length.

Editorial Review

AI-generated drafts are not publishable. They are structurally correct but have three recurring problems: they use filler phrases that sound authoritative while saying nothing, they hedge on strong opinions, and they sometimes fabricate details about tools I have not personally tested. Every draft goes through a manual review pass that typically takes 30 to 45 minutes.

During review I verify every factual claim, cut every sentence that could be removed without losing meaning, and replace any paragraph that reads like it was written by a committee. The editorial pass is the bottleneck in the pipeline — it is the only step that cannot be automated, and I spend more time on it than on any other part of the process. A tool review that took 15 seconds to generate might take an hour to edit into something I would stand behind.

The pipeline itself is a set of Bun scripts that handle prompt construction, API calls, draft storage in the Supabase editorial queue, and post-generation formatting. It is not a SaaS product — it is a handful of TypeScript files in the repo that I run from the command line. I built it this way because I wanted to understand every step of the process, and because gluing APIs together is not hard enough to justify paying someone else to do it.

Distribution and Analytics

Once an article is published, three things happen automatically.

Cross-posting. A Cloudflare Worker triggers on the RSS feed update, formats each new article for the target platform, and posts to Bluesky (via the AT Protocol API), dev.to (via their publishing API), and Mastodon (via the Mastodon API). The Worker runs in about 200 milliseconds and costs nothing on the free tier. Each platform gets a slightly different version of the post — Bluesky gets a thread with the key points, dev.to gets the full article with canonical URL pointing back to pickuma.com, and Mastodon gets a short summary with a link.

Analytics. I run Google Analytics 4 for basic pageview tracking, but I also maintain a custom tracking setup that logs affiliate link clicks through Supabase. When a reader clicks an affiliate link, a small JavaScript snippet fires a POST to a Supabase Edge Function, which records the click with the article slug, link destination, and timestamp. This gives me per-article, per-link click data without relying on third-party link shorteners. The Edge Function handles about 200 requests per day and runs well within the free tier’s 2 million monthly invocation limit.

Affiliate link management. Every affiliate link in an article is an MDX component — <AffiliateLink href="..." provider="..."> — that renders as a standard anchor tag but includes a data-affiliate attribute and the provider name. The custom click tracking script listens for clicks on these elements. I do not use a link management service because I do not need one — the site has maybe 50 active affiliate links, and tracking them through a database table is simpler than paying for a dedicated tool.

What It Costs

Here is the actual monthly infrastructure cost for pickuma.com as of May 2026:

ServiceMonthly Cost
Cloudflare Pages (hosting, CDN)$0
Supabase (database, edge functions)$0
Cloudflare Workers (cross-posting)$0
Claude API (article drafting)~$8
Google Analytics 4$0
Domain (pickuma.com, annual)$12/year ($1/month)
GitHub (source hosting, CI minutes)$0
Total~$9/month

The total is under $10 per month. There is no server to provision, no database to scale, and no service that costs more than the domain registration. The Claude API is the only variable cost, and it fluctuates between $6 and $12 depending on how many articles I publish that month.

If the site grows to the point where Supabase’s free tier is insufficient — roughly 50,000 monthly active readers, based on current query patterns — the next step is the Pro plan at $25/month. Cloudflare Pages would remain free until 500 builds per month. I do not expect to need a dedicated server or a CDN upgrade for the foreseeable future.

This is the advantage of building a content site in 2026. The infrastructure that would have cost hundreds of dollars per month a decade ago is now free or nearly free at the scale most independent publishers operate at. The real cost is not the infrastructure — it is the time spent writing, editing, and maintaining quality.

FAQ

Why Astro instead of Next.js? +
Next.js is a React framework that excels at interactive applications with server-side state. Pickuma is a content blog with no interactive state and no client-side routing. Astro ships zero JavaScript by default, which means faster page loads and a simpler mental model. Moving from Next.js to Astro eliminated roughly 180 KB of unnecessary JavaScript from every page load.
Do you disclose AI-assisted articles to readers? +
Yes. Every article that used AI in any part of the pipeline includes `aiAssisted: true` in its frontmatter, and we publish a separate disclosure page explaining exactly how the tools are used. The Claude API generates first drafts that receive 30 to 45 minutes of manual editorial review before publication. Nothing is published without human editing.
How long does it take to publish one article end-to-end? +
Roughly one hour: 15 to 30 seconds for the Claude API to generate a draft, 30 to 45 minutes of editorial review and rewriting, 10 minutes for formatting, cross-linking, and metadata, and about 40 seconds for the Cloudflare Pages build and deploy. The bottleneck is the editorial review — everything else is automated.

Related reading

See all Meta articles →

Get the best tools, weekly

One email every Friday. No spam, unsubscribe anytime.