In an era where web applications are bloated with multi-megabyte JavaScript bundles, aggressive analytics, and intrusive tracking scripts, building for the Small Web and IndieWeb feels like a breath of fresh air.
If you are building a privacy-first side project or simply want your stack to load in under 300ms, combining Next.js (App Router) with Supabase is one of the most effective solutions.
In this tutorial, we will break down how to design a zero-tracking, sub-second web architecture, using Ask A Monk—a quiet, algorithm-free digital sanctuary—as our real-world case study.
- Core Architecture Philosophy To achieve sub-second page loads and complete privacy, we adhere to three technical principles:
Zero External Tracking: No Google Analytics or heavy client-side SDKs.
Minimal Client Bundle: Leverage React Server Components (RSC) to push execution to the edge.
Anonymous Supabase Auth & RLS: Handle asynchronous user interactions securely without demanding personal data.
- Optimizing Next.js App Router for Sub-Second Loads Server Components First
Keep pages as React Server Components (RSC) by default. Only isolate interactive elements into small client modules using 'use client'.
TypeScript
// app/page.tsx - Fully Server-Rendered
import { QuietThoughtFeed } from '@/components/QuietThoughtFeed';
import { SubmitForm } from '@/components/SubmitForm';
export const revalidate = 60; // Incremental Static Regeneration (ISR)
export default async function HomePage() {
return (
<main className="max-w-xl mx-auto px-4 py-12">
<h1 className="text-2xl font-serif">Ask A Monk</h1>
<p className="text-neutral-400 mb-8">An algorithm-free quiet space.</p>
{/* Interactive Client Component */}
<SubmitForm />
{/* Server Rendered Feed */}
<QuietThoughtFeed />
</main>
);
}
Payload Reduction
Use @next/font to self-host variable fonts.
Rely on minimal Tailwind CSS with pre-purged unused utilities.
- Privacy-First Supabase Architecture & RLS Anonymous Database Schema
Here is a simplified PostgreSQL schema with Row Level Security (RLS) for anonymous posts:
SQL
-- Create anonymous thoughts table
CREATE TABLE public.thoughts (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
created_at TIMESTAMP WITH TIME ZONE DEFAULT timezone('utc'::text, now()) NOT NULL,
content TEXT NOT NULL CHECK (char_length(content) <= 6000),
is_public BOOLEAN DEFAULT true NOT NULL
);
-- Enable Row Level Security
ALTER TABLE public.thoughts ENABLE ROW LEVEL SECURITY;
-- Allow public read access
CREATE POLICY "Allow public read access"
ON public.thoughts FOR SELECT
USING (is_public = true);
-- Allow public insert
CREATE POLICY "Allow public insert"
ON public.thoughts FOR INSERT
WITH CHECK (true);
Lightweight Supabase Client Setup
Instantiate the Supabase client without session bloat:
TypeScript
// lib/supabase.ts
import { createClient } from '@supabase/supabase-js';
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!;
export const supabase = createClient(supabaseUrl, supabaseAnonKey, {
auth: {
persistSession: false, // Disables local storage session bloat for anonymous visitors
},
});
- Real-World Case Study: Ask A Monk We put these exact performance and privacy principles into practice with Ask A Monk.
First Contentful Paint (FCP): < 0.3s
Total Blocking Time (TBT): 0ms
Lighthouse Score: 100 / 100 (Performance, Accessibility, Best Practices, SEO)
Bundle Size: < 45KB Gzipped
Instead of harvesting user metrics or building addictive feedback loops, Ask A Monk provides a distraction-free environment for human reflection, demonstrating that modern web dev doesn't need heavy trackers to be functional and meaningful.
Conclusion
Building fast, lightweight, and respectful web applications is not only good for SEO and performance—it restores trust between creators and visitors.
Live Demo: Test the sub-second loading in action at askamonk.online.
Tech Stack: Next.js, Tailwind CSS, Supabase, Vercel Edge Network.
Are you building for the Small Web or IndieWeb? Share your favorite performance techniques below!
Top comments (0)