开源项目
Database Migration Strategies for Next.js and Supabase Production Apps
Database Migration Strategies for Next.js and Supabase Production Apps You've built your Next.js app with Supabase. It works perfectly in development. Now you need to deploy to production and realize: how do I safely change the database schema without breaking everything? Database migrations are how you version control your schema and deploy changes safely. This guide covers everything from basic migrations to zero-downtime production deployments. Prerequisites Supabase project (local and production) Supabase CLI installed Next.js application Git for version control Understanding Migrations A migration is a SQL file that changes your database schema: -- supabase/migrations/20260314120000_add_posts_table.sql CREATE TABLE posts ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4 (), title TEXT NOT NULL , content TEXT , user_id UUID REFERENCES auth . users ( id ), created_at TIMESTAMPTZ DEFAULT NOW () ); ALTER TABLE posts ENABLE ROW LEVEL SECURITY ; CREATE POLICY "Users can view own posts" ON posts FOR SELECT USING ( auth . uid () = user_id ); Migrations are: Versioned: Timestamped filenames ensure order Tracked: Supabase knows which migrations have run Repeatable: Same migrations produce same result Reversible: You can write rollback logic Setting Up Migrations Initialize Supabase locally: npx supabase init This creates: supabase/ config.toml seed.sql migrations/ Link to your remote project: npx supabase link --project-ref your-project-ref Creating Your First Migration Create a new migration: npx supabase migration new create_posts_table This creates: supabase / migrations / 20260314120000 _create_posts_table . sql Write your schema changes: -- Create posts table CREATE TABLE posts ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4 (), title TEXT NOT NULL , content TEXT NOT NULL , slug TEXT UNIQUE NOT NULL , user_id UUID REFERENCES auth . users ( id ) ON DELETE CASCADE , published BOOLEAN DEFAULT FALSE , created_at TIMESTAMPTZ DEFAULT NOW (), updated_at TIMESTAMPTZ DEFAULT NOW
AI 资讯
7 Things I Wish I Knew Before Scaling Next.js + Supabase to 100K Users
7 Things I Wish I Knew Before Scaling Next.js + Supabase to 100K Users Six months ago, we launched our SaaS with Next.js and Supabase. The stack was perfect for our MVP: fast development, great DX, and it just worked. Then we hit 10K users. Then 50K. Then 100K. Everything that worked beautifully at small scale started breaking. Database queries that took 50ms now took 5 seconds. Our Supabase bill went from $25/month to $800/month. Users complained about slow page loads. Here's what I wish someone had told me before we started. 1. RLS Policies Are Not Optional (Even in Development) We skipped RLS in development. "We'll add it before launch," we said. Launch day came. We enabled RLS on all tables. The app broke in 47 different places. Queries that worked suddenly returned empty arrays. Inserts failed with permission errors. We spent 12 hours fixing RLS policies while users waited. What I'd do differently: Enable RLS from day one. Write policies as you create tables: CREATE TABLE posts ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4 (), title TEXT NOT NULL , user_id UUID REFERENCES auth . users ( id ) ); -- Enable RLS immediately ALTER TABLE posts ENABLE ROW LEVEL SECURITY ; -- Write policies now, not later CREATE POLICY "Users can view own posts" ON posts FOR SELECT USING ( auth . uid () = user_id ); Test with RLS enabled. If it works in development, it'll work in production. 2. Database Indexes Are Not Premature Optimization "We'll add indexes when we need them." We needed them on day 3. Our posts feed query went from 50ms to 8 seconds as we hit 10K posts. Users complained. We scrambled to add indexes during peak traffic. The query: const { data } = await supabase . from ( ' posts ' ) . select ( ' *, profiles(*) ' ) . eq ( ' published ' , true ) . order ( ' created_at ' , { ascending : false }) . limit ( 20 ) The fix: CREATE INDEX posts_published_created_at_idx ON posts ( published , created_at DESC ) WHERE published = true ; Query time dropped to 12ms. What I'd do di
AI 资讯
Self-Host Postgres or Use Supabase? Here's How to Decide
Short answer first: use Supabase if you want Postgres plus auth, realtime, storage, and a dashboard as one managed bundle. Self-host Postgres – or use a managed Postgres – if you mostly need a database and your app already handles its own auth and logic. The choice is not really "Postgres vs Supabase". It's whether you need the extra layers Supabase puts on top of Postgres. Supabase is not a database Supabase runs on PostgreSQL, but it's a stack of services around it: Postgres – the actual database Auth – user signup, login, JWT tokens Realtime – live updates over websockets Storage – an S3-style file store Edge Functions – serverless functions Studio – dashboard + auto-generated REST/GraphQL API So "self-host Postgres or use Supabase" compares a plain database to a full backend. The honest question: do you need those extra layers, or just the database underneath them? A quick test: You use Supabase Auth, Storage, and Realtime → Supabase earns its place. You use one of them → it's replaceable. You use none and treat it as "Postgres with a nice dashboard" → you want plain Postgres. Side-by-side comparison Factor Supabase (managed) Self-hosted Supabase Plain Postgres (managed or self-hosted) Database engine PostgreSQL PostgreSQL PostgreSQL Built-in auth Yes Yes No (bring your own) Realtime / websockets Yes Yes No File storage Yes Yes No Dashboard + auto API Yes Yes No (use any SQL client) Backups Managed (limits by plan) You manage Managed or you manage Cost shape Metered, grows with usage Server cost + your time Database only Self-host effort None High (many containers) Low–medium Lock-in Medium–high Medium Very low The lock-in point decides it for many teams. Your data is standard Postgres in every option ( pg_dump portable). The lock-in is everything else: Auth tokens, Storage paths, Supabase-specific RLS policies, Edge Function code. The more Supabase-specific features you adopt, the harder the exit. When each option wins Pick managed Supabase when: You're startin
AI 资讯
How to build a credit system for a Next.js AI app (Stripe + Supabase)
If you're building an AI app (image generation, transcription, an agent, anything that calls a model) you've probably realized a flat "$10/month" doesn't work. Every action costs you real money in GPU/API spend, so a single power user can torch your margins. The answer is usage credits : users buy a balance, each action spends some. Credits sound trivial. They are not. I've shipped about 10 small AI/SaaS apps, and the credit layer is where I got burned every single time. It took three patterns to fix it for good. Here they are, with copy-pasteable code for Next.js + Supabase + Stripe. Get these right and your billing won't oversell, double-charge, or strand a user's money. The three things everyone gets wrong Overdrawing. Two requests arrive at once, both read "balance = 1," both spend. Now the balance is negative and you gave away work for free. Double-granting. Stripe retries webhooks (it will ), and if you grant credits on every delivery, a $9 purchase becomes $18 of credits. Forgetting the refund. The AI job fails after you've already charged the credits. The user paid for nothing and emails you angry. Let's kill all three. Part 1. The atomic spend (overdraw becomes impossible) The mistake is doing the check in your app code: // DON'T: read-then-write has a race condition const { balance } = await getBalance ( userId ); if ( balance < cost ) throw new Error ( " insufficient " ); await setBalance ( userId , balance - cost ); // two concurrent requests both pass the check Do it in the database, in one statement, with the guard in the WHERE clause: -- balances: one row per user create table credit_balances ( user_id uuid primary key references auth . users ( id ) on delete cascade , balance integer not null default 0 check ( balance >= 0 ), updated_at timestamptz not null default now () ); -- append-only ledger = audit log + idempotency guard (see Part 2) create table credit_ledger ( id bigint generated always as identity primary key , user_id uuid not null referen
AI 资讯
Supabase doubles valuation to $10B in 8 months
Supabase, an example of an open source project becoming a fast-growing company, has greatly benefited from AI tools like Claude, Codex, and other vibe-coding platforms.
AI 资讯
I built PhysioFlow — clinic software for Indian physiotherapists, solo in a week
A physiotherapist asked me a simple question a couple of months ago: "Can you build something to run my whole clinic?" So I did — solo, in about a week. Here's the full 2.5-minute walkthrough 👇 What PhysioFlow does PhysioFlow runs an entire physiotherapy clinic from one screen — built for India (₹, GST, WhatsApp, +91): Dashboard — attendance, collections & pending bookings at a glance Patient files — recharge session packs, track usage, auto-generate GST-ready bills Attendance in seconds with a QR scan Online bookings that convert straight into a patient file Reports — daily ledger, revenue, CSV/PDF export Patient portal — patients see their own sessions & prescriptions The stack Next.js + Supabase + TypeScript — multi-tenant, with row-level security so no clinic's data ever leaks to another. Try it Live now with a 14-day free trial, no card needed → https://physioflow.devfrend.com I'm Amar, a full-stack & AI engineer. I design and build products like this end-to-end. I'm open to work — SaaS builds, MCP servers, LLM apps & automation. Reach me on LinkedIn .