1
0 Comments

The Supabase Schema Headache: Architecting seekaitool for 1,000+ Records

The Reality
Spent my entire Sunday wrestling with relational mapping. Building a simple list is easy; building a scalable database for https://seekaitool.com/ that doesn't crawl when the "Filter" button is clicked is a different beast.

The Deep Dive
I’m using Next.js 15 (App Router) with Supabase. The goal is sub-200ms latency for tool discovery. My initial mistake? Using a single "catch-all" table for tool metadata. It was a JSONB nightmare that killed type safety.

Today, I refactored the schema to a strictly typed relational model. I’m leveraging PostgreSQL views to handle complex joins (categories, pricing models, API availability) so the frontend only fetches exactly what it needs for the initial paint.

Here’s a snippet of how I’m enforcing data integrity via TypeScript to prevent "Ghost Tools" in the UI:

// Strict definition for our tool entities
export type AITool = {
  id: string;
  slug: string;
  title: string;
  features: string[];
  pricing_tier: 'free' | 'freemium' | 'paid';
  updated_at: ISODateString; // No more 'any' types allowed
};

// Next.js Server Action with selective fetching
const { data, error } = await supabase
  .from('tools_view')
  .select('title, slug, features')
  .limit(20);

By moving the heavy lifting to the database layer (Supabase functions), I've managed to keep the client-side bundle size lean. No unnecessary logic in the browser—just fast, hydrated HTML.

The Ask
When you're scaling a directory or marketplace, do you prefer JSONB columns for flexibility, or do you stick to a strict relational schema from Day 1? I’m worried about the migration overhead 6 months down the line.

on April 14, 2026