챕터
2. 데이터베이스

Database: Storing Your Data

Learning Objectives

  • Understand what a database is and why you need one
  • Set up Supabase and create tables
  • Save and retrieve data from your app
  • Understand environment variables and manage them properly

2.1 What is a Database?

Simple Analogy: Organized Excel

A database (DB) is where you store data systematically. Think of it like Excel.

  • Database = Excel file
  • Table = Sheet
  • Row = One line of data
  • Column = Fields (name, email, etc.)

Why Do You Need One?

The landing page we've built so far resets everything on refresh. To save user information, settings, posts, and other data, you need a database.

  • To keep data even after refresh
  • To manage data from multiple users
  • Required for login, settings, history, and all features

2.2 Getting Started with Supabase

Supabase is a cloud database service that's free to start. You can use it immediately without complex setup, perfect for vibe coding.

Step 1: Create Account

  1. Go to supabase.com
  2. Sign up with GitHub (recommended)
  3. Click "New Project"
  4. Project name: linkhub
  5. Select Region: Northeast Asia (Tokyo)
  6. Set Database Password (save it somewhere safe!)

Step 2: Explore the Dashboard

After project creation, you'll see various features on the dashboard:

MenuDescription
Table EditorVisually manage tables
SQL EditorRun SQL queries directly
AuthAuthentication/login management (next chapter)
StorageFile storage
APIAPI keys and URL

Step 3: Check API Keys

In Settings → API, you can find two keys:

Key TypePurposeCan Expose?
Project URLSupabase addressO
anon (public) keyUsed on clientO
service_role keyServer onlyNever!
🚫

Warning

If the service_role key is exposed, anyone can manipulate your database freely. Never put it in frontend code or push to GitHub!


2.3 Designing LinkHub Tables

Now let's create the tables LinkHub needs.

Data to Store

  • Profiles - username, bio, theme
  • Links - title, URL, icon, sort order
  • Clicks - which link was clicked and when

Creating Tables

Ask Claude like this:

Create tables for the LinkHub service in Supabase.

profiles table:
- id (UUID, Primary Key)
- user_id (UUID, Foreign Key → auth.users)
- username (text, unique)
- display_name (text)
- bio (text)
- theme (text, default: 'minimal')
- created_at (timestamp)

links table:
- id (UUID, Primary Key)
- profile_id (UUID, Foreign Key → profiles)
- title (text)
- url (text)
- icon (text)
- sort_order (integer)
- is_active (boolean, default: true)

Create as SQL.

Run the SQL Claude generates in Supabase's SQL Editor.

Understanding Relationships

Connecting tables is called a 'relationship'. In LinkHub:

  • One user has one profile (1:1)
  • One profile can have multiple links (1:N)

Foreign Key serves as this connection. The profile_id column contains the id from the profiles table.


2.4 Environment Variables Setup

Don't put API keys directly in code. Use environment variables.

Creating .env.local File

Create a .env.local file in project root:

NEXT_PUBLIC_SUPABASE_URL=https://xxxxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6...

NEXT_PUBLIC_ Prefix

Variables starting with NEXT_PUBLIC_ are accessible in the browser. Only add this prefix to values that are safe to expose.

Supabase Client Setup

Create code to set up the Supabase client.
Make it /lib/supabase.ts file.
Read URL and anon key from environment variables.

2.5 Implementing CRUD

CRUD is the 4 basic operations for handling data:

  • Create - Create data
  • Read - Retrieve data
  • Update - Modify data
  • Delete - Remove data

Creating Dashboard Page

Create a dashboard page.
- View my links list (fetch from Supabase)
- Add new link button
- Edit link title/URL
- Delete link
- Drag to reorder

Implement CRUD using Supabase client.

Let's look at the key parts of the code Claude generates:

// Read - Retrieve data
const { data: links } = await supabase
  .from('links')
  .select('*')
  .eq('profile_id', profileId)
  .order('sort_order')
 
// Create - Create data
await supabase.from('links').insert({
  profile_id: profileId,
  title: 'My Website',
  url: 'https://example.com'
})
 
// Update - Modify data
await supabase.from('links')
  .update({ title: newTitle, url: newUrl })
  .eq('id', linkId)
 
// Delete - Remove data
await supabase.from('links')
  .delete()
  .eq('id', linkId)

2.6 Other Database Options

Besides Supabase, there are other database services suitable for vibe coding.

Options Comparison

ServiceFeaturesFree TierRecommended For
SupabasePostgreSQL + Auth + Real-time500MB, 2 projectsAll-in-one solution
FirebaseNoSQL + Google ecosystem1GB storage, 10GB transferGoogle service integration
NeonServerless PostgreSQL512MB, unlimited projectsGreat with Vercel
PlanetScaleServerless MySQLPaid only ($39/mo+)Large-scale scaling
TursoEdge SQLite9GB, 500 DBsUltra-low latency
ConvexReal-time + Serverless functionsGenerous free tierReal-time focused

Firebase (Google)

Easy integration with Google ecosystem, uses NoSQL.

Create LinkHub database with Firebase.
Use Firestore, collection structure:
- users/{userId}
- users/{userId}/profile
- users/{userId}/links/{linkId}
💡

SQL vs NoSQL

  • Supabase (SQL): Table, row, column structure. Strong for complex queries
  • Firebase (NoSQL): Document, collection structure. Flexible and fast

Neon

Official partnership with Vercel makes integration easy.

Connect Neon PostgreSQL to Next.js.
Use @neondatabase/serverless package.
Environment variable: DATABASE_URL
// Neon connection example
import { neon } from '@neondatabase/serverless';
 
const sql = neon(process.env.DATABASE_URL!);
 
// Run query
const agents = await sql`
  SELECT * FROM agents WHERE user_id = ${userId}
`;

PlanetScale

MySQL-based with unique branching feature. Manage DB schema like Git.

Connect PlanetScale MySQL to Next.js.
Use @planetscale/database package.

Turso (LibSQL)

Use SQLite in the cloud. Runs at the edge so it's very fast.

Connect Turso to Next.js.
Use @libsql/client package.

Convex

A platform integrating database + serverless functions + real-time.

Create LinkHub backend with Convex.
Define schema and set up real-time queries.

Which One Should You Choose?

SituationRecommendation
First time, want all-in-oneSupabase
Planning to use Google login, Firebase FunctionsFirebase
Vercel deployment, want PostgreSQLNeon
Large-scale traffic, prefer MySQLPlanetScale
Speed is top priorityTurso
Real-time + backend integrationConvex

Vibe Coding Tip

Whichever DB you use, asking Claude "Migrate this project to [DB name]" will convert it. Start with Supabase and switch later if needed.


Chapter Summary

  • Understood the concept of databases
  • Created a Supabase project
  • Designed and created tables
  • Properly set up environment variables
  • Implemented CRUD functionality
  • Learned about various DB options

In the next chapter, we'll add login functionality.

Chapter 3: Authentication →