This is Part 2 of a 2-part series. If you have not set up your project yet, start with Part 1: VSCode + Git + GitHub Setup.
Welcome back. At this point you have a working Task Manager app running locally on your computer and your code is saved on GitHub. In Part 2, we will:
- Add a real database using Supabase (so tasks are saved permanently)
- Deploy your app live on the internet using Vercel
- Connect a custom domain
- Set up environment variables for secrets
- Enable automatic deployments (every push to GitHub updates your live site)
By the end, you will have a fully functional, production-grade web application that anyone in the world can use.
What is Supabase?
Supabase is an open-source Firebase alternative that gives you a fully managed PostgreSQL database, real-time subscriptions, authentication, file storage, and an auto-generated API — all for free on the starter plan.
In plain terms: Supabase is your app’s memory. When a user adds a task, it gets saved to Supabase. When they refresh the page or come back tomorrow, the task is still there.
Step 1 — Create a Supabase Account and Project
- Go to supabase.com and click Start your project
- Sign up with your GitHub account (easiest option — use the same GitHub account you created in Part 1)
- Click New Project
- Fill in:
- Organization: your name or team name
- Project name:
my-task-manager - Database password: create a strong password and save it somewhere safe
- Region: choose the one closest to you (e.g., “US East” for Toronto)
- Click Create new project
Supabase will take about 1-2 minutes to set up your project. You will see a loading screen. Wait for it to finish.
Step 2 — Get Your API Keys
Once your project is ready, you need two pieces of information to connect your app to Supabase:
- In the Supabase dashboard, click Settings (the gear icon in the left sidebar)
- Click API
- Under “Project URL,” copy the URL that looks like:
https://abcdefghijklm.supabase.co - Under “Project API Keys,” copy the anon / public key
Keep these handy — you will need them in the next steps.
⚠️ Important: The anon key is safe to use in your frontend code. Never expose your service_role key in frontend code — that key bypasses all security rules.
Step 3 — Create Your Database Table
Now we need to create a table to store tasks. Supabase uses PostgreSQL, a professional-grade database used by companies like Instagram and Reddit.
- In the Supabase dashboard, click Table Editor in the left sidebar
- Click Create a new table
- Set the table name to:
tasks - Add these columns by clicking Add column for each:
- title — type:
text, not nullable - completed — type:
bool, default value:false
- title — type:
- The id and created_at columns are added automatically — leave them as-is
- Click Save
Alternatively, you can create the table using SQL. Click SQL Editor in the sidebar, paste this, and click Run:
-- Create the tasks table
create table tasks (
id uuid default gen_random_uuid() primary key,
title text not null,
completed boolean default false,
created_at timestamp with time zone default now()
);
-- Enable Row Level Security (best practice)
alter table tasks enable row level security;
-- Allow all operations for development (we can restrict this later)
create policy "Allow all for now" on tasks for all using (true);
Your database is ready. No server to manage, no SQL server to install — Supabase handles everything.
Step 4 — Connect Supabase to Your Next.js App
Open your my-task-manager project in VS Code. In the terminal, install the Supabase JavaScript library:
npm install @supabase/supabase-js
Create your environment variables file:
In VS Code, create a new file in your project root called .env.local. This file stores your secrets and is never uploaded to GitHub (notice it is already in your .gitignore file).
NEXT_PUBLIC_SUPABASE_URL=https://your-project-id.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key-here
Replace the values with the URL and anon key you copied from Supabase in Step 2.
What is NEXT_PUBLIC_? In Next.js, any environment variable starting with NEXT_PUBLIC_ is safe to use in the browser. Variables without that prefix are server-only secrets.
Create the Supabase client file:
In your project, create a new folder called lib and inside it create a file called supabase.js:
// lib/supabase.js
import { createClient } from '@supabase/supabase-js'
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL
const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY
export const supabase = createClient(supabaseUrl, supabaseKey)
This creates one reusable Supabase connection that the rest of your app can import.
Step 5 — Update Your App to Use the Database
Now update app/page.js to load tasks from Supabase and save them there. Replace the entire file with:
'use client'
import { useState, useEffect } from 'react'
import { supabase } from '@/lib/supabase'
export default function Home() {
const [tasks, setTasks] = useState([])
const [newTask, setNewTask] = useState('')
const [loading, setLoading] = useState(true)
useEffect(() => {
fetchTasks()
}, [])
async function fetchTasks() {
setLoading(true)
const { data, error } = await supabase
.from('tasks')
.select('*')
.order('created_at', { ascending: false })
if (error) {
console.error('Error fetching tasks:', error)
} else {
setTasks(data || [])
}
setLoading(false)
}
async function addTask() {
if (!newTask.trim()) return
const { error } = await supabase
.from('tasks')
.insert([{ title: newTask.trim() }])
if (error) {
console.error('Error adding task:', error)
} else {
setNewTask('')
fetchTasks()
}
}
async function toggleTask(id, completed) {
const { error } = await supabase
.from('tasks')
.update({ completed: !completed })
.eq('id', id)
if (!error) fetchTasks()
}
async function deleteTask(id) {
const { error } = await supabase
.from('tasks')
.delete()
.eq('id', id)
if (!error) fetchTasks()
}
return (
<main className="max-w-xl mx-auto p-8">
<h1 className="text-3xl font-bold mb-2 text-gray-800">My Task Manager</h1>
<p className="text-gray-500 mb-6">Powered by Next.js + Supabase</p>
<div className="flex gap-2 mb-6">
<input
type="text"
value={newTask}
onChange={(e) => setNewTask(e.target.value)}
onKeyDown={(e) => e.key === 'Enter' && addTask()}
placeholder="Add a new task..."
className="flex-1 border border-gray-300 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
<button
onClick={addTask}
className="bg-blue-600 text-white px-5 py-2 rounded-lg hover:bg-blue-700 transition"
>
Add
</button>
</div>
{loading ? (
<p className="text-center text-gray-400 py-8">Loading tasks...</p>
) : (
<ul className="space-y-3">
{tasks.length === 0 && (
<p className="text-gray-400 text-center py-8">No tasks yet. Add one above!</p>
)}
{tasks.map((task) => (
<li key={task.id} className="flex items-center gap-3 p-4 bg-gray-50 rounded-lg border group">
<input
type="checkbox"
checked={task.completed}
onChange={() => toggleTask(task.id, task.completed)}
className="w-4 h-4 cursor-pointer"
/>
<span className={`flex-1 ${task.completed ? 'line-through text-gray-400' : 'text-gray-800'}`}>
{task.title}
</span>
<button
onClick={() => deleteTask(task.id)}
className="text-red-400 hover:text-red-600 opacity-0 group-hover:opacity-100 transition text-sm"
>
Delete
</button>
</li>
))}
</ul>
)}
</main>
)
}
Test it locally:
npm run dev
Visit http://localhost:3000. Add some tasks. Refresh the page — the tasks are still there! They are now saved in your Supabase database. You can even see them by going to your Supabase dashboard → Table Editor → tasks.
Commit this progress:
git add .
git commit -m "Connect Supabase database for persistent task storage"
git push
Step 6 — Deploy to Vercel
Vercel is the company that created Next.js. Their hosting platform is designed specifically for Next.js apps and has a free Hobby tier that is more than enough for personal and small projects.
Create a Vercel account:
- Go to vercel.com
- Click Sign Up
- Choose Continue with GitHub — Vercel will ask permission to access your repositories
- Authorize Vercel on GitHub
- On the welcome screen, select Personal and Hobby (free)
Import your project:
- In the Vercel dashboard, click Add New… → Project
- You will see a list of your GitHub repositories — find
my-task-managerand click Import - Vercel automatically detects that it is a Next.js project and configures the build settings
- Under Environment Variables, add your Supabase credentials:
- Name:
NEXT_PUBLIC_SUPABASE_URL| Value: your Supabase URL - Name:
NEXT_PUBLIC_SUPABASE_ANON_KEY| Value: your anon key - Click Add for each one
- Name:
- Click Deploy
Vercel will:
- Download your code from GitHub
- Install dependencies (
npm install) - Build your Next.js app (
npm run build) - Deploy it to their global CDN (servers around the world)
This takes about 1-2 minutes. When it finishes, Vercel gives you a live URL like https://my-task-manager-abc123.vercel.app. Click it — your app is live on the internet!
Step 7 — Connect a Custom Domain
Your site is live but has an ugly .vercel.app URL. Let’s connect a proper custom domain like mytasks.com.
First, you need to own a domain. If you do not have one yet, buy one from a domain registrar like Namecheap, Google Domains, or Cloudflare (usually $10-15/year for a .com).
Add the domain in Vercel:
- In the Vercel dashboard, open your project
- Click Settings → Domains
- Type your domain name (e.g.,
mytasks.com) and click Add - Vercel will show you DNS records to add
Update your DNS records at your domain registrar:
Log into wherever you bought your domain and look for “DNS Management” or “DNS Records.” You need to add:
For a root domain (yourdomain.com):
| Type | Name | Value |
|---|---|---|
| A | @ | 76.76.21.21 |
For www subdomain (www.yourdomain.com):
| Type | Name | Value |
|---|---|---|
| CNAME | www | cname.vercel-dns.com |
DNS changes take anywhere from a few minutes to 48 hours to propagate worldwide (usually under 30 minutes). Vercel automatically handles SSL/HTTPS — your site will have a padlock icon and a valid certificate at no extra cost.
Once the domain is verified, Vercel shows a green checkmark next to it and your custom domain is live.
Step 8 — The Auto-Deploy Magic
Here is where everything clicks together. From now on, every time you push code to GitHub, Vercel automatically rebuilds and deploys your site. You never have to touch Vercel again — just push to GitHub.
Let’s prove it. Make a small change to your app:
- Open
app/page.jsin VS Code - Change the title from
My Task ManagertoMy Awesome Task Manager - Save the file
- Run:
git add .
git commit -m "Update page title"
git push
Go to your Vercel dashboard and watch the Deployments tab. You will see a new deployment start automatically within seconds. After 1-2 minutes, your live site shows the updated title.
This is the professional development loop:
# The daily development workflow
# 1. Write code in VS Code
# 2. Test locally: npm run dev → http://localhost:3000
# 3. Commit and push to GitHub:
git add .
git commit -m "What I changed and why"
git push
# 4. Vercel auto-deploys — done!
Step 9 — Managing Environment Variables
Your app needs secret values (like database credentials) to work. These should NEVER be in your code or on GitHub. There are two places you manage them:
Local development — .env.local
The .env.local file on your computer stores secrets for local development. It is in your .gitignore so it is never uploaded to GitHub.
# .env.local (on your computer only — never commit this file)
NEXT_PUBLIC_SUPABASE_URL=https://yourproject.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Production — Vercel Dashboard
For your live site, environment variables are set in Vercel:
- Vercel Dashboard → your project → Settings → Environment Variables
- Add your variables here with Production, Preview, and Development scopes
- After adding or changing variables, redeploy by pushing a new commit (or triggering a manual redeploy)
Rule of thumb for what belongs in environment variables:
- API keys and tokens — yes
- Database URLs and passwords — yes
- Payment processor keys — yes
- Your website’s name or color scheme — no (hardcode those)
Step 10 — Understanding Vercel Deployment Types
Vercel creates different kinds of deployments automatically:
| Deployment Type | When It Happens | URL |
|---|---|---|
| Production | Every push to main branch |
your custom domain |
| Preview | Every push to other branches or a Pull Request | unique-hash.vercel.app |
| Development | npm run dev on your computer |
localhost:3000 |
Preview deployments are extremely useful. When you are building a new feature, create a separate Git branch:
# Create a new branch to work on a feature
git checkout -b add-due-dates
# Work on your feature, then commit and push
git add .
git commit -m "Add due date field to tasks"
git push -u origin add-due-dates
Vercel automatically creates a preview deployment at a unique URL so you can test the feature live before it goes to production. When you are happy with it, merge the branch into main on GitHub and Vercel deploys it to production.
Step 11 — Full Production Checklist
Before you share your site with the world, go through this checklist:
Security
- ✅ No secrets in your code or GitHub (all in
.env.localand Vercel settings) - ✅ Supabase Row Level Security (RLS) is enabled on all tables
- ✅ HTTPS is active (Vercel does this automatically)
Performance
- ✅ Images are optimized (use Next.js
<Image>component instead of plain<img>) - ✅ App loads in under 3 seconds (check in Chrome DevTools → Network tab)
SEO and Sharing
- ✅ Add metadata to
app/layout.js:
// app/layout.js
export const metadata = {
title: 'My Task Manager',
description: 'A simple, fast task manager built with Next.js and Supabase',
openGraph: {
title: 'My Task Manager',
description: 'Stay organized with this full-stack task manager',
},
}
Monitoring
- ✅ Check Vercel’s Analytics tab (free basic analytics are built in)
- ✅ Check your deployment logs if anything breaks: Vercel → project → Deployments → click on a deployment → Functions tab
Troubleshooting Common Issues
Build fails on Vercel with “Module not found” error
This usually means you installed a package locally but forgot to commit package.json. Make sure you run git add . and commit after running npm install.
App works locally but not on Vercel — blank page or database error
Almost always caused by missing environment variables in Vercel. Go to Settings → Environment Variables and make sure NEXT_PUBLIC_SUPABASE_URL and NEXT_PUBLIC_SUPABASE_ANON_KEY are there. After adding them, you need to redeploy.
Tasks not saving — Supabase “row level security” error
Your Supabase table has RLS enabled (good!) but no policy allowing writes. Go to Supabase → Authentication → Policies and create a policy that allows the operations you need, or use the SQL from Step 3 to create an open policy for development.
“This site can’t be reached” after adding custom domain
DNS changes take time to propagate. Wait 30 minutes and try again. You can check propagation status at dnschecker.org — enter your domain and it shows which DNS servers worldwide have updated.
Environment variable changes not taking effect in production
Vercel only reads environment variables at build time. After changing them in the Vercel dashboard, you must trigger a new deployment (push a commit or click “Redeploy” in Vercel).
What You Have Built
Take a moment to appreciate what you have accomplished. Starting from zero, you have built and deployed a full-stack production web application that:
- ✅ Has a professional code editor setup (VS Code with extensions)
- ✅ Uses version control (Git + GitHub) — you can never permanently lose your work
- ✅ Has a real PostgreSQL database (Supabase) — data persists forever
- ✅ Is live on the internet (Vercel) — accessible from any device, anywhere in the world
- ✅ Has automatic deployments — push to GitHub, site updates in 2 minutes
- ✅ Has HTTPS/SSL — your users’ data is encrypted in transit
This is the exact same stack used by professional development teams at startups and tech companies. The difference between you and a professional developer is not which tools they use — it is how much they have practiced using them.
What to Learn Next
Now that you have the foundation, here are natural next steps for each layer of your stack:
Make your app more powerful with Supabase:
- Authentication — add user login so everyone has their own private tasks (
@supabase/auth-helpers-nextjs) - Real-time — tasks update instantly on all devices using Supabase Realtime subscriptions
- Storage — let users attach files or images to tasks
Make your app better with Next.js:
- Server Components — fetch data on the server for faster initial loads
- API Routes — create backend endpoints in the same project
- Middleware — protect pages that require login
Scale your deployment with Vercel:
- Analytics — understand where your users come from
- Edge Functions — run code geographically close to your users for ultra-low latency
- Cron Jobs — run scheduled tasks (daily emails, database cleanup)
The Stack That Powers Modern Web Apps
What you have built today uses the same fundamental architecture as apps like Linear, Notion, and Vercel’s own dashboard. The tools change (different databases, different frameworks), but the concept is identical:
- Write code locally in an editor
- Track changes with Git
- Backup and collaborate through GitHub
- Deploy automatically via CI/CD (Vercel does this for you)
- Persist data in a managed database (Supabase/PostgreSQL)
You are no longer a person who has never deployed a web application. You are a developer.
Have questions or hit a snag? Contact us — we help GTAVille readers get their first projects live.




