Skip to main content

Overview

The TWIGZ backend uses the @convex-dev/migrations library to define and run database migrations. Migrations handle schema evolution by backfilling new fields on existing records, ensuring all documents conform to the latest schema requirements. Location: convex/migrations.ts
Migrations process records one at a time using migrateOne. Each migration only modifies records that are missing the target fields, making them safe to run multiple times (idempotent).

Running Migrations

Migrations are executed using the exported run function, which is a Convex mutation that can be invoked from the Convex dashboard or programmatically.
import { api } from "../convex/_generated/api";

// Run all pending migrations
await convex.mutation(api.migrations.run);

Migration Functions

addStatusToStores

Adds a status field to existing store documents that are missing it.
PropertyValue
Tablestores
Field Addedstatus
Default Value"pending"
ConditionOnly applies to stores without a status field
export const addStatusToStores = migrations.define({
  table: "stores",
  migrateOne: async (ctx, store) => {
    if (!("status" in store)) {
      return { status: "pending" as const };
    }
  },
});

ensureStoreFields

A comprehensive migration that ensures all stores have the required fields. Handles multiple missing fields in a single pass.
PropertyValue
Tablestores
Fields Addedstatus, phoneNumberVerified
Default Valuesstatus: "pending", phoneNumberVerified: false
ConditionOnly updates stores missing one or more of the target fields
export const ensureStoreFields = migrations.define({
  table: "stores",
  migrateOne: async (ctx, store) => {
    const updates: any = {};
    if (!("status" in store)) {
      updates.status = "pending" as const;
    }
    if (!("phoneNumberVerified" in store)) {
      updates.phoneNumberVerified = false;
    }
    return Object.keys(updates).length > 0 ? updates : undefined;
  },
});

addUsernamesToCustomers

Generates unique usernames for existing customers that do not have one. Derives the username from the customer’s name, appending numeric suffixes to resolve conflicts.
PropertyValue
Tablecustomers
Field Addedusername
Default ValueDerived from customer.name (lowercased, alphanumeric, max 12 chars)
ConditionOnly applies to customers without a username field or with a falsy value
Username generation strategy:
1

Base Name

Takes the customer’s name, converts to lowercase, strips non-alphanumeric characters, and truncates to 12 characters.
2

Uniqueness Check

Queries the by_username index to verify availability. If taken, appends an incrementing numeric suffix (e.g., john1, john2).
3

Fallback

After 999 attempts, falls back to a user_{timestamp} format with an optional random suffix for guaranteed uniqueness.

addPrivacyToCustomers

Sets a default privacy setting for existing customers that do not have one.
PropertyValue
Tablecustomers
Field AddedisPrivate
Default Valuetrue
ConditionOnly applies to customers without isPrivate or where it is undefined
This migration defaults existing customers to private (isPrivate: true). New customers created after this field was added to the schema may have a different default depending on the registration flow.

Migration Summary

MigrationTableFieldsDefault Values
addStatusToStoresstoresstatus"pending"
ensureStoreFieldsstoresstatus, phoneNumberVerified"pending", false
addUsernamesToCustomerscustomersusernameDerived from name
addPrivacyToCustomerscustomersisPrivatetrue

Best Practices

Create a new migration whenever you add a required field to the schema that existing documents will not have. This ensures all existing records are backfilled with appropriate default values.
All migrations check whether the target field already exists before modifying a record. This means migrations can safely be re-run without causing duplicate updates or data corruption.
The run function from @convex-dev/migrations handles execution order automatically. Migrations that have already been applied are skipped on subsequent runs.
Always test migrations in a development environment before running them in production. Use the Convex dashboard to monitor migration progress and verify results.