Level: π΄ Advanced | Time: β±οΈ 15 min | Prerequisites: Configuration
This guide explains how to configure additional user fields that are captured during signup.
- β Add custom fields to user signup
- β Configure metadata storage
- β Use centralized user field configuration
FlowStack uses a centralized configuration for user metadata fields. Instead of adding columns to the database for each custom field, all additional data is stored in a flexible metadata JSON column.
Configuration Location: packages/config/src/config/user-metadata.ts
- Open
packages/config/src/config/user-metadata.ts - Add your field to the
USER_METADATA_FIELDSarray:
export const USER_METADATA_FIELDS: UserMetadataField[] = [
// Existing field
{
key: "organizationName",
label: "Organization Name",
placeholder: "Enter your organization name",
description: "This will be your workspace name",
required: true,
type: "string",
createsOrganization: true,
},
// Add your new field
{
key: "companySize",
label: "Company Size",
placeholder: "e.g., 1-10, 11-50, 50+",
required: false,
type: "string",
},
];- The field will automatically appear in:
- Backend auth config (
additionalFields) - Frontend signup forms (web and tanstack apps)
- Backend auth config (
| Property | Type | Required | Description |
|---|---|---|---|
key |
string |
Yes | Unique identifier stored in metadata JSON |
label |
string |
Yes | Display label for the form |
placeholder |
string |
No | Placeholder text for the input |
description |
string |
No | Helper text shown below the input |
required |
boolean |
No | Whether the field is required (default: false) |
type |
"string" | "number" | "boolean" |
No | Field data type (default: "string") |
createsOrganization |
boolean |
No | If true, triggers organization creation on signup |
returned |
boolean |
No | Whether to return in API responses (default: false) |
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β @repo/config/src/config/user-metadata.ts β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β USER_METADATA_FIELDS = [{ key, label, ... }] β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
ββββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββββ
β
βββββββββββββββββΌββββββββββββββββ
βΌ βΌ βΌ
βββββββββββββββββ βββββββββββββββββ βββββββββββββββββ
β @repo/auth β β apps/web β β apps/tanstack β
β additionalFieldsβ β signup form β β signup form β
βββββββββββββββββ βββββββββββββββββ βββββββββββββββββ
Returns field configuration for Better Auth's user.additionalFields:
import { getAuthUserFields } from "@repo/config";
const auth = betterAuth({
user: {
additionalFields: getAuthUserFields(),
},
});Returns field configuration for AuthUIProvider:
import { getUIUserFields } from "@repo/config";
const additionalFields = getUIUserFields();Returns keys of fields that trigger organization creation:
import { getOrganizationCreationFields } from "@repo/config";
const orgFields = getOrganizationCreationFields();
// Returns: ["organizationName"]