How to Create a CRUD App Using Next.js and Supabase
Develop a Full-Stack Application Quickly Using Next.js and Supabase
In today's fast-paced web development world, creating full-stack applications quickly and efficiently is more important than ever. This is where Next.js and Supabase come into play, offering a powerful combination for building robust, scalable web applications with minimal backend configuration.
In this tutorial, we'll walk through the process of building a simple CRUD (Create, Read, Update, Delete) application using Next.js for our frontend and Supabase as our backend-as-a-service (BaaS) solution. By the end of this guide, you'll have a functional web app that allows you to manage a list of items, demonstrating the core operations of any data-driven application.
We'll cover:
Setting up a Next.js project
Creating a Supabase project and connecting it to our app
Implementing each CRUD operation with Next.js and Supabase
Whether you're a seasoned developer looking to streamline your stack or a beginner eager to build your first full-stack application, this tutorial will provide you with the knowledge to get started with this powerful tech combo.
Let's dive in and start building!
What is Supabase?
Supabase is an open-source Firebase alternative that provides a suite of tools for building scalable web applications. It offers a powerful combination of services that traditionally required juggling multiple providers or building from scratch. Here's what makes Supabase stand out:
PostgreSQL Database: At its core, Supabase provides a PostgreSQL database, offering the robustness and features of this popular relational database system.
Real-time Subscriptions: Built-in support for real-time data syncing, allowing your app to instantly react to database changes.
Authentication: A complete authentication system that supports email/password, magic links, and various OAuth providers.
Auto-generated APIs: Supabase automatically creates RESTful APIs for your database, saving you time on backend development.
Storage: Built-in storage solution for managing large files like images and videos.
Edge Functions: Serverless functions for running your backend code.
For our CRUD app, we'll primarily be using Supabase's database and auto-generated APIs. This will allow us to focus on building our Next.js frontend while Supabase handles the heavy lifting on the backend.
The combination of Next.js and Supabase is particularly powerful because it allows developers to build full-stack applications with JavaScript/TypeScript across the entire stack. This uniformity can significantly speed up development and reduce the complexity of your project.
Setting Up Your Project
To get started with our CRUD app, we need to set up both our Next.js frontend and our Supabase backend. Let's tackle these one at a time.
Creating a Next.js App
Open your terminal and run the following command:
npx create-next-app@latest crud-app-nextjs-supabase
When prompted, choose the following options:
Would you like to use TypeScript? › Yes
Would you like to use ESLint? › Yes
Would you like to use Tailwind CSS? › Yes
Would you like to use
src/
directory? › NoWould you like to use App Router? › Yes
Would you like to customize the default import alias? › No
Once the installation is complete, navigate to your project directory:
cd crud-app-nextjs-supabase
Setting up a Supabase Project
Go to supabase.com and sign up or log in.
Click on "New project" and give your project a name.
Choose a database password and your region. Note down the password for later use.
Click "Create new project" and wait for your project to be provisioned.
Once your project is ready, go to the "Settings" section in the sidebar, then "API".
You'll find your project URL and anon public API key here. We'll need these to connect our Next.js app to Supabase.
Installing Supabase Client
Back in your terminal, install the Supabase client library:
npm install @supabase/supabase-js
With these steps completed, you now have a Next.js project set up and a Supabase project ready to use. In the next section, we'll connect these two pieces together.
Connecting Next.js to Supabase
Now that we have both our Next.js app and Supabase project set up, it's time to connect them. We'll create a Supabase client that we can use throughout our application.
First, create a new file called
.env.local
in the root of your Next.js project. Add the following content, replacing the placeholder values with your actual Supabase project details:NEXT_PUBLIC_SUPABASE_URL=your-project-url NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
Next, create a new file
utils/supabase.ts
in your project directory. Add the following code: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 a Supabase client that we can import and use in our components.
Now, let's set up our database table. Go to your Supabase project dashboard, navigate to the "Table Editor" section, and create a new table called "items" with the following structure:
id: int8 (primary key, auto-increment)
created_at: timestamptz (default: now())
name: text
description: text
To test our connection, let's modify the
app/page.tsx
file to fetch and display items from our Supabase database:import { supabase } from '../utils/supabase' export default async function Home() { const { data: items, error } = await supabase .from('items') .select('*') if (error) { console.error('Error fetching items:', error) } return ( <main className="flex min-h-screen flex-col items-center justify-between p-24"> <h1 className="text-4xl font-bold mb-8">My Items</h1> <ul> {items?.map((item) => ( <li key={item.id}>{item.name}</li> ))} </ul> </main> ) }
Start your Next.js development server:
npm run dev
Visit http://localhost:3000
in your browser. You should see a page with the title "My Items" and an empty list (assuming you haven't added any items to your database yet).
Congratulations! You've successfully connected your Next.js app to Supabase. In the next section, we'll implement the full CRUD functionality.
Excellent. Let's move on to implementing the CRUD (Create, Read, Update, Delete) operations. We'll cover each operation one by one, keeping our explanations concise but informative.
Implementing CRUD Operations
Now that our Next.js app is connected to Supabase, let's implement the four CRUD operations: Create, Read, Update, and Delete.
Create: Adding New Items
Let's add a form to create new items:
- Update
app/page.tsx
:
'use client'
import { useState } from 'react'
import { supabase } from '../utils/supabase'
export default function Home() {
const [items, setItems] = useState([])
const [newItemName, setNewItemName] = useState('')
const [newItemDescription, setNewItemDescription] = useState('')
const fetchItems = async () => {
const { data, error } = await supabase.from('items').select('*')
if (error) console.error('Error fetching items:', error)
else setItems(data)
}
const addItem = async (e) => {
e.preventDefault()
const { data, error } = await supabase
.from('items')
.insert([{ name: newItemName, description: newItemDescription }])
.select()
if (error) console.error('Error adding item:', error)
else {
setNewItemName('')
setNewItemDescription('')
fetchItems()
}
}
return (
<main className="flex min-h-screen flex-col items-center justify-between p-24">
<h1 className="text-4xl font-bold mb-8">My Items</h1>
<form onSubmit={addItem} className="mb-8">
<input
type="text"
value={newItemName}
onChange={(e) => setNewItemName(e.target.value)}
placeholder="Item name"
className="mr-2 p-2 border rounded"
/>
<input
type="text"
value={newItemDescription}
onChange={(e) => setNewItemDescription(e.target.value)}
placeholder="Item description"
className="mr-2 p-2 border rounded"
/>
<button type="submit" className="p-2 bg-blue-500 text-white rounded">Add Item</button>
</form>
<ul>
{items.map((item) => (
<li key={item.id}>{item.name}: {item.description}</li>
))}
</ul>
</main>
)
}
Read: Fetching and Displaying Items
We've already implemented the read operation in the code above. The fetchItems
function retrieves all items from the database, and we display them in an unordered list.
Update: Modifying Existing Items
Let's add the ability to update items:
// Add this function inside the Home component
const updateItem = async (id, newName, newDescription) => {
const { error } = await supabase
.from('items')
.update({ name: newName, description: newDescription })
.eq('id', id)
if (error) console.error('Error updating item:', error)
else fetchItems()
}
// Modify the list rendering to include an update button
<ul>
{items.map((item) => (
<li key={item.id}>
{item.name}: {item.description}
<button onClick={() => updateItem(item.id, prompt('New name'), prompt('New description'))}>
Update
</button>
</li>
))}
</ul>
Delete: Removing Items
Finally, let's add the ability to delete items:
// Add this function inside the Home component
const deleteItem = async (id) => {
const { error } = await supabase
.from('items')
.delete()
.eq('id', id)
if (error) console.error('Error deleting item:', error)
else fetchItems()
}
// Modify the list rendering to include a delete button
<ul>
{items.map((item) => (
<li key={item.id}>
{item.name}: {item.description}
<button onClick={() => updateItem(item.id, prompt('New name'), prompt('New description'))}>
Update
</button>
<button onClick={() => deleteItem(item.id)}>Delete</button>
</li>
))}
</ul>
With these changes, you now have a fully functional CRUD application using Next.js and Supabase!
Conclusion
Congratulations! You've successfully built a basic CRUD (Create, Read, Update, Delete) application using Next.js and Supabase. Let's recap what we've accomplished:
Set up a Next.js project and a Supabase backend
Connected our Next.js app to Supabase
Implemented all four CRUD operations:
Created new items
Read and displayed items from the database
Updated existing items
Deleted items from the database
This simple application demonstrates the power and simplicity of combining Next.js with Supabase. With just a few lines of code, we've created a fully functional web application with a robust backend.
Next Steps
To further enhance your application, consider exploring these areas:
Implement authentication: Supabase offers easy-to-use authentication. Try adding user sign-up and login to your app.
Improve the UI: Use Tailwind CSS or another styling solution to make your app more visually appealing.
Add real-time functionality: Supabase supports real-time subscriptions. Try updating your list of items in real-time when changes occur.
Server-side rendering: Explore Next.js's server-side rendering capabilities to improve your app's performance and SEO.
Error handling: Implement more robust error handling and user feedback for a better user experience.
Remember, this is just the beginning. The combination of Next.js and Supabase provides a powerful foundation for building complex, scalable web applications. Keep exploring, and happy coding!