User Settings Management#
User settings updates in Zerobyte flow through Better Auth's updateUser endpoint, which is automatically generated for any fields declared under user.additionalFields in the server auth config. The Settings UI calls this endpoint directly — no custom API route is needed for profile field changes.
Server: Additional Fields via Better Auth#
In app/server/lib/auth.ts, four custom fields are registered on the user model:
| Field | Type | Notes |
|---|---|---|
username | string | Required, returned in session |
hasDownloadedResticPassword | boolean | Tracks recovery key download |
dateFormat | string | User date display preference |
timeFormat | string | User time display preference |
Declaring a field here causes Better Auth to automatically expose it through the POST /api/auth/update-user endpoint — no additional server-side handler is required . The username and hasDownloadedResticPassword fields are marked returned: true, meaning they are included in session responses .
The user.modelName is set to "usersTable" , mapping to the schema definition which also stores dateFormat (default: "MM/DD/YYYY") and timeFormat (default: "12h") .
Client: authClient and inferAdditionalFields#
The client-side authClient is created with inferAdditionalFields<typeof auth>() , which pulls the additional field types from the server auth instance so that authClient.updateUser(...) is fully typed against those fields. Other plugins (usernameClient, adminClient, organizationClient, etc.) add their own methods to the same client object .
Settings UI: Auto-Save on Select Change#
The Settings page (app/client/modules/settings/routes/settings.tsx) uses an auto-save pattern — there is no explicit "Save" button for date/time preferences. Instead, each <Select> fires onValueChange, which immediately calls authClient.updateUser(...):
handleDateFormatChange— called on date format select change; skips the API call if the value is unchanged.handleTimeFormatChange— same pattern for time format.- Both delegate to
handleDateTimeFormatChange, which callsauthClient.updateUser({ dateFormat, timeFormat, ... })and triggerswindow.location.reload()on success to apply the new preferences .
The settings page also displays a live preview of the currently selected format before saving, using the formatDateTime utility from useTimeFormat .
Read-Only Fields#
username and email are rendered as disabled inputs in the Account Information section — they cannot be changed from the Settings UI. Password changes go through authClient.changePassword(...) , which revokes other sessions on success and then automatically signs the user out.
Settings Page Structure#
The settings page at /(dashboard)/settings/ renders two tabs :
- Account — Account information, date/time format, password change, backup recovery key download, API keys, 2FA, passkeys.
- Organization — Shown only to users with the
organizationSettings.viewpermission; contains org details, member management, and SSO configuration.
Tab state is persisted in the URL via the ?tab= search param .
Key Files#
| File | Purpose |
|---|---|
app/server/lib/auth.ts | Better Auth config — defines additional user fields |
app/client/lib/auth-client.ts | Client auth instance with inferAdditionalFields |
app/client/modules/settings/routes/settings.tsx | Settings UI — auto-save and all account actions |
app/server/db/schema.ts | DB schema with default values for dateFormat / timeFormat |