Yashveer Singh
Connect
<- All posts
Web App and Frontend Development7 min read

Settings and Preferences: A Common Pattern Done Badly

Settings pages reveal how well an app is architected. Most of them reveal the opposite.

Written by Yashveer Singh, founder of Yashveer Labs.

# Settings and Preferences: A Common Pattern Done Badly

Settings and preferences are where application architecture gets exposed. A well-built settings system saves state reliably, reflects changes immediately, handles conflicts gracefully, and gives users clear feedback at every step. Most settings implementations do none of these things reliably. They lose state on refresh, apply changes that silently fail, and create UI patterns that contradict each other across different sections of the same app.

What you need to know

  • The difference between user preferences (per-user, stored in your database) and app configuration (global or environment-level, stored in config) should be explicit from the start
  • Optimistic UI updates in settings feel fast but require careful rollback handling when the save fails
  • Settings pages are where most apps hide their worst form patterns: no validation feedback, ambiguous save states, inconsistent save-on-change vs save-on-submit behavior
  • Notification preferences in particular need their own architecture: a flag in a JSON column or a dedicated notification preferences table, not a pile of boolean columns
  • The "undo" problem in settings is underrated; users expect to be able to back out of changes they made accidentally

The core argument

Settings pages are almost never planned properly. They grow one field at a time as product requirements arrive. First it is a display name. Then it is a notification toggle. Then it is a timezone selector. Then it is API key management. Then it is two-factor auth. By the time the settings page has a dozen sections, it is carrying the accumulated debt of every feature that did not have a home anywhere else.

The architecture problem shows up as inconsistency. Some fields save on blur. Some require a Submit button. Some changes take effect immediately. Some require a page reload. The user has no mental model because there is no underlying model to have. This is what I fixed when I rebuilt the user settings section for Velmora. The existing implementation had three different save patterns across different settings sections, a notification preferences system stored as a flat JSON blob, and no error states whatsoever. The rebuild drew a clean line: preferences that affect display persist optimistically with a rollback toast on failure. Preferences that affect security require a confirmation step and explicit save. System configuration changes trigger a clear visual state change to signal they are in effect.

The deeper issue is that settings pages are tests of your data model. If your user table has 15 boolean columns for notification preferences, your data model is the problem and the settings UI is just exposing it. A separate notification preferences table with rows keyed by notification type gives you flexibility to add new notification categories without a migration every time, and makes the UI component data-driven rather than hardcoded.

Common mistakes

  1. Mixing save behaviors in the same settings page without communicating the difference. If some settings auto-save and others require a button click, the page needs clear visual cues for each. Users will assume one pattern and break the other one constantly.
  1. No loading state on save. A settings form that goes silent after the user clicks Save is worse than one that shows an error. Users will click again, submit twice, or assume nothing happened.
  1. Storing notification preferences as boolean columns. This approach requires a schema migration every time a new notification type ships. A preferences JSON column or a dedicated table is far more maintainable.
  1. No validation on the frontend for fields that have server-side constraints. If a display name has a character limit on the backend, validate it on the frontend too. Do not make the user complete a round trip to find out the field is wrong.
  1. Building settings as a single route with a single form. Settings pages with many sections should be structured as a layout with sub-routes. It makes bookmarking, deep linking, and URL-based navigation work naturally, and it keeps each section's state isolated.

Where to start

  1. Audit your current settings data model. List every field users can change. Where is each one stored? How does it get applied? Are there fields that affect security that do not require confirmation? Identify the inconsistencies before you write a line of UI.
  1. Standardize your save pattern. Pick one: auto-save with visual feedback, or explicit save button with clear loading and error states. Then apply it consistently across the entire settings surface. One exception is security-sensitive fields, which should always require explicit confirmation.
  1. Build the notification preferences as a data-driven component. Your backend serves a list of notification categories and the user's current state for each. The frontend renders that list. When a new category is added, it appears in settings automatically.

Related reading

FAQ

Frequently asked

Author

My approach to this kind of work

I approach this kind of work the way I would want someone to approach a system I depended on. With care, with rigor, with a sense that the next person who touches it should be able to understand it without my help. Yashveer Singh, founder of Yashveer Labs. That is the standard. If it is the standard you are looking for, I am the engineer to hire.

Related reading