DEV Community

Cover image for DevLog: Building GritPath OS - Day 1 Using Convex
Xion Apex Academy
Xion Apex Academy

Posted on

DevLog: Building GritPath OS - Day 1 Using Convex

Hi Everyone! Creator X here 👋

As I promised last week, I'm diving into my latest project and sharing the journey with you all. First, I want to give a massive shout-out to Artem Lazarev - he's also on YouTube and was a real lifesaver for this project. Definitely check out his template; it's absolutely amazing!

My Tech Stack

Here's what I'm working with for this build:

  • Next.js - React framework
  • Shadcn/Tailwind - UI components and styling
  • Convex - Database and backend
  • Clerk Auth - Authentication
  • TypeScript - Type safety
  • Python - (not fully implemented yet)
  • Vercel - Deployment

Quick Check-in

How are you doing? What are you looking to achieve this week? Any new projects you're working on? Let me know in the comments!

Setting Up Next.js

Let's start with the basics. First, create your Next.js app:

npx create-next-app@latest my-app
Enter fullscreen mode Exit fullscreen mode

You'll get prompted with several questions:

  • What is your project named? my-app
  • Would you like to use TypeScript? Yes
  • Which linter would you like to use? ESLint
  • Would you like to use Tailwind CSS? Yes
  • Would you like your code inside a src/ directory? Yes
  • Would you like to use App Router? (recommended) Yes
  • Would you like to use Turbopack? (recommended) Yes
  • Would you like to customize the import alias? No

Setting Up Convex

Next, install the Convex library:

npm install convex
Enter fullscreen mode Exit fullscreen mode

Then run:

npx convex dev
Enter fullscreen mode Exit fullscreen mode

This sets up your environment and will ask you to login or work as a guest. Just follow the instructions to confirm your account. You can either import an existing project from the Convex dashboard or start fresh. Once done, it creates a convex/ folder with a _generated/ folder inside.

My Journey from Traditional Databases to Convex

Moving from traditional databases to Convex was definitely something different. At first, it's confusing, but once you start understanding the basics, it clicks.

Creating Your Schema

First, I created my schema.ts:

// convex/schema.ts
import { defineSchema, defineTable } from "convex/server";
import { v } from "convex/values";

export default defineSchema({
  users: defineTable({
    // Your user fields here
  }),
  // Add more tables as needed
});
Enter fullscreen mode Exit fullscreen mode

Pro tip: You can also use the import command if you have existing data:

npx convex import --table tasks sampleData.jsonl
Enter fullscreen mode Exit fullscreen mode

I only learned this later! 😅

Understanding Mutations (My "Aha!" Moment)

This is where I got confused initially. Convex uses something called mutations, and here's how I understand them:

Mutations are functions that handle your database operations - creating, updating, and retrieving data. They work as a bridge between your frontend and database.

Think of it this way:

  • Your .tsx page has a form (frontend)
  • Your mutation takes that form data and saves it to the database
  • The same mutation can pull data back to display it

They usually work in pairs. If you have business_profile.tsx, you'd have businessProfile.ts for the mutations.

Complete Mutation Example

Here's a simple, complete example of how mutations work:

Backend - Mutation file (convex/tasks.ts):

import { v } from "convex/values";
import { query, mutation } from "./_generated/server";

// Create a new task
export const createTask = mutation({
  args: {
    title: v.string(),
    description: v.string(),
  },
  handler: async (ctx, args) => {
    const taskId = await ctx.db.insert("tasks", {
      title: args.title,
      description: args.description,
      completed: false,
      createdAt: Date.now(),
    });
    return taskId;
  },
});

// Get all tasks
export const getAllTasks = query({
  args: {},
  handler: async (ctx) => {
    return await ctx.db.query("tasks").collect();
  },
});
Enter fullscreen mode Exit fullscreen mode

Frontend - React Component (app/tasks/page.tsx):

"use client";
import React, { useState } from 'react';
import { useMutation, useQuery } from "convex/react";
import { api } from "@/convex/_generated/api";

export default function TasksPage() {
  const [title, setTitle] = useState("");
  const [description, setDescription] = useState("");

  const createTask = useMutation(api.tasks.createTask);
  const tasks = useQuery(api.tasks.getAllTasks);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    await createTask({ title, description });
    setTitle("");
    setDescription("");
  };

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input
          value={title}
          onChange={(e) => setTitle(e.target.value)}
          placeholder="Task title"
          required
        />
        <textarea
          value={description}
          onChange={(e) => setDescription(e.target.value)}
          placeholder="Task description"
        />
        <button type="submit">Add Task</button>
      </form>

      <div>
        {tasks?.map((task) => (
          <div key={task._id}>
            <h3>{task.title}</h3>
            <p>{task.description}</p>
          </div>
        ))}
      </div>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Schema (convex/schema.ts):

import { defineSchema, defineTable } from "convex/server";
import { v } from "convex/values";

export default defineSchema({
  tasks: defineTable({
    title: v.string(),
    description: v.string(),
    completed: v.boolean(),
    createdAt: v.number(),
  }),
});
Enter fullscreen mode Exit fullscreen mode

Important: All mutations must go in your convex/ folder so they get added to _generated/.

Setting Up the Client Provider

Create ConvexClientProvider.tsx in your app/ folder. This allows your app to communicate with Convex:

// This wraps ConvexProvider and passes ConvexReactClient
Enter fullscreen mode Exit fullscreen mode

Then wrap your app/layout.tsx children with <ConvexClientProvider>.

Displaying Data

To show your data on the frontend:

import { useQuery } from "convex/react";
import { api } from "../convex/_generated/api";
Enter fullscreen mode Exit fullscreen mode

Common Issues I Encountered (Save Yourself Some Pain!)

  1. Run npx convex dev strategically - Don't run it after every single file creation. Create a few pages first, then run it. You'll get fewer errors and they're more manageable.

  2. _generated folder not updating? - Sometimes after running npx convex dev, the _generated/ folder doesn't update properly. If this happens:

   rm -r _generated/
   npx convex dev
Enter fullscreen mode Exit fullscreen mode

It's safe to delete - Convex will recreate it.

  1. Check the dashboard logs - If you get TypeScript errors that don't make sense, check your Convex dashboard logs. They often have more detailed error information.

  1. Test your functions - Cool feature: you can test functions directly in the Convex dashboard! Select a function and click "Run function" on the right.

Environment Variables and Deployment

In your Convex settings, you'll find:

  • Deployment URL
  • HTTP Actions URL

Copy these to your Vercel environment variables so they can communicate properly. You can also add other environment variables that work with your Convex database there.

Final Thoughts

To be honest, I used to hate databases with a passion. I've tried several and failed miserably. The only two I actually enjoy working with are PostgreSQL and now Convex. What I love about Convex is how straightforward it becomes once you understand the basics.

My advice: take your time and enjoy the process. The learning curve is worth it!

What's Next?

In my next post, I'll dive into Clerk authentication and deployment.

The project I'm building is called GritPath OS - a platform that helps businesses create blueprints to level up. I'm thrilled to say I finally got it on Product Hunt! 🎉

That's part one of my dev journal, with plenty more to come.


Note: These guides are aimed at helping beginners. If you have more experience with Convex, please drop your insights in the comments!

Thanks for reading, and don't forget to say hello! 👋


What challenges have you faced when switching to new databases? Let me know in the comments!

Top comments (0)