Skip to main content
ASoc
The ASoc Blog

Guides for shipping faster with Tailwind and Next.js

Practical write-ups from the team that builds the templates — architecture decisions, migration notes, and honest framework comparisons.

Tutorial9 min read

React Loading Spinner: 3 Instances, and 3 More Places That Skip It

Three components spin a Loader2 icon; three more swap button text instead and skip it entirely. The rule that decides between them, audited across this codebase's seven loading states.

Read more
Tutorial8 min read

Tailwind Aspect Ratio: 22 Uses, Zero of Them aspect-video

Why this codebase writes aspect-[16/9] instead, and how the card's ratio has to agree with the img's width, height and the generated file's width.

Read more
Tutorial9 min read

Tailwind Height: 139 Uses, Zero of Them Plain h-screen

This codebase's h-* utilities are mostly icon sizing. The one true viewport lock is h-[100dvh], not h-screen — because a static 100vh lies on mobile.

Read more
Comparison10 min read

Supabase vs Vercel: Both, and 42 Lines Where They Meet

Not alternatives. Vercel builds and serves 584 pages, Supabase holds the schema and the policies, and one 42-line proxy can take the whole site down.

Read more
Tutorial9 min read

React DevTools Shows 24 of This Site's 92 Components

Open the Components tab on an App Router page and the tree looks empty. 68 of 92 components ran at build time and never mount in a browser.

Read more
Tutorial9 min read

React Icons: 12 From a Library, 55 Written by Hand

One icon library, twelve imports, 55 inline SVGs — and the split falls exactly on the client boundary rather than on taste.

Read more
Tutorial9 min read

Tailwind Flex: 6 of 12 Utilities, 296 Call Sites

296 flex-utility call sites across 68 files use 6 of Tailwind's 12 flex classes — the other six, all per-child grow/shrink tuning, are never needed.

Read more
Tutorial8 min read

Next.js UI Library Roundups List Five. This Site Uses Zero.

Zero of shadcn, Radix, MUI, Chakra or daisyUI in this package.json. 92 components run on Tailwind v4 tokens and one enforced import rule instead.

Read more
Tutorial9 min read

E-Commerce in React: The Storefront With No Shopping Cart

This storefront sells 113 products with zero cart code: one Server Action resolves a fixed-tier checkout, and a slot-based entitlement engine replaces the order.

Read more
Guide9 min read

Firebase Hosting Cost, Measured Against a Real 156 MB Build

Firebase bills $0.026/GB stored and $0.15/GB transferred. This storefront's 156.5 MB build uses 1.6% of the free storage tier — transfer is the line that bills.

Read more
Tutorial8 min read

forEach in TypeScript: 4 Uses Against 149 Maps

A census of a real TypeScript codebase: 4 forEach calls, 149 .map() and 137 for...of. What the four have in common, and the async trap that explains the ratio.

Read more
Comparison8 min read

Vite vs. Vue: A Build Tool and a Framework Are Not Alternatives

Vite builds, Vue renders, and most projects use both. The comparison that resolves is Vite vs. Vue CLI — plus which layer to blame when a build breaks.

Read more
Comparison9 min read

SvelteKit vs. Remix: Same Primitives, Different Component Bill

Both answer routing, data loading and form posts the same way. The divergence is what reaches the browser — and how much of a page you can avoid shipping at all.

Read more
Comparison9 min read

Qwik vs. Next.js: Resumability vs. Not Shipping the Component

Qwik ships near-zero JS through resumability; this site's RSC split already does that for 9 of 10 home-page sections. Where the real cost still lands: one accordion.

Read more
Tutorial8 min read

Building an HTML/CSS Navigation Bar (and the Bug That Hides It)

Six ingredients build an accessible nav bar — and this site's own mobile drawer shipped the pointer-events-none bug that leaves closed links keyboard-reachable.

Read more
Tutorial10 min read

Tailwind Font Weight: 9 Named Steps, 4 This Codebase Uses

193 font-weight utility calls across this codebase, spanning only 4 of Tailwind's 9 named steps — traced to two atoms that set the hierarchy once.

Read more
Tutorial9 min read

React + EmailJS: What Ships in Your Bundle vs. a Server Action

EmailJS ships its service ID, template ID and public key in your bundle by design. This storefront's contact form ships none of that — the two files that decide it.

Read more
Tutorial12 min read

DB Schema: Two Meanings, Six Tables, and 271 Lines of Postgres

In Postgres “schema” means both the structure and a namespace. Here is a real commerce schema — 6 tables, 8 migrations, and the four times it had to change.

Read more
Tutorial9 min read

Tailwind Grid: 26 Files, and Not One col-span

A 538-page site's whole grid vocabulary is three utilities — plus the display:contents trick that reorders a product page on mobile without duplicating state.

Read more
Tutorial7 min read

Next.js Turbopack: 13.9s vs. webpack's 18.3s, Same Commit

A measured head-to-head on 538 pages, plus the config trap: Turbopack serializes options to Rust, so an imported MDX plugin now fails the build outright.

Read more
Comparison8 min read

shadcn vs. Tailwind Is a Category Error (One Runs on the Other)

92 components, 13 runtime dependencies, zero UI libraries — what hand-rolling actually cost this codebase, and the seven components shadcn would have handed over.

Read more
Comparison8 min read

Vitest vs. Jest: 11 Lines of Config and 331 Tests in 2.48s

Measured on this repo: 31 files, 331 tests, 2.48s — and the `environment 3ms` line that explains most of the Vitest-versus-Jest gap.

Read more
Tutorial9 min read

React Dropdown: The Two Defects a useState Toggle Ships With

A production dropdown, defect by defect: why one `open` boolean breaks the click, and why the 8px gap has to be padding rather than margin.

Read more
Comparison9 min read

SolidJS vs. Next.js: You're Comparing the Wrong Two Things

SolidStart is the real comparison. 24 of 92 component files here ship client JS — the number that decides fine-grained reactivity against RSC.

Read more
Tutorial9 min read

React Images: 26 `<img>` Tags and Not One `import`

1,160 image files, zero imported ones. The import-vs-string-path choice is really a choice about who verifies the path — and what you have to build once the bundler stops.

Read more
Tutorial8 min read

The Latest Next.js Version Is 16.3.4. This Repo Runs 16.2.9.

npm carries sixteen dist-tags for `next` and `latest` is only one of them. Which version to be on, measured from a repo that pins the framework and ships it to other people.

Read more
Tutorial9 min read

React Hooks: Why This Codebase's `useContext` Count Is Zero

24 useState, 13 useEffect, 0 useContext across 22 files — a real hook census, and the module-scope store pattern this codebase uses instead of Context.

Read more
Tutorial9 min read

HTML `<textarea>`: Auditing the Only One in This Codebase

One real <textarea> across 111 products, a honeypot beside it, and a silent mismatch between the field's missing maxlength and the server's 5,000-char cap.

Read more
Comparison8 min read

esbuild vs. Vite: What This Repo's Own Lockfile Says

Neither is a dependency here — but the Vite version vitest pulls in has already dropped esbuild for Rolldown, proven straight from the lockfile.

Read more
Tutorial9 min read

Web Accessibility Tools: Which Ones Caught This Site's Real Defects

Accessibility 100 on all 8 pages, and two real defects no scanner flagged. Four defects sorted by which tool found them — and why two were structurally invisible.

Read more
Guide9 min read

Is Tailwind CSS Worth It? 881 Class Attributes, One 78 KB File

Answered with three measurements instead of taste: 133 hand-written lines, 14 KB gzipped across 488 pages, and the AA contrast bug the token scale made easy to ship.

Read more
Comparison9 min read

Vite vs. Webpack: 488 Pages Built by a Repo Running Neither

Most comparisons assume you pick a bundler. On a framework you inherit one — and the two config lines this codebase writes anyway are where the real difference shows.

Read more
Tutorial8 min read

What's Actually in a Data Dashboard? 59 Views, Counted

9 admin templates, 59 dashboard views, audited from the catalog — what a coded data dashboard actually contains versus a BI tool.

Read more
Comparison8 min read

Vercel vs. DigitalOcean: What Owning the Server Actually Costs

Two Route Handlers, zero Dockerfiles, zero nginx configs — what this storefront's own deploy setup says about Vercel vs a DigitalOcean Droplet.

Read more
Tutorial8 min read

What Actually Builds a Landing Page? Ten Organisms, One Cut

Ten organisms, one deliberately unmounted, and a real LCP image bug — what actually builds a landing page, audited from the source file.

Read more
Tutorial8 min read

Is React a Framework? 110 of 139 Editions Say Next.js

React ships no router, no data layer, no build step and no server. Settled with inventory: 139 framework editions across 111 products, and the 9 built twice.

Read more
Tutorial8 min read

What Is a Web Page Template? Two Products Share the Word

A hosted design you edit in a builder, and a source repo you own, are both called templates. What is actually inside one, from a catalog of 111.

Read more
Tutorial8 min read

What Is Supabase Used For? Four Things, in One Real App

Four things, precisely: auth, row-level authorization, private storage, atomic writes -- including the rate-limit race this app actually hit and fixed.

Read more
Comparison8 min read

React vs. Gatsby: The Real Question Is the GraphQL Layer

Gatsby adds a GraphQL data layer on top of React. This catalog imports typed data directly instead, with zero GraphQL and zero content plugins.

Read more
Comparison9 min read

Tailwind vs. CSS: 139 Components, One 133-Line Stylesheet

139 components, 881 classNames, one 133-line stylesheet: the exact 40 lines of hand-written CSS a Tailwind codebase still needs, and why.

Read more
Guide8 min read

Website Template Copyright: What You Own, What You Don't

Buying a template never transfers copyright in its code. What you actually own, plus the hardcoded footer year this codebase shipped unfixed for a month.

Read more
Tutorial9 min read

Next.js Link: 40 of Them, and 22 CTAs the Lint Rule Cannot See

no-html-link-for-pages reads literal hrefs on raw anchors, so it never saw this site's button atom. Plus the internal URL that must stay an anchor: /api/download.

Read more
Tutorial9 min read

Tailwind Button: 15 Utilities, 3 Variants, and Zero Buttons

The component called Button renders a link all 22 times it is used, while 44 real button elements sit elsewhere. The full class list, and the disabled state it was missing.

Read more
Tutorial10 min read

React Focus Trap: Two Dialogs Claimed aria-modal, One Meant It

An audit of four overlay surfaces: the wishlist panel that let Tab walk out of a modal dialog, the off-screen drawer pointer-events-none never hid, and the iframe case.

Read more
Comparison9 min read

Supabase vs PlanetScale: 7 Foreign Keys Into a Table MySQL Doesn't Have

The dialect differences port. The 7 foreign keys into auth.users and 6 policies built on auth.uid() don't — inventoried line by line from this storefront's 8 migrations.

Read more
Tutorial8 min read

Supabase SQL Editor: This Schema Has Never Been Edited Through It

Studio's SQL Editor is built for one-off queries. Every schema change here shipped instead as one of 8 reviewed migration files — what each tool is actually for.

Read more
Tutorial8 min read

React Multi-Step Forms: 1 of 5 Form Components Here Needs One

Most tutorials assume a step-index useState pattern by default. This codebase's one real example is two states confirming an irreversible choice, not more fields.

Read more
Comparison9 min read

Next.js vs. Nuxt: 24 of 92 Components Opt Into the Client

Not React versus Vue — the real split is where each framework lets you draw the server/client boundary. Next.js draws it through the import graph; Nuxt's default is universal.

Read more
Tutorial10 min read

Email Signup Landing Pages: Where the Capture Point Actually Goes

Squeeze-page advice says strip the page to one form. Only 14 of 66 landing templates in this catalog do — audited against this storefront's own single, sitewide capture point.

Read more
Comparison9 min read

Astro vs. Remix: Two Opposite Rendering Defaults

Astro assumes a page is static until a component opts in; Remix assumes a route is a server request until it opts out. This build's own 452-static/8-dynamic split shows why that matters.

Read more
Tutorial10 min read

Is Webflow Good for Ecommerce? What the SKU Cap Actually Costs

Webflow's ecommerce plans cap items and charge a transaction fee on top. This storefront's entire commerce stack — entitlements, checkout, webhook — is 843 lines with no cap at all.

Read more
Tutorial10 min read

How to Learn Next.js by Reading a Real, Shipped Codebase

Courses teach the Next.js API in isolation. This walkthrough traces one real request through five actual files in a shipped storefront, linking to deeper audits at every stop.

Read more
Tutorial10 min read

Next.js on AWS: Amplify, Lambda, ECS or EC2 — 8 Routes Decide It

Amplify, Lambda via SST, ECS Fargate, or EC2 — AWS has no framework-aware default. This build's own 428 static and 8 Node-runtime dynamic routes decide which compute layer actually fits.

Read more
Comparison10 min read

Angular vs. Svelte: 7 of 24 Client Components Need No State At All

DI-injected signals versus a build-time compiler. Both assume a component needs a reactive primitive — 7 of this codebase's 24 Client Components prove a third of the time, it doesn't.

Read more
Tutorial10 min read

What Is a Tailwind Class? 658 className Attributes, One Compiler Rule

A Tailwind class is a compiler-generated CSS rule that only exists because a literal string appeared in your source. Audited from 658 className attributes and 91 components.

Read more
Tutorial10 min read

next-seo Is Obsolete: 28 Native Metadata Declarations, Zero Package

next-seo is a Pages Router package the native Metadata API replaced in Next 13. Zero dependency here, 28 metadata sources across 27 pages — the full migration mapping.

Read more
Comparison10 min read

React vs. Bootstrap: 74 KB of CSS for 420 Routes, Zero jQuery

React is a UI library, Bootstrap a CSS framework — the real fork is Tailwind vs. Bootstrap, measured against this site's single 74 KB stylesheet and zero jQuery dependency.

Read more
Tutorial10 min read

Next.js Error Monitoring: 41 console.error Calls, Zero APM

No Sentry, no instrumentation.ts — 41 structured console.error calls, an ALERT-marker convention, and the error-hygiene test that keeps server detail out of the browser.

Read more
Tutorial9 min read

Robots.txt and Sitemap.xml in Next.js: One Declared Date, 420 Routes

The STOREFRONT_COPY_REVISED fix for a sitemap that told Google 111 pages changed on a date nothing did, plus the noindex-vs-disallow split this codebase actually uses.

Read more
Tutorial12 min read

Next.js Routing: 27 Page Files, 412 URLs, Three Conventions Unused

A census of one production app/ tree: which of the nine reserved filenames actually earn a file, and the 40 links, 13 redirects and 2 routers that move between them.

Read more
Tutorial11 min read

Next.js Error Boundaries: One File, and a Digest Nothing Read

One error.tsx covering 27 page files, no global-error.tsx, and a digest the boundary declared but discarded — the audit, and both fixes that shipped with this post.

Read more
Tutorial10 min read

Next.js Currency Formatting: Four Renderings, One That Lied

Four ways to print money in one codebase, and the fallback that stamped a dollar sign on any currency Intl could not parse. The audit, the fix, and the locale rule.

Read more
Guide9 min read

Next.js License Key: Why This Storefront Doesn't Have One

No key field anywhere in this codebase's entitlement types — ownership is a database row scoped to a session, checked fresh on every download.

Read more
Tutorial9 min read

HTML Nav: The Element, Not the Layout

A real production nav, from a 4-item desktop bar to a slide-out drawer — the aria-expanded toggle, the z-index stacking, and what a div-only navbar loses.

Read more
Tutorial9 min read

Collapsible HTML: Why This Codebase Skips the Details Element

Zero details elements across 91 components, and the CSS grid-template-rows trick FaqItem uses instead — plus when the native element is the right call.

Read more
Tutorial10 min read

A Podcast Landing Page Is a Registry, a Feed, and One CSP Line

Episodes belong in a typed registry, the feed is the actual product, and the player embed renders blank unless your Content-Security-Policy names its host.

Read more
Tutorial9 min read

Best SaaS Landing Pages: What 17 Real Templates Actually Ship

Not a gallery — a section-by-section census of 17 SaaS landing templates. Pricing, testimonials and integrations each appear in 10 of 17; the median product is 11 pages.

Read more
Comparison9 min read

Vercel vs Cloudflare Pages: Count the Routes That Need a Runtime

414 prerendered pages any CDN serves the same way, 8 dynamic routes, and exactly 2 that pin the Node runtime for node:crypto. Those two lines are the whole decision.

Read more
Tutorial7 min read

A Next.js CI Pipeline in 23 Lines, Timed Step by Step

Real per-step timing from a production run — 100 seconds total, cheapest checks first, no separate typecheck step because next build already does one.

Read more
Comparison7 min read

Vercel vs. AWS Amplify: The Bundled Backend Is the Real Question

13 runtime dependencies, zero AWS SDK packages, and a build that splits 392 static pages from 8 dynamic routes with no deployment config authored for either.

Read more
Comparison7 min read

Sass vs. Tailwind: 133 Lines and One Arbitrary Selector

Sass's four features, checked one at a time against this codebase's real @theme block, group-hover usage, and the single [&_selector] Tailwind still reaches for.

Read more
Tutorial10 min read

React Landing Pages: Half the HTML Isn't the Page

This storefront's home page prerenders to 436 KB, and 52.1% of that is a serialized copy of the render, not the page. What actually reaches a crawler before any JavaScript runs.

Read more
Guide10 min read

Landing Page Cost: The Page Is the Cheapest Line Item

The build is the smallest number in the project. Priced from a real page: ten components and 1,256 words, then four attachments and the two assets no licence includes.

Read more
Tutorial9 min read

Tailwind Design Tokens: 41 Declared, 22 Values That Went Around Them

41 tokens across three of Tailwind v4's 19 namespaces, and 161 utilities that spell a value literally instead. 22 of those literals were already a token in the same stylesheet.

Read more
Tutorial10 min read

React Form Validation: The Allowlist Is the Validation

Client-side checks are UX. The server-side function that reads three named fields and ignores everything else — proven by a test that smuggles in a fake user_id — is the actual gate.

Read more
Tutorial9 min read

Next.js Route Groups: Why This 24-Route App Uses Zero

Route groups hide a folder from the URL. Every one of this app's 24 top-level folders needs to be in the URL — which is the exact case they're not for.

Read more
Comparison10 min read

Vercel vs. Render: Does Anything You Run Need to Stay Running?

Two Route Handlers, both stateless, neither overriding the default timeout — versus a release script that clones, installs, and boots for minutes. That split is the real decision axis.

Read more
Tutorial9 min read

React Suspense: 376 Prerendered Pages, Zero Boundaries

Suspense buys streaming, and a page rendered at build time has nothing left to stream. Zero boundaries and zero loading.tsx here, plus the useSearchParams de-opt everyone reports wrong.

Read more
Tutorial9 min read

Auth in React: The Session Belongs in a Cookie, Not in Context

Six Server Actions, a 68 KiB auth SDK kept out of every initial bundle, and one line that decides the whole security posture: getClaims(), never getSession().

Read more
Comparison9 min read

Supabase vs Prisma: An ORM Cannot See Your Row-Level Security

Point Prisma at a Supabase database and your policies stop working — in one of two directions, neither the one you wrote. Our own six policies, audited against that.

Read more
Tutorial8 min read

Next.js Charts: The Bill Isn't the Library, It's the Boundary

Every chart library is a client component. What that actually costs, measured here: 42 KB gzipped across twelve routes, from a five-line constant nobody suspected.

Read more
Comparison8 min read

Next.js vs. Vue: The Reactivity Primitive You Don't Need

Vue's Composition API needs ref/computed for every stateful value, server or client. This storefront's 13 dependencies carry zero state library — here's why.

Read more
Tutorial8 min read

Next.js Pagination: The Threshold This Blog Blew Past by 3x

This codebase paginates nothing — /blog still renders 106 posts on one page, 3.5x past its own stated 30-post threshold. The searchParams pattern for when it's real.

Read more
Tutorial8 min read

Next.js Testing: 305 Tests, Zero Rendered Components

31 test files, zero jsdom, zero @testing-library — every assertion is a data invariant or a security boundary. What that catches, and what it can't.

Read more
Comparison8 min read

React vs. Remix: A Mismatched Pairing, and the Real Question

Remix runs on React — they aren't competitors. The real comparison is Next.js vs. React Router v7, and it comes down to which way the static default points.

Read more
Tutorial10 min read

React Toast Notifications: Five Live Regions That Announced Nothing

Zero toast libraries and five aria-live regions here — all five mounted with their first message, so none of them ever announced. The audit, and the atom that fixed it.

Read more
Tutorial10 min read

Next.js Trailing Slash: The Config Isn't Your Problem, the Env Var Is

344 prerendered routes, zero trailing slashes, and no trailingSlash config at all. The bug that did reach production came from one env var, and the one-line fix it now has.

Read more
Guide9 min read

Should I Hire a Web Designer? Six Defects a Comp Cannot Contain

Hire for direction, not for pictures of a decision you already made. Six real defects found on a site scoring accessibility 100 — none of them visible in any comp.

Read more
Comparison9 min read

Supabase vs. Convex: A Lock You Write vs. a Transaction You Get

Convex's transaction model would have prevented a real TOCTOU race this storefront hit in its Postgres download limiter. Why that's true, and why the fix stayed on Supabase anyway.

Read more
Tutorial8 min read

A Waitlist Landing Page Is One Server Action and a Honeypot

This storefront's real waitlist form: the Resend Audience API's deprecated field a copy-pasted snippet would miss, and firing one analytics event per successful subscribe, not per render.

Read more
Tutorial8 min read

Next.js Intercepting Routes: Why This Codebase Has Zero

Intercepting routes mask navigation to a route in your own app. This storefront's live-preview modal shows a cross-origin iframe instead — a real reason the pattern never fit here.

Read more
Comparison8 min read

Vercel vs. GitHub Pages: 344 Static Pages, 8 That Need a Server

GitHub Pages has no compute layer at all — not slower, absent. A fresh build of this storefront counts exactly which routes that categorically rules out, and why it isn't a rendering-mode question.

Read more
Tutorial12 min read

Tailwind Max Width: 62 Usages, 57 Arbitrary, and 96 Lost Pixels

max-w-* reads the --container-* scale in v4, and max-w-md is 448px, not 768px. A census of 62 usages here, plus the viewport band where our layout narrows as it widens.

Read more
Guide12 min read

Website Development Cost: Price the Artifacts, Not the Pages

332 prerendered routes from 27 page files. Why a per-page quote is unplannable, and the three line items estimates leave out: verification, the post-launch rework pass, content.

Read more
Comparison8 min read

Next.js vs. Angular: A Function Call vs. a DI Container

Angular needs a DI container before a component can fetch anything; a Next.js Server Component just calls a function. Measured from this storefront's 334-page static build.

Read more
Tutorial7 min read

React Lazy Loading: This Codebase Uses Zero React.lazy() Calls

This codebase has zero React.lazy() calls. What it actually lazy-loads — an explicit per-post import map and a conditional SDK import — and why that distinction matters.

Read more
Tutorial7 min read

A Next.js Calendar Grid, and the Timezone Bug It Has to Avoid

No calendar UI here, but this codebase already fixed the timezone bug that breaks most of them, twice. The UTC-safe date pattern, applied to a month grid.

Read more
Comparison11 min read

Gumroad Alternative: The Six Jobs You Take Back In-House

A hosted storefront does six jobs. Another one changes the fee; owning your storefront takes them back as code — 1,607 lines here, file by file.

Read more
Comparison9 min read

Next.js vs SvelteKit: Where a Write Is Allowed to Live

Bundle size is the wrong axis for a meta-framework choice. The real divide is routing defaults and whether a mutation can live anywhere or only on the route that owns it.

Read more
Comparison10 min read

Supabase vs Neon: Both Are Postgres, So the Database Isn't the Call

Six RLS policies, all built on auth.uid() — a function Postgres does not have. An audit of exactly which of our own code depends on the platform rather than the database.

Read more
Tutorial10 min read

The Next.js Bundle Analyzer Doesn't Run on Turbopack. Here's What Does.

ANALYZE=true writes nothing in Next 16, and the route table no longer prints First Load JS. The replacement, where it hides its output, and the 42 KB one constant was costing twelve routes.

Read more
Tutorial9 min read

Next.js Rewrites: Three Phases, and the Four We Turned Down

318 pages and zero rewrites, with the compiled manifest to prove it. What each phase beats, why our seven hub pages stayed files, and the 308 redirect nobody configured.

Read more
Tutorial9 min read

React Protected Routes: What a Server-Rendered Guard Does Differently

React Router's client-side wrapper isn't the only pattern. This codebase's redirect guard runs on the server, plus the open-redirect check most tutorials skip on the ?next= param.

Read more
Tutorial9 min read

A Tailwind Data Table Audit: One Real Table, Two Real Defects

The only <table> in this codebase, read cell by cell: what it gets right, the missing caption and text-free checkmarks it shipped with, and the fix.

Read more
Comparison8 min read

Playwright vs Vitest: Why This Repo Runs Both for Unrelated Jobs

Vitest is a committed dependency gating 305 tests on every push. Playwright is deliberately not a dependency at all — installed ad hoc for a script that runs a few times a year.

Read more
Tutorial9 min read

Tailwind Container Queries: One @container, Zero Queries

Our own home page had the container context and none of the queries — so a card loses a third of its width at lg while its padding never moves. The arithmetic and the fix.

Read more
Tutorial10 min read

A React Sidebar in 60 Lines and Zero JavaScript

Sticky positioning without a scroll listener, aria-current for the active row, and the hard-coded active-state bug that only appears when you add a second page.

Read more
Tutorial9 min read

React Tooltip: When 38 aria-label Attributes Beat a Library

38 aria-label attributes, zero tooltip libraries. What this codebase actually uses to name icon-only buttons, and the one place a real tooltip earns its keep.

Read more
Tutorial8 min read

Next.js Redirects: Three APIs, and Why We Use Two of Them

Thirteen redirects, eight files, zero next.config.ts entries. Why every redirect() call here depends on auth state config-based redirects cannot see.

Read more
Tutorial12 min read

React Tabs: Six Requirements, and the Three Ours Was Missing

Our dashboard tabs had the roles and none of the wiring — no aria-controls, no tabpanel, no roving tabindex. The audit, why no scanner caught it, and the fix that shipped with this post.

Read more
Tutorial11 min read

Tailwind v4 Dark Mode: We Wrote 480 Variants and Shipped No Toggle

One @custom-variant line replaces darkMode: 'class'. Then you choose: dark: at every call site, or tokens under .dark. We picked the first 480 times — and found nothing can turn it on.

Read more
Guide12 min read

Ecommerce Site Cost: Four Decisions, Not a Quote

Agency guides price the build. The recurring bill is set by four architectural choices — and here they are itemised from a live storefront: 111 products, 288 static pages, 13 dependencies.

Read more
Comparison8 min read

Supabase vs MongoDB: The Question Isn't the App, It's the Dataset

Our 8,114-line, 111-product catalog is document-shaped — and lives in a typed array, not a database. The commerce layer is relational, on Postgres. Why the split decides, not the app.

Read more
Tutorial7 min read

Next.js Docker: The Standalone Output and the Env Var That Bites

output: "standalone" keeps the image small; the trap is that NEXT_PUBLIC_ vars are baked in at build time, not read at container start. This repo's own env-var warning shows exactly why that matters.

Read more
Tutorial7 min read

React UI Libraries: When Hand-Rolling 91 Components Actually Wins

This storefront ships zero UI-library dependencies across 91 hand-rolled components. The real tradeoff — bundle cost against accessibility coverage you skip rebuilding — measured against our own code.

Read more
Comparison7 min read

One-Time Payment vs Subscription: What the Webhook Handler Has to Know

Our entitlement engine is 75 lines with two status states; our LemonSqueezy webhook recognizes two event names. That's not a shortcut — it's the real cost gap between the two pricing models.

Read more
Tutorial11 min read

A/B Testing in Next.js 16: The Proxy Recipe Costs the CDN, Not SSG

Rewriting in middleware does not make your pages dynamic — both variants stay prerendered. What it really costs is the shared cache and every request's critical path.

Read more
Tutorial8 min read

Next.js Deployment: The Env-Var Mistake That Breaks Every Page

Static export can't run middleware, a restart isn't a rebuild, and a missing env var in a proxy file breaks the whole site on first request. Our own go-live checklist.

Read more
Tutorial8 min read

Real Estate Landing Pages Need One Section Generic Advice Skips

A filterable listings grid, agent profiles, and a valuation funnel — not a demo request. What a real-estate landing template actually ships, using our own catalog as the reference.

Read more
Tutorial8 min read

Skipping React Hook Form: What Four Real Forms Look Like Without One

Login, signup, password reset and contact all run on FormData, a Server Action and useActionState — zero form libraries in package.json. Here's the actual validation code.

Read more
Tutorial8 min read

React Modal, Zero Dependencies: The Iframe Focus Bug We Fixed

A real accessible React modal with zero dependencies — focus trap, ARIA dialog role, restore-on-close, and the iframe-focus-escape bug most modal libraries never mention.

Read more
Comparison9 min read

The Auth0 Alternative for a Postgres-Backed Next.js Stack

Six RLS policies, all for select, zero write policies anywhere. What authorization looks like when it's a property of the table instead of a service beside it.

Read more
Tutorial8 min read

React Carousel: Two Patterns, Zero Dependencies, One Bug We Fixed

A passive CSS marquee and a navigable translated-track gallery, both dependency-free — plus the missing prefers-reduced-motion guard this audit found and fixed.

Read more
Tutorial8 min read

We Grepped Our Own Meta Tags. 29% of Titles Ran Long.

187 prerendered pages, checked against the build output rather than the pattern: title and description lengths, what generates them, and where the trade-off is deliberate.

Read more
Guide11 min read

A Website Launch Checklist Where Every Item Is a Command

Five commands, three greps, and the defects they caught on a site that already looked finished — including a licence page selling a tier that no longer existed.

Read more
Tutorial10 min read

An RSS Feed in the App Router, Without an RSS Library

One route file, force-static, and eight lines of helpers. RFC-822 dates, five escaped characters, and the absolute-URL bug that reached our production markup.

Read more
Comparison11 min read

Monorepo vs Multi-Repo: 110 Products Across 113 Repositories

Choose by the boundary the customer receives, not by code sharing. The cost is not merging — it is the generated index, and ours already had four bad rows.

Read more
Guide11 min read

A Lighthouse Accessibility Score of 100 Is Not WCAG Conformance

The score is a claim about one URL. Three defects our own audit found only by measuring every page, three more no scanner reports, and a ten-minute test you can run before buying.

Read more
Tutorial12 min read

Automated Product Screenshots with Playwright, 111 Templates Deep

The capture is four lines; deciding what is in frame is the work. Nav-driven page discovery, the is-this-the-product check, and the proxy bug that blanks every Chromium request.

Read more
Tutorial12 min read

Generative Engine Optimization: Building a Site AI Answers Can Cite

An audit of our own site against the standard, including the two places it falls short and the checklist item we deliberately do not ship. The unit of success is a passage, not a page.

Read more
Guide12 min read

Atomic Design in Next.js: The Import Rule That Does the Real Work

Naming five layers changes nothing. Ordering their imports changes everything — including where the client boundary lands, which on this site was never designed at all.

Read more
Tutorial11 min read

Next.js 16 Renamed Middleware to Proxy: What Changes and What Breaks

Renaming the file is a third of the migration. The exported function has to change too, keeping both files is a build error, and the proxy runs on Node rather than the Edge.

Read more
Comparison12 min read

WordPress vs Next.js for a Marketing Site: The Honest Comparison

Most comparisons pit a WordPress theme against a from-scratch Next.js build. Compare theme to template instead and the real trade turns out to be who edits the copy.

Read more
Tutorial13 min read

Programmatic SEO in Next.js: Derive the Pages, Don't List Them

A hand-maintained slug list left 24 of our products on no category page at all, and nothing failed. Here is the derived hub-and-spoke build that fixed it.

Read more
Guide13 min read

A Digital Product Refund Policy You Can Enforce in Code

A 14-day, no-download refund policy and the four-state engine behind it — including the attribution 'fix' that opens a download-then-refund bypass.

Read more
Tutorial11 min read

Storefront Search Without a Search Service

111 products, no search index. The predicate, the rule that stops results looking broken, and the bundle trade we took on one page only.

Read more
Comparison10 min read

Vercel Analytics vs Google Analytics 4: The Consent Banner Decides It

A banner-gated tool measures the subset of visitors who agreed to be measured. The cookieless trade, the typed event union, and the CSP origin we nearly added for nothing.

Read more
Tutorial13 min read

Gated File Downloads in Next.js: The Order the Checks Must Run In

Authenticate, verify, validate, authorize, rate-limit and record — then sign. The atomic limiter that closes the count-then-insert race, and what fails closed versus open.

Read more
Tutorial11 min read

Persisting UI State in localStorage Without a Hydration Mismatch

Prerendered HTML cannot know what one browser saved. An empty server snapshot, the getSnapshot cache that stops an infinite render loop, and why theme is the opposite problem.

Read more
Guide11 min read

How to Evaluate a Website Template Before You Buy: 10 Checks

Judge it on what you cannot fix after buying. Run Lighthouse on mobile, audit the inner pages, count the routes that actually exist — and read the licence for seats, not domains.

Read more
Tutorial10 min read

A Next.js Content Security Policy That Keeps Static Rendering

The documented nonce recipe turns every route it touches dynamic. The static-safe policy we ship instead, what 'unsafe-inline' really costs, and what the header still blocks.

Read more
Comparison10 min read

MDX vs a Headless CMS: Choosing by Who Writes the Posts

An editorial-workflow decision wearing an architecture decision's clothes. What MDX buys you in CI, the Turbopack plugin trap, and the four cases where a CMS simply wins.

Read more
Tutorial11 min read

A Product Image Gallery in Next.js That Google Can Actually See

Virtualizing a four-slide carousel removes three product images from the HTML. Mount every slide, starve the off-screen ones, and the ARIA that a carousel actually needs.

Read more
Guide10 min read

React vs Next.js Template Editions: Which One to Start From

Every other comparison asks which framework to build in. This asks which folder to open after you have bought the design — and why the licence usually covers both.

Read more
Comparison12 min read

Supabase vs Firebase for a Template-Based SaaS

Authorization is where they differ most and what you cannot change later. Row-Level Security vs Security Rules, the Server Component fit, and the 68 KiB our own auth SDK cost.

Read more
Guide13 min read

Migrating a Marketing Site to Next.js Without Losing Rankings

Change the technology or the URLs, never both. The redirect map, the internal-link diff that put 38 of our own pages in “Discovered — not indexed”, and the 90 days after.

Read more
Tutorial11 min read

An Accessible Mega Menu in Next.js Without a Headless UI Library

It is a navigation landmark, not an application menu — and the ARIA menu pattern most tutorials copy removes your nav from every screen reader's link list. Six behaviours, eighty lines.

Read more
Tutorial12 min read

Data Tables in Next.js: Virtualizing 10,000 Rows Without Losing the Server

Virtualization forces the table into a Client Component and hands back the sorting, filtering and accessibility the server did for free. The three options, and the hybrid worth using.

Read more
Comparison11 min read

Shopify vs a Next.js Storefront: What You Actually Inherit

Shopify's fee buys a checkout, tax handling and an ops backend — not hosting. The four jobs you take on by leaving, the headless hybrid, and when owning the frontend pays.

Read more
Comparison10 min read

Astro vs Next.js for a Marketing Site: We Measured the Difference

Both score 100 on desktop. We blocked every image on our own site and LCP moved 46ms — the mobile gap is React hydration, not bytes. What that means for the choice.

Read more
Tutorial12 min read

Product Variants in Next.js Without a Commerce Backend

Size and colour variants render fine from a typed file — until stock has to be authoritative. The option matrix, the URL-driven picker, the canonical, and where it breaks.

Read more
Tutorial13 min read

Next.js Image Optimization Without next/image: 255 KiB to 33 KiB

A closed image set does not need a request-time optimiser. The sharp build script, the plain-img markup, and the lazy LCP image that cost us 1.67s of load delay.

Read more
Comparison10 min read

Webflow vs Next.js for a Landing Page: How to Actually Decide

The launch-speed argument mostly disappears once you compare template to template. What is left is who edits the copy, what each locks in, and three cases where Webflow wins.

Read more
Tutorial11 min read

A Next.js Contact Form with Server Actions, Zod and Resend

No API route, no client fetch, and it still submits with JavaScript off. Validation, a honeypot, a rate limit that survives serverless, and the from-address trap that kills deliverability.

Read more
Tutorial11 min read

Dynamic Open Graph Images in Next.js with ImageResponse

A metadata route under a dynamic segment needs its own generateStaticParams, or every card renders per request. That trap, the Satori CSS subset, fonts, and how to verify a crawler sees it.

Read more
Tutorial11 min read

Scroll-Driven Animations in Tailwind v4 Without a JS Library

animation-timeline replaces the scroll-animation library category — behind two guards. The Tailwind v4 setup, the element you must never fade in, and when IntersectionObserver still wins.

Read more
Tutorial11 min read

Shopping Cart in Next.js 16: Where Cart State Should Live

A cookie, a database row, or React Context? The three cart architectures compared, the add-to-cart Server Action, and the badge that quietly breaks static rendering.

Read more
Tutorial10 min read

Product Filtering in Next.js: Why Filters Belong in the URL

Filters in useState cannot be shared, bookmarked, or server-rendered. How to read them from searchParams — and which filtered URLs to let Google crawl.

Read more
Tutorial9 min read

Product Schema in Next.js: JSON-LD That Earns Rich Results

Product needs only one of offers, review or aggregateRating — so a truthful offer qualifies you without inventing reviews. The shape, the validation, the manual-action trap.

Read more
Guide9 min read

Template vs Building From Scratch: An Honest Cost Breakdown

Four to nine weeks of UI work sits between an installed framework and a presentable app. What a template saves, what it does not, and when building wins.

Read more
Comparison12 min read

Next.js App Router vs Pages Router: Which to Use in 2026

The App Router is the default for new projects, but the Pages Router is not deprecated. Here is what actually changed and when migrating is not worth it.

Read more
Tutorial11 min read

Multi-Tenant Theming with Tailwind CSS v4 and CSS Variables

Tailwind v4 tokens compile to real CSS custom properties, so one build can serve every tenant's brand. The override pattern, contrast handling, and the pitfalls.

Read more
Tutorial12 min read

Building a SaaS Landing Page in Next.js 16 That Loads Fast

Static rendering, LCP on the hero, and a small client bundle — plus the accessibility bugs our own Lighthouse audit caught that code review missed.

Read more
Tutorial12 min read

How to Build an Admin Dashboard with Next.js 16 and Tailwind CSS v4

A working admin dashboard in Next.js 16 and Tailwind CSS v4 — App Router layouts, a CSS-first theme, an accessible sidebar, and the server/client split that keeps it fast.

Read more
Comparison11 min read

Next.js vs React + Vite for Admin Dashboards: How to Choose

Both ship excellent dashboards. The decision comes down to where your data lives, whether you need SEO, and who deploys it — not to raw performance.

Read more
Comparison10 min read

Tailwind CSS v4 vs Bootstrap 5 for Dashboard UIs in 2026

A fair comparison of two mature CSS frameworks for admin UIs — component coverage, customization ceiling, bundle size, and the team each one suits.

Read more