Workshop 3 — Appendix

AI & Data APIs

Voice · Image · LLM · Databases
Voice APIs

🎤 Speech-to-Text & Text-to-Speech

Speak into your app — or make it speak back
These APIs turn voice into text (transcription) or text into natural-sounding audio (synthesis). Use them to build voice commands, voice notes, accessibility features, or any "talk to your app" experience.

Speech-to-Text (STT) — user speaks, you get text

🎙️

OpenAI Whisper

openai.com · POST /v1/audio/transcriptions
API key needed ~$0.006 / min
Use when: you want users to record a voice note, dictate text, or issue voice commands. Whisper handles 99 languages automatically — no configuration needed.

You record audio in the browser using the MediaRecorder API, send the audio file to your backend, and your backend forwards it to Whisper. You get a text transcript back in ~1 second.

⚠️ Backend required. Never call OpenAI directly from your frontend code — your API key would be visible in the browser. All OpenAI calls must go through a server function (e.g. Vercel Serverless Function, Supabase Edge Function).
Step 1 — Frontend: record audio in the browser
const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); const recorder = new MediaRecorder(stream); const chunks = []; recorder.ondataavailable = e => chunks.push(e.data); recorder.onstop = async () => { const blob = new Blob(chunks, { type: 'audio/webm' }); const formData = new FormData(); formData.append('file', blob, 'recording.webm'); // Send to YOUR backend — not to OpenAI directly const res = await fetch('/api/transcribe', { method: 'POST', body: formData }); const { text } = await res.json(); console.log('Transcript:', text); // "remind me to call Tom tomorrow" }; recorder.start(); document.getElementById('stop-btn').onclick = () => recorder.stop();
Step 2 — Backend: Vercel serverless function /api/transcribe.js
import OpenAI from 'openai'; import formidable from 'formidable'; import fs from 'fs'; const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY }); export default async function handler(req, res) { const form = formidable({ uploadDir: '/tmp', keepExtensions: true }); const [, files] = await form.parse(req); const file = files.file[0]; const transcript = await openai.audio.transcriptions.create({ file: fs.createReadStream(file.filepath), model: 'whisper-1', }); res.json({ text: transcript.text }); }
💡 Claude prompt to get started: "I'm building a project in Claude and deploying on Vercel via GitHub. Add a voice recorder button that records audio from the microphone, sends it to a Vercel serverless function at /api/transcribe using the OpenAI Whisper API (whisper-1 model), and displays the text transcript in a text field. Store OPENAI_API_KEY as a Vercel environment variable. Give me the complete index.html and the /api/transcribe.js function separately."
📄 OpenAI STT Docs 🔑 Get API Key

Text-to-Speech (TTS) — your app speaks

🔊

OpenAI TTS

openai.com · POST /v1/audio/speech
API key needed ~$0.015 / 1K chars
Use when: you want your app to read text aloud — reading assistant, language learning app, accessibility feature, or "AI that talks back" experience.

Send a text string, choose a voice (alloy, echo, fable, onyx, nova, shimmer), and get an MP3 audio file back. Play it directly in the browser.

Backend function /api/speak.js
import OpenAI from 'openai'; const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY }); export default async function handler(req, res) { const { text, voice = 'nova' } = req.body; const mp3 = await openai.audio.speech.create({ model: 'tts-1', voice, // alloy | echo | fable | onyx | nova | shimmer input: text, }); const buffer = Buffer.from(await mp3.arrayBuffer()); res.setHeader('Content-Type', 'audio/mpeg'); res.send(buffer); }
Frontend: call the function & play audio
async function speak(text) { const res = await fetch('/api/speak', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text, voice: 'nova' }), }); const blob = await res.blob(); const url = URL.createObjectURL(blob); new Audio(url).play(); } speak("Welcome to your smart study planner.");
📄 OpenAI TTS Docs 🎧 Voice demos
🎭

ElevenLabs

elevenlabs.io · premium voice quality + custom cloning
10k chars / month free API key needed
Use when: you need more realistic or emotionally expressive voices than OpenAI TTS — or you want to clone a specific voice (e.g. a branded AI persona).

ElevenLabs offers 100+ pre-built voices with emotional range, and a free tier generous enough for demos. More natural than OpenAI TTS for longer passages.

Backend function /api/elevenlabs.js
export default async function handler(req, res) { const { text } = req.body; const VOICE_ID = '21m00Tcm4TlvDq8ikWAM'; // "Rachel" — browse at elevenlabs.io/voices const response = await fetch( `https://api.elevenlabs.io/v1/text-to-speech/${VOICE_ID}`, { method: 'POST', headers: { 'xi-api-key': process.env.ELEVENLABS_API_KEY, 'Content-Type': 'application/json', }, body: JSON.stringify({ text, model_id: 'eleven_monolingual_v1', voice_settings: { stability: 0.5, similarity_boost: 0.75 }, }), } ); const buffer = Buffer.from(await response.arrayBuffer()); res.setHeader('Content-Type', 'audio/mpeg'); res.send(buffer); }
📄 ElevenLabs Docs 🔑 Free account 🎧 Browse voices
Image Generation APIs

🖼️ Generate Images from Text

Turn a description into a visual in under 5 seconds
Send a text prompt, receive a generated image URL. Use for: dynamic hero images, product mockups, user-created avatars, AI-powered design tools, or any feature where users want to visualise an idea.

OpenAI DALL-E 3 — best quality, easiest to use

🎨

OpenAI DALL-E 3

openai.com · POST /v1/images/generations
API key needed $0.04–0.12 / image
Use when: you need high-quality photorealistic or artistic images from a text prompt. DALL-E 3 has the best prompt-following of any image model — it understands nuanced descriptions well.

You send a prompt and optionally specify size (1024×1024, 1792×1024, 1024×1792) and quality (standard / hd). You get back a URL to the generated image — valid for 1 hour. Save it to your storage if you need it longer.

⚠️ Backend required. Never call OpenAI from frontend JavaScript — use a backend proxy function.
Backend function /api/generate-image.js
import OpenAI from 'openai'; const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY }); export default async function handler(req, res) { const { prompt, size = '1024x1024' } = req.body; const response = await openai.images.generate({ model: 'dall-e-3', prompt, // e.g. "a minimalist app icon for a meditation app, flat design" n: 1, // DALL-E 3 only supports n:1 size, quality: 'standard', }); res.json({ url: response.data[0].url }); }
Frontend: show the generated image
async function generateImage(prompt) { document.getElementById('img-status').textContent = 'Generating…'; const res = await fetch('/api/generate-image', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ prompt }), }); const { url } = await res.json(); const img = document.getElementById('result-img'); img.src = url; img.style.display = 'block'; document.getElementById('img-status').textContent = ''; } document.getElementById('gen-btn').onclick = () => { generateImage(document.getElementById('prompt-input').value); };
💡 Prompt tip: The more specific your prompt, the better the result. Include style, medium, mood, and composition. Example: "a flat-design mobile app icon for a travel journaling app, teal and white colour palette, rounded corners, clean and modern"
📄 DALL-E Docs ✏️ Prompting guide

Alternatives — more control, lower cost

Stability AI via Replicate

replicate.com · run any open-source model via a simple API
API key needed ~$0.003–0.02 / image
Use when: you need cheaper per-image costs, specific artistic styles (anime, illustration, oil painting), or you want to give users more style parameters to control. Replicate hosts SDXL, Stable Diffusion 3, Flux, and 1000+ other models.
Backend function using Replicate SDK
import Replicate from 'replicate'; const replicate = new Replicate({ auth: process.env.REPLICATE_API_TOKEN }); export default async function handler(req, res) { const { prompt } = req.body; // Stable Diffusion XL — change model version for different styles const output = await replicate.run( 'stability-ai/sdxl:7762fd07cf82c948538e41f63f77d685e02b063e37291fae17', { input: { prompt, negative_prompt: 'blurry, low quality, distorted', width: 1024, height: 1024, num_outputs: 1, } } ); res.json({ url: output[0] }); // returns image URL }

DALL-E 3 vs Replicate

DALL-E 3 has better prompt understanding and photorealism. Replicate is cheaper per image and supports hundreds of specialised styles — illustrative, anime, logo design, interior design, etc.

For your MVP

Start with DALL-E 3 for simplicity. Move to Replicate if you need lower cost at scale or specialised artistic styles.

📄 Replicate Docs 🔍 Explore models 🔑 Get API token
Chat / LLM APIs

🤖 AI That Reads, Thinks & Writes

Build chatbots, summarisers, coaches, and AI-powered features
LLM (Large Language Model) APIs let you send a message and receive a smart, context-aware text response. They power chatbots, smart search, auto-fill, content generation, feedback tools, and much more.

OpenAI GPT-4o — the industry standard

🧠

OpenAI GPT-4o / GPT-4o-mini

openai.com · POST /v1/chat/completions
API key needed GPT-4o-mini ~$0.15 / 1M tokens
Use when: you need an AI that understands and generates text — chatbots, business plan feedback, smart search, auto-completing forms, summarising content, or generating personalised recommendations. GPT-4o-mini is the cheapest option for most use cases.

The API takes an array of messages (with roles: system, user, assistant). The system message defines the AI's persona and task. Your user's input goes in a user message. The AI responds as assistant.

⚠️ Backend required. All GPT API calls must go through your backend. Never put OPENAI_API_KEY in frontend code.
Backend function /api/chat.js
import OpenAI from 'openai'; const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY }); export default async function handler(req, res) { const { userMessage, history = [] } = req.body; const messages = [ { role: 'system', content: 'You are a friendly startup pitch coach. Give concise, constructive feedback.' }, ...history, // previous turns for multi-turn conversation { role: 'user', content: userMessage } ]; const completion = await openai.chat.completions.create({ model: 'gpt-4o-mini', // or 'gpt-4o' for higher quality messages, max_tokens: 500, temperature: 0.7, // 0=deterministic, 1=creative }); res.json({ reply: completion.choices[0].message.content }); }
Frontend: simple chat UI
let history = []; async function sendMessage(userText) { history.push({ role: 'user', content: userText }); const res = await fetch('/api/chat', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ userMessage: userText, history }), }); const { reply } = await res.json(); history.push({ role: 'assistant', content: reply }); displayMessage('AI', reply); }

System prompt — the most powerful parameter

The system message shapes everything. It's where you give the AI its role, rules, tone, and domain. Examples:

  • "You are a business model advisor. Only answer questions about revenue models, pricing, and customer segments."
  • "You are a language tutor teaching Lithuanian to English speakers. Respond in short lessons with examples."
  • "You analyse startup pitches and give 3 specific improvements. Be direct and concise."
📄 OpenAI Chat Docs 🧪 Playground

Anthropic Claude — great for analysis & long documents

Anthropic Claude

anthropic.com · POST /v1/messages · claude-haiku-4-5 / claude-sonnet-4-5
API key needed Haiku ~$0.25 / 1M tokens
Use when: you need to analyse long documents, do careful reasoning, or want a model that tends to be more cautious and structured. Claude Haiku is extremely fast and cheap; Claude Sonnet is more capable for complex tasks.
Backend function /api/claude.js
import Anthropic from '@anthropic-ai/sdk'; const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY }); export default async function handler(req, res) { const { userMessage } = req.body; const message = await client.messages.create({ model: 'claude-haiku-4-5', // fastest + cheapest; use claude-sonnet-4-5 for quality max_tokens: 1024, system: 'You are a helpful business analyst for early-stage startups.', messages: [{ role: 'user', content: userMessage }], }); res.json({ reply: message.content[0].text }); }
📄 Claude API Docs 🔑 Get API Key

Google Gemini — free tier, multimodal, and Google AI Studio

🔵

Google Gemini 2.0 Flash

aistudio.google.com · generativelanguage.googleapis.com
Free tier (60 req/min) JS + Python SDK
Use when: you want a powerful LLM with a generous free tier (no credit card needed), need to analyse images or documents alongside text, or want to prototype quickly using Google AI Studio's built-in code generation before connecting the API.

Gemini 2.0 Flash is Google's fastest and most cost-effective model. Unlike GPT-4o and Claude, the free tier is usable for real student projects — 15 requests per minute and 1 million tokens per day at no cost. It is also natively multimodal: you can send text, images, PDFs, and audio in the same request.

🛠️ Google AI Studio — free browser IDE

Before writing a single line of code, visit aistudio.google.com. It's a free browser tool where you can test prompts, experiment with multimodal inputs, and — crucially — click "Get code" to export a ready-to-run JavaScript or Python snippet for exactly what you just tested. Think of it as a live scratchpad that hands you working code.

💡 Free tier is genuinely useful: The Gemini API free tier requires no billing setup — just a Google account. For a workshop prototype with moderate usage, you will not need to pay anything.
Backend function /api/gemini.js
import { GoogleGenerativeAI } from '@google/generative-ai'; const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY); export default async function handler(req, res) { const { userMessage } = req.body; const model = genAI.getGenerativeModel({ model: 'gemini-2.0-flash' }); const result = await model.generateContent({ contents: [{ role: 'user', parts: [{ text: userMessage }] }], systemInstruction: 'You are a helpful startup advisor for student entrepreneurs.', }); res.json({ reply: result.response.text() }); }
Frontend: call the backend
async function askGemini(userText) { const res = await fetch('/api/gemini', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ userMessage: userText }), }); const { reply } = await res.json(); document.getElementById('answer').textContent = reply; }

🖼️ Multimodal — analyse an image with text

Gemini's standout feature is native multimodal support. You can send an image (uploaded by the user, a screenshot, a product photo) alongside a text question — all in one API call, with no separate vision endpoint needed.

Backend: analyse an uploaded image
import { GoogleGenerativeAI } from '@google/generative-ai'; const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY); export default async function handler(req, res) { const { prompt, imageBase64, mimeType } = req.body; // imageBase64: base64-encoded image string from the browser // mimeType: e.g. 'image/jpeg' or 'image/png' const model = genAI.getGenerativeModel({ model: 'gemini-2.0-flash' }); const result = await model.generateContent({ contents: [{ role: 'user', parts: [ { text: prompt }, // e.g. "What product is in this photo?" { inlineData: { data: imageBase64, mimeType } } // the image ] }] }); res.json({ reply: result.response.text() }); }
Frontend: send image + question
async function analyseImage(file, question) { // Convert file to base64 const base64 = await new Promise(resolve => { const reader = new FileReader(); reader.onload = e => resolve(e.target.result.split(',')[1]); reader.readAsDataURL(file); }); const res = await fetch('/api/gemini', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ prompt: question, imageBase64: base64, mimeType: file.type, }), }); const { reply } = await res.json(); console.log(reply); } // Example use — triggered by file input document.getElementById('img-input').onchange = async (e) => { const file = e.target.files[0]; await analyseImage(file, 'Describe what you see and suggest a product name.'); };

Multimodal use cases for MVPs

Receipt scanner → extract total and items. Product photo → suggest description and price. Sketch/wireframe → describe the UI to a developer. Business card → extract contact info. Screenshot of a competitor app → list features and gaps.

🛠️ Google AI Studio (free) 📄 Gemini API Docs 🔑 Get free API key 💰 Pricing (free tier)

Which model to choose — GPT vs Claude vs Gemini

GPT-4o / GPT-4o-mini

Widest ecosystem, best function-calling support, most community examples. GPT-4o-mini is very cheap. Use for: general chat, tool use, code generation, image understanding.

Anthropic Claude

Best for long documents (200k context), careful structured output, and reasoning tasks. Tends to be more cautious and less prone to hallucination. Use for: analysis, summarisation, document Q&A.

Google Gemini

Best free tier (no billing needed), native multimodal (text + image in one call), and Google AI Studio for instant prototyping. Use for: student prototypes, image analysis, and any project where budget is zero.

💡 For this workshop: start with Gemini if you have no budget and want multimodal. Use GPT-4o-mini if you need the most community support. Use Claude Haiku if you're processing long text or documents. All three accept the same basic prompt structures.

Useful AI prompt patterns for MVPs

Copy-paste system prompt templates

Drop these into the system field of any LLM call and customise for your product:

Feedback / coaching tool
You are an expert [domain] coach. The user will share [input type]. Give exactly 3 pieces of specific, actionable feedback. Format: start each point with a number. Be direct and encouraging. Limit your response to 200 words.
Data analyser / summariser
You analyse [document type] for [target user]. Respond with: 1. A 2-sentence summary 2. 3 key insights as bullet points 3. One recommended action Be concise. Avoid jargon. Assume the reader has no prior expertise.
Personalisation / recommendation engine
You are a recommendation engine for [product type]. The user will provide their [preferences / profile / history]. Recommend exactly 3 options. For each: name, one-sentence reason, confidence score (1-10). Return valid JSON: [{ "name": "...", "reason": "...", "score": 8 }, ...]
Databases

🗄️ Storing Your App's Data

Save users, posts, orders, and anything else your app needs to remember
A database lets your app remember things between sessions. Without one, every page refresh loses all data. Choose based on your data shape: structured rows → Supabase; flexible real-time docs → Firebase; spreadsheet-like → Airtable.

What is a database and when do you need one?

A database is persistent storage — it keeps data even when the server restarts or the user closes the browser. You need one when your app must:

  • Remember registered users and their profiles
  • Save posts, orders, feedback, or any user-generated content
  • Share data between multiple users (e.g. a shared task list)
  • Persist preferences or progress across sessions

For a one-user demo that only runs in one browser, localStorage may be enough. For anything real: use a database.

Supabase — recommended for most student projects

🟢

Supabase

supabase.com · PostgreSQL + REST API + Auth + Storage
Free tier (500MB) JS SDK available
Use when: your data is structured like a spreadsheet (users, posts, orders with fixed columns), you need user authentication, or you need SQL power with simple JS access. Supabase is Postgres under the hood — the most widely used database in the world.
  • 1
    Create a projectGo to supabase.com → New project → choose a name and region → wait ~2 minutes
  • 2
    Create a tableIn the Supabase dashboard → Table Editor → New table. Add columns (e.g. id, email, created_at, idea_text)
  • 3
    Get your keysSettings → API → copy Project URL and anon public key
  • 4
    Install SDKnpm install @supabase/supabase-js — or ask Claude to add it. Claude will include the correct import and package.json entry automatically.
Initialise client (safe to put URL + anon key in frontend)
import { createClient } from '@supabase/supabase-js'; const supabase = createClient( 'https://your-project.supabase.co', // from Settings → API 'your-anon-public-key' // NOT the service_role key );
Insert a record (save user idea)
const { data, error } = await supabase .from('ideas') .insert([{ email: 'student@example.com', idea_text: 'An app that matches volunteer skills to NGOs', created_at: new Date().toISOString(), }]); if (error) console.error(error); else console.log('Saved:', data);
Read records (fetch all ideas)
const { data: ideas, error } = await supabase .from('ideas') .select('*') .order('created_at', { ascending: false }) .limit(10); ideas.forEach(idea => console.log(idea.email, idea.idea_text));
Update a record
const { error } = await supabase .from('ideas') .update({ idea_text: 'Updated description' }) .eq('id', 42); // update the row where id = 42
Delete a record
const { error } = await supabase .from('ideas') .delete() .eq('id', 42);
💡 Row Level Security (RLS): Supabase's free tier has RLS enabled by default, which means the anon key can only read/write data according to your policies. For a quick demo, go to Authentication → Policies and add a policy that allows all operations — or ask Claude to set up auth with policies: "Add Supabase RLS policies that allow any authenticated user to read all rows and insert their own rows."
💡 Built-in Auth: Supabase includes email/password, magic link, and Google OAuth for free. Ask Claude: "Add Supabase email/password authentication to this project. Store SUPABASE_URL and SUPABASE_ANON_KEY as Vercel environment variables."
📄 Supabase Docs 🔐 Auth guide 🔑 Create free project

Firebase / Firestore — Google's real-time database

🔥

Firebase / Firestore

firebase.google.com · NoSQL document database
Spark plan free JS SDK available
Use when: your data is flexible (different documents may have different fields), you need real-time syncing across multiple users (collaborative tools, live feeds), or you're building a mobile app. Firebase is Google's platform and integrates with Google Sign-In natively.

Firestore stores data as documents inside collections. Think of a collection like a folder, and a document like a JSON file inside it. There's no fixed schema — each document can have different fields.

  • 1
    Create a projectconsole.firebase.google.com → Add project → name it → continue through setup
  • 2
    Add a web appProject overview → Add app → Web → Register → copy the config object shown
  • 3
    Create Firestore databaseBuild → Firestore Database → Create database → choose test mode (for prototyping)
  • 4
    Install SDKnpm install firebase
Initialise Firebase
import { initializeApp } from 'firebase/app'; import { getFirestore, collection, addDoc, getDocs, query, orderBy } from 'firebase/firestore'; const app = initializeApp({ apiKey: 'your-api-key', // from the config object Firebase gave you authDomain: 'your-app.firebaseapp.com', projectId: 'your-project-id', storageBucket: 'your-app.appspot.com', messagingSenderId: '123456789', appId: 'your-app-id', }); const db = getFirestore(app);
Add a document (save an idea)
const docRef = await addDoc(collection(db, 'ideas'), { email: 'student@example.com', ideaText: 'An app that matches volunteers to NGOs', createdAt: new Date(), }); console.log('Saved with ID:', docRef.id);
Read all documents
const q = query(collection(db, 'ideas'), orderBy('createdAt', 'desc')); const snapshot = await getDocs(q); snapshot.forEach(doc => { console.log(doc.id, doc.data()); });
Real-time listener (updates live without refreshing)
import { onSnapshot } from 'firebase/firestore'; onSnapshot(collection(db, 'ideas'), (snapshot) => { snapshot.docChanges().forEach(change => { if (change.type === 'added') console.log('New idea:', change.doc.data()); }); });

Firebase vs Supabase key difference

Firebase is NoSQL (flexible documents, great for real-time). Supabase is SQL (structured tables, great for relational data with joins). For most startup prototypes, Supabase is easier to start with. Choose Firebase if real-time collaboration is a core feature.

📄 Firestore Quickstart 🔑 Firebase Console

Airtable — spreadsheet as a database

📊

Airtable API

airtable.com · REST API on top of your spreadsheet
Free (1k records / base) API key needed
Use when: you want the simplest possible database with no SQL knowledge required, your team already manages data in spreadsheets, or you want to let non-technical teammates add and edit records visually while your app reads them via API.

Airtable is a spreadsheet where each sheet is a table and each row is a record. You can interact with it using a simple REST API — no database client or SDK required. Perfect for quick prototypes, content management, and admin-friendly data entry.

  • 1
    Create a baseairtable.com → Add a base → add columns (e.g. Name, Email, Idea, Status)
  • 2
    Get your IDsCopy your Base ID from the URL: airtable.com/appXXXXXXX/... (the appXXX part). Table name = exactly as shown in Airtable.
  • 3
    Get an API tokenairtable.com/account → Developer Hub → Personal access tokens → Create token
⚠️ Backend required for write operations. For read-only public data, the anon key can technically be exposed, but best practice is always to proxy through a backend function.
Read records (list all ideas)
const BASE_ID = 'appXXXXXXXXXXXXXX'; // from your Airtable URL const TABLE = 'Ideas'; // exact table name const API_KEY = process.env.AIRTABLE_API_KEY; const res = await fetch( `https://api.airtable.com/v0/${BASE_ID}/${TABLE}?maxRecords=20&sort[0][field]=Name`, { headers: { Authorization: `Bearer ${API_KEY}` } } ); const { records } = await res.json(); records.forEach(record => { console.log(record.fields.Name, record.fields.Email); });
Create a record (save a new idea)
const res = await fetch( `https://api.airtable.com/v0/${BASE_ID}/${TABLE}`, { method: 'POST', headers: { Authorization: `Bearer ${API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ fields: { Name: 'Student A', Email: 'student@example.com', Idea: 'App that matches volunteers to NGOs', Status: 'Draft', } }), } ); const record = await res.json(); console.log('Created record ID:', record.id);
💡 Perfect for admin panels: Build your frontend with Claude, connect it to Airtable. Non-technical stakeholders manage content directly in Airtable's spreadsheet view while the app reads it via API — no database administration needed. Ask Claude: "Add a fetch call that reads all records from my Airtable base via a Vercel serverless function at /api/content.js."
📄 Airtable API Docs 🔑 Create API token
Database Comparison

⚖️ Supabase vs Firebase vs Airtable

Pick the right database for your MVP in 30 seconds
All three are free to start and can be set up in under 10 minutes. The choice depends on your data shape and team's technical comfort.
Feature 🟢 Supabase 🔥 Firebase 📊 Airtable
Data model SQL tables (rows + columns) NoSQL documents (flexible JSON) Spreadsheet (rows + named columns)
Free tier 500 MB, 50k rows 1 GB storage, 50k reads/day 1,000 records per base
Auth built-in ✓ Email, OAuth, magic link ✓ Email, Google, Apple, SMS ✗ Not included
Real-time updates Partial (via Realtime channels) ✓ Native (onSnapshot) ✗ Polling only
SQL queries ✓ Full SQL support ✗ No SQL ✗ No SQL
Non-technical admin UI Partial (table editor) Partial (console) ✓ Excellent spreadsheet UI
File storage ✓ Built-in (images, PDFs) ✓ Firebase Storage ✓ Attachments in records
JS SDK quality ✓ Excellent ✓ Excellent (Google-maintained) REST API only (no official SDK)
Best for Structured data, auth, SQL joins Real-time collab, mobile apps Content management, no-code CMS
Learning curve Low (SQL is widely known) Medium (NoSQL concepts) Very low (like a spreadsheet)

Quick decision guide

Choose Supabase if…

Your app has users, posts, or orders with relationships between them (e.g. a user has many posts). You want login/signup included. You're comfortable thinking in rows and columns. Default choice for most MVPs.

Choose Firebase if…

Real-time updates are a core feature (live chat, collaborative editing, live dashboards). You're building a mobile app. Your data structure changes often and you don't want to run database migrations.

Choose Airtable if…

Non-technical teammates need to add or edit content without any code. You're building a content-driven app (product catalogue, event listings, job board) where the "database" acts as a CMS. You want to be up and running in 5 minutes with zero backend setup.


Asking AI to connect your database — prompt templates

Supabase — Claude prompt

Add Supabase to this project: 1. Create a 'submissions' table with columns: id, name, email, idea_text, created_at 2. On form submit, insert a row into 'submissions' using the Supabase JS SDK 3. On the dashboard page, fetch and display all submissions ordered by created_at desc 4. Store SUPABASE_URL and SUPABASE_ANON_KEY as environment variables

Firebase — Claude prompt

Add Firebase Firestore to this project: 1. Initialise Firebase with config stored in environment variables 2. Create a 'posts' collection 3. When the user submits the form, add a document with fields: title, body, authorEmail, timestamp 4. On the feed page, use onSnapshot to show posts in real time, newest first

Airtable — Claude prompt

Add Airtable as the database for this project: 1. Create a serverless function at /api/airtable.js 2. GET /api/airtable?action=list — returns all records from the 'Submissions' table 3. POST /api/airtable with { name, email, idea } — creates a new record 4. Store AIRTABLE_API_KEY and AIRTABLE_BASE_ID as environment variables

⚡ General rule

You don't need to write database code from scratch. Give Claude the prompt above inside your Project — it generates the complete code, including the Vercel serverless functions. Your job is to understand which database to use and what data to store. Push everything to GitHub and Vercel handles the rest.