Convex Setup
Create a Convex project, configure auth providers, and connect your app.
Convex Setup
Convex is the backend for ScaleRocket. It handles your database, authentication, real-time subscriptions, and serverless functions — all in TypeScript.
Create a Convex Account
- Go to convex.dev
- Click Sign up and create your account
- You can sign up with GitHub or Google
Initialize Your Project
From the root of your project, run:
npx convex devOn first run, this will:
- Prompt you to log in (if you haven't already)
- Create a new Convex project (or link to an existing one)
- Deploy your schema and functions
- Start watching for changes and hot-reloading
Note:
npx convex devis the main command you'll use during development. It watches yourconvex/directory and auto-deploys changes in real time.
Get Your Deployment URL
- Go to dashboard.convex.dev
- Select your project
- Copy the Deployment URL (looks like
https://your-project-123.convex.cloud) - Add it to your environment file:
# apps/app/.env.local
VITE_CONVEX_URL=https://your-project-123.convex.cloudConfigure Auth Providers
ScaleRocket supports email/password, Google, and GitHub login out of the box.
Set your environment variables via the Convex CLI:
# Site URL (your app's public URL)
npx convex env set SITE_URL https://your-app.com
# GitHub OAuth
npx convex env set AUTH_GITHUB_ID your-github-client-id
npx convex env set AUTH_GITHUB_SECRET your-github-client-secret
# Google OAuth
npx convex env set AUTH_GOOGLE_ID your-google-client-id
npx convex env set AUTH_GOOGLE_SECRET your-google-client-secretGitHub OAuth
- Go to GitHub Developer Settings
- Click New OAuth App
- Set the authorization callback URL to your
SITE_URL - Copy the Client ID and Client Secret
- Set them with
npx convex env setas shown above
Google OAuth
- Go to Google Cloud Console
- Create a new project (or use an existing one)
- Go to APIs & Services > Credentials
- Create an OAuth 2.0 Client ID (Web application)
- Add your
SITE_URLas an authorized redirect URI - Copy the Client ID and Client Secret
- Set them with
npx convex env setas shown above
Schema Overview
With Convex, your schema is defined entirely in TypeScript:
// convex/schema.ts
import { defineSchema, defineTable } from "convex/server";
import { v } from "convex/values";
export default defineSchema({
profiles: defineTable({
userId: v.string(),
name: v.string(),
email: v.string(),
avatarUrl: v.optional(v.string()),
}).index("by_userId", ["userId"]),
subscriptions: defineTable({
userId: v.string(),
stripeSubscriptionId: v.string(),
status: v.string(),
}).index("by_userId", ["userId"]),
});The schema is automatically deployed when you run npx convex dev. There are no migrations to manage — Convex handles schema changes for you.
Note: Convex validates all data against your schema at runtime. If a mutation tries to insert data that doesn't match, it will throw an error.
Convex Functions
Convex provides four types of functions:
| Type | Purpose | Example use case |
|---|---|---|
| Queries | Read data (cached & reactive) | Fetching a user's profile |
| Mutations | Write data (transactional) | Updating a subscription status |
| Actions | Call external APIs (non-transactional) | Sending an email, calling Stripe |
| HTTP Actions | Handle incoming webhooks | Stripe webhook endpoint |
Query Example
// convex/profiles.ts
import { query } from "./_generated/server";
import { v } from "convex/values";
export const getProfile = query({
args: { userId: v.string() },
handler: async (ctx, args) => {
return await ctx.db
.query("profiles")
.withIndex("by_userId", (q) => q.eq("userId", args.userId))
.unique();
},
});Mutation Example
// convex/profiles.ts
import { mutation } from "./_generated/server";
import { v } from "convex/values";
export const updateProfile = mutation({
args: { userId: v.string(), name: v.string() },
handler: async (ctx, args) => {
const profile = await ctx.db
.query("profiles")
.withIndex("by_userId", (q) => q.eq("userId", args.userId))
.unique();
if (!profile) throw new Error("Profile not found");
await ctx.db.patch(profile._id, { name: args.name });
},
});Action Example
// convex/emails.ts
import { action } from "./_generated/server";
import { v } from "convex/values";
export const sendWelcomeEmail = action({
args: { email: v.string(), name: v.string() },
handler: async (ctx, args) => {
// Call an external email API
await fetch("https://api.your-email-service.com/send", {
method: "POST",
body: JSON.stringify({
to: args.email,
subject: `Welcome, ${args.name}!`,
}),
});
},
});Real-time
All useQuery hooks in Convex are reactive by default. When the underlying data changes, your components re-render automatically — no extra setup needed.
// apps/app/src/components/Profile.tsx
import { useQuery } from "convex/react";
import { api } from "../../convex/_generated/api";
export function Profile({ userId }: { userId: string }) {
const profile = useQuery(api.profiles.getProfile, { userId });
if (!profile) return <div>Loading...</div>;
return <div>{profile.name}</div>;
}Note: There is no need for polling, WebSocket setup, or cache invalidation. Convex handles all of this for you. When any mutation updates data that a query depends on, all subscribed clients receive the update instantly.
Convex Dashboard
Convex comes with a built-in dashboard at dashboard.convex.dev where you can:
- Browse and edit your data tables
- View and run your functions
- Monitor logs and errors
- Manage environment variables
- View deployment history
Note: The dashboard is a great tool for debugging during development. You can inspect your data, run queries manually, and see real-time logs.
Next Steps
- Configure Stripe for payments
- Set up authentication flows in the dashboard
- Create API endpoints for your API
Done reading? Mark this page as complete.