You can build a database-powered app with end-to-end type safety and real-time updates without needing to learn how to manage databases. This tutorial will show you how.
- Finished app: https://convex-dashboard-react.netlify.app/
- Source code: https://github.com/learnwithjason/dashboard-convex-react
Prefer to watch instead of reading? I’ve got you!
If you learn better by watching and listening, I’ve got a video version of this tutorial up on YouTube. (Don’t forget to subscribe if it’s useful!)
For frontend devs, databases can be intimidating
If you’re a web developer like me, you probably have exciting ideas for new apps all the time.
Most of my app ideas hit the same challenge: building them would require setting up a database.
And I don’t know you, but when I start thinking about all the work that goes into setting up and managing a database, I always tend to land on the same solution: I convince myself that my app idea wasn’t that good, and I give up.
At least that’s how I used to feel. These days, there’s a new wave of innovation happening in the database space that’s flattening the learning curve for web developers who want to add data to their apps, even if they’d describe themselves as a frontend developer or — as Brad Frost once said — a “front-of-the-frontend” developer.
Build a data-powered app for reacting to dogs
This tutorial will step through adding a Convex database to a web app and using it to store information about dogs and how people have reacted to those dogs. It will have a home page where people can react, and a stats view for showing aggregate data about reactions for each dog.
The app is built using React started from the Vite React TypeScript starter. (
npm create vite --template react-ts)
Clone the repo and get local development running
For this app, we’ll start with the frontend already built out and styled. Clone the
start branch of the tutorial repo, install dependencies, and start the dev server:
This is a Vite-powered project, so the local dev server starts at
http://localhost:5173. Open it in your browser and you’ll see the app:
The home page shows a list of pups, each with a few buttons to let us react. If we toggle to the stats page, we can see the aggregate of how many times each reaction has been hit for each pup.
Right now all the data is hard-coded. We’re going to use Convex to store both our pup data and reaction data.
Install and start Convex in the web app
Keep the local dev server running in your terminal. Open up a second terminal and install the
Next, start Convex in dev mode:
This will take you through the process of setting up a Convex account, then ask you for the name of your project and generate
.env files for local and production development.
dev command will stay running while we work to keep our local app connected to the Convex datastore.
Define a type-safe database schema
Because we want type safety and autocomplete, our first step is to define a schema. The
convex package provides the helpers we need to define the overall schema, data tables, and the field types within the table.
Create a new file at
The Convex CLI will automatically update once this file is saved, configuring everything on the backend for us so we don’t need to deal with dashboards or additional config.
Wrap the React app with Convex provider
To make sure our app has access to Convex data, wrap it in the Convex provider component by making the following changes in
Creating a client lets the provider know which Convex project we’re working with, and the provider makes sure we can run queries and mutations from any component that’s rendered inside the provider.
The environment variable (
import.meta.env.VITE_CONVEX_URL) was automatically added to
.env.local when we started Convex.
Create and display pup entries
Next, we can define how we create and read data to the tables we just defined. Let’s start with the pups.
Create a new file at
Make sure to type out the
db.insert() part of this code in your editor. It’s extremely cool that the function autocompletes with the names of our two schema tables. Plus, once we select a table, the second argument to
db.insert() knows what the fields are.
This is a killer feature of Convex: the database is automatically type safe and we haven’t defined any types ourselves, let alone had to mess with configuration files. It Just Works™.
Next up, let’s modify the home page to add pups to the database and read them out on screen.
src/components/list.tsx and make the following changes:
Did you see
useQuery() autocomplete with our pup query? Again: this Just Works™. Hover over
pups and you’ll see what data each pup includes.
Right now, the home page will be empty since there aren’t any pups in the database yet. Let’s fix that.
addPup() function to use a Convex mutation by making the following change:
The code is already written to check if the pups array is empty and add the seed data if so, which means once we save this file, our pup data will be sent to Convex and we’ll see it loaded on the page.
Create and display reactions
Next, we want users in our app to be able to react to each pup and see how other people have reacted to them as well.
Let’s start by defining a mutation to store new reactions and a query to read them out grouped by reaction type and the pup that was reacted to. In a new file at
convex/reactions.ts, add the following:
The mutation is pretty straightforward, but that query might look a little intense. For the bar chart to work, we need to deliver reaction data in the following format:
The code inside the query uses the reaction data to load the right pup data, then uses nested reducers (😅) to shape the data into the format we need.
Next, let’s hook up our buttons to save a new reaction in the database. Make one last change to
Save, then click a few of the reactions on your favorite pups to add some reaction entries to the database.
To display these reaction stats, open up
src/components/bar-chart.tsx and make the following change:
Save and navigate to the stats and you’ll see that the reaction data now corresponds to how many reactions you’ve added.
Deploy a Convex app to production
To deploy the app, follow the deployment instructions in the Convex docs.
- Commit all your changes (including the
.envfile — the Convex URL is not sensitive) and get them up on GitHub
- Go to app.netlify.com and either sign in or create an account using your GitHub login
- Get your deploy key from the Convex Dashboard
- Add it as an environment variable called
- Set your build command to
npx convex deploy && npm run build
The site will build and deploy to a public URL. Open it up and add some reactions! Your database-powered app is now deployed and running!
But wait, there’s more!
If getting a fully type-safe data workflow isn’t cool enough for you, there’s one more built-in bonus when you choose Convex as your data layer: real-time updates Just Work™.
Open your live site in two browser windows. On one, load the home page with all the pups. In the other, load the stats. Add some reactions and watch the chart update in real time! For even more fun, open the site on your phone and watch the browser update as you tap away on your favorite pups.
This reactivity is automatic, so you don’t have to configure anything for it to work. You’ll even see realtime updates if you edit your data directly in the Convex dashboard!
Databases are for everyone now — even front-of-the-frontend developers
For web devs who would describe themselves as frontend developers or even “front of the frontend devs”, working with data might feel like a lot — but hopefully this tutorial made it feel a little more approachable.
Get out there and build all those fun app ideas!