S
Solo Kit
DocumentationComponentsPricingChangelogRoadmapFAQContact
LoginGet Started
DocumentationComponentsPricing
LoginGet Started
Welcome to Solo Kit DocumentationIntroductionTech StackRoadmapFAQGetting Started
Database OverviewSchema DesignDatabase QueriesDatabase MigrationsDatabase SeedingDatabase PerformanceDatabase SecurityBackup & RestoreDatabase MonitoringAdvanced Database Features
Database

Database Overview

Database Overview

Solo Kit uses Convex - a reactive, serverless database platform that combines database, backend functions, and real-time sync in one unified system. This guide covers everything from basic concepts to advanced database management.

πŸ—οΈ Architecture Overview

Convex-First Design

Solo Kit is built with Convex, providing:

  • Type Safety - End-to-end TypeScript with generated types
  • Real-time - Automatic UI updates when data changes
  • Serverless - Zero operations, automatic scaling
  • Consistency - Same development experience from dev to production

Technology Stack

πŸ“Š Application Layer (React/Next.js)
    ↓ (useQuery, useMutation hooks)
πŸ”§ Convex Functions (TypeScript)
    ↓ (Type-safe queries/mutations)
πŸ’Ύ Convex Database (Document store)
    ↓ (Global distribution)
☁️  Convex Cloud (Managed infrastructure)

πŸ—‚οΈ Database Structure

Convex Organization

apps/web/convex/
β”œβ”€β”€ schema.ts            # Database schema definition
β”œβ”€β”€ _generated/          # Auto-generated types
β”‚   β”œβ”€β”€ api.ts          # API exports
β”‚   β”œβ”€β”€ server.ts       # Server types
β”‚   └── dataModel.ts    # Data model types
β”œβ”€β”€ users.ts            # User functions
β”œβ”€β”€ auth.ts             # Authentication functions
β”œβ”€β”€ sessions.ts         # Session management
└── payments.ts         # Payment functions

πŸ”§ Core Concepts

Schema Definition

Type-Safe Schema:

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

export default defineSchema({
  users: defineTable({
    name: v.string(),
    email: v.string(),
    image: v.optional(v.string()),
    emailVerified: v.optional(v.boolean()),
    createdAt: v.number(),
  }).index('by_email', ['email']),

  sessions: defineTable({
    userId: v.id('users'),
    expiresAt: v.number(),
    token: v.string(),
  })
    .index('by_user', ['userId'])
    .index('by_token', ['token']),
});

Benefits:

  • Automatic type generation
  • Runtime validation
  • Built-in indexing
  • Real-time reactivity

Convex Functions

Three types of functions handle all backend logic:

Queries (Read Data):

import { query } from './_generated/server';
import { v } from 'convex/values';

export const getUser = query({
  args: { userId: v.id('users') },
  handler: async (ctx, { userId }) => {
    return await ctx.db.get(userId);
  },
});

Mutations (Write Data):

import { mutation } from './_generated/server';
import { v } from 'convex/values';

export const createUser = mutation({
  args: {
    name: v.string(),
    email: v.string(),
  },
  handler: async (ctx, args) => {
    return await ctx.db.insert('users', {
      ...args,
      emailVerified: false,
      createdAt: Date.now(),
    });
  },
});

Actions (External Operations):

import { action } from './_generated/server';
import { v } from 'convex/values';

export const sendEmail = action({
  args: {
    to: v.string(),
    subject: v.string(),
  },
  handler: async (ctx, { to, subject }) => {
    // Call external email service
    await fetch('https://api.email.com/send', {
      method: 'POST',
      body: JSON.stringify({ to, subject }),
    });
  },
});

πŸ’» Using Convex in Your App

Client Components

Real-time reactive data:

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

export function UserProfile({ email }: { email: string }) {
  // Automatically updates when data changes
  const user = useQuery(api.users.getUserByEmail, { email });
  const updateUser = useMutation(api.users.updateUser);

  if (!user) return <div>Loading...</div>;

  return (
    <div>
      <h1>{user.name}</h1>
      <button onClick={() => updateUser({ userId: user._id, name: "New Name" })}>
        Update Name
      </button>
    </div>
  );
}

Server Components

Fetch data for SSR:

import { fetchQuery } from "convex/nextjs";
import { api } from "@/convex/_generated/api";

export default async function UserPage({ params }: { params: { id: string } }) {
  const user = await fetchQuery(api.users.getUser, {
    userId: params.id as Id<"users">
  });

  return <div>{user.name}</div>;
}

πŸš€ Getting Started

1. Initialize Convex

# Start Convex dev server
npx convex dev

This will:

  • Create a Convex project
  • Set up your convex/ directory
  • Add environment variables
  • Start the dev server

2. Define Your Schema

Create convex/schema.ts:

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

export default defineSchema({
  users: defineTable({
    email: v.string(),
    name: v.string(),
  }).index('by_email', ['email']),
});

3. Create Functions

Create convex/users.ts:

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

export const list = query({
  handler: async (ctx) => {
    return await ctx.db.query('users').collect();
  },
});

export const create = mutation({
  args: {
    email: v.string(),
    name: v.string(),
  },
  handler: async (ctx, args) => {
    return await ctx.db.insert('users', args);
  },
});

4. Use in Your App

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

export function Users() {
  const users = useQuery(api.users.list);
  const createUser = useMutation(api.users.create);

  return (
    <div>
      {users?.map(user => <div key={user._id}>{user.name}</div>)}
      <button onClick={() => createUser({ email: "new@example.com", name: "New User" })}>
        Add User
      </button>
    </div>
  );
}

🎯 Key Features

Real-time Updates

Convex queries automatically subscribe to data changes:

// Component re-renders automatically when data changes
const users = useQuery(api.users.list);

Type Safety

TypeScript types are generated from your schema:

import { Doc, Id } from './_generated/dataModel';

type User = Doc<'users'>;
type UserId = Id<'users'>;

Performance

  • Automatic indexing
  • Query optimization
  • Global edge deployment
  • WebSocket connections for real-time

Developer Experience

  • Local dev server with instant feedback
  • Dashboard for data browsing
  • Function logs and performance metrics
  • Built-in testing utilities

πŸ“Š Best Practices

Schema Design

  • Use indexes for frequently queried fields
  • Keep documents relatively flat
  • Use references (IDs) to link documents
  • Add search indexes for text search

Query Optimization

  • Use indexes for filtering
  • Limit results with .take(n)
  • Paginate large result sets
  • Avoid full table scans

Security

  • Implement authorization in functions
  • Validate inputs with Convex validators
  • Never expose sensitive data
  • Use function-level security checks

πŸ“š Learn More

  • Schema Definition
  • Querying Data
  • Mutations
  • Real-time
  • Performance

πŸ†˜ Getting Help

  • Convex Documentation
  • Convex Discord
  • Solo Kit Issues

πŸŽ“ Quick Reference

Common Operations

// Get by ID
const user = await ctx.db.get(userId);

// Query with index
const user = await ctx.db
  .query('users')
  .withIndex('by_email', (q) => q.eq('email', email))
  .first();

// Insert
const userId = await ctx.db.insert('users', {
  name: 'John',
  email: 'john@example.com',
});

// Update
await ctx.db.patch(userId, {
  name: 'John Updated',
});

// Delete
await ctx.db.delete(userId);

Environment Variables

# Required for Convex
NEXT_PUBLIC_CONVEX_URL=https://your-project.convex.cloud
CONVEX_DEPLOY_KEY=your-deploy-key

CLI Commands

# Start dev server
npx convex dev

# Deploy to production
npx convex deploy

# View dashboard
npx convex dashboard

# Clear local data
npx convex data clear

Next Steps:

  1. Define your schema
  2. Create your first functions
  3. Deploy to production

Getting Started

Learn how to set up and run Solo Kit locally

Schema Design

Design robust, scalable database schemas with Convex, proper relationships, and best practices

On this page

Database OverviewπŸ—οΈ Architecture OverviewConvex-First DesignTechnology StackπŸ—‚οΈ Database StructureConvex OrganizationπŸ”§ Core ConceptsSchema DefinitionConvex FunctionsπŸ’» Using Convex in Your AppClient ComponentsServer ComponentsπŸš€ Getting Started1. Initialize Convex2. Define Your Schema3. Create Functions4. Use in Your App🎯 Key FeaturesReal-time UpdatesType SafetyPerformanceDeveloper ExperienceπŸ“Š Best PracticesSchema DesignQuery OptimizationSecurityπŸ“š Learn MoreπŸ†˜ Getting HelpπŸŽ“ Quick ReferenceCommon OperationsEnvironment VariablesCLI Commands