Chrome Extension Extension Configuration — Best Practices

3 min read

Extension Configuration Patterns

Configuration management is critical for building flexible, user-customizable Chrome extensions. This guide covers patterns for implementing robust configuration systems.

Default Configuration

Always provide hardcoded default values merged with user overrides:

const DEFAULT_CONFIG = {
  theme: 'system',
  notifications: true,
  syncEnabled: false,
  maxResults: 50,
} as const;

async function loadConfig(): Promise<Config> {
  const userConfig = await chrome.storage.local.get(null);
  return { ...DEFAULT_CONFIG, ...userConfig };
}

Schema Validation

Validate configuration on load and reject invalid values:

const configSchema = z.object({
  theme: z.enum(['light', 'dark', 'system']).default('system'),
  notifications: z.boolean().default(true),
  maxResults: z.number().min(1).max(100).default(50),
});

function validateConfig(raw: unknown): Config {
  return configSchema.parse(raw);
}

Configuration Versioning

Migrate config across extension updates:

const CONFIG_VERSION = 2;

const migrations: Record<number, (config: Config) => Config> = {
  1: (cfg) => ({ ...cfg, theme: 'system', version: 2 }),
};

async function migrateConfig(config: Config): Promise<Config> {
  let current = config;
  for (let v = (config.version || 1); v < CONFIG_VERSION; v++) {
    current = migrations[v](current);
  }
  return { ...current, version: CONFIG_VERSION };
}

Layered Configuration

Priority: defaults < user settings < enterprise policy:

async function getEffectiveConfig(): Promise<Config> {
  const [defaults, user, policy] = await Promise.all([
    loadDefaults(),
    chrome.storage.local.get(null),
    chrome.storage.managed.get(null),
  ]);
  return { ...defaults, ...policy, ...user };
}

Observing Config Changes

Use chrome.storage.onChanged for reactive updates:

chrome.storage.onChanged.addListener((changes, area) => {
  if (area === 'local') {
    const newConfig = validateConfig(changes);
    applyConfig(newConfig);
  }
});

Typed Config with TypeScript

Use interfaces for type-safe configuration:

interface ExtensionConfig {
  theme: 'light' | 'dark' | 'system';
  notifications: boolean;
  syncEnabled: boolean;
  maxResults: number;
  version: number;
}

Config UI Patterns

Sync vs Local Storage

Feature Toggles

Enable/disable features via boolean flags:

const FEATURES = {
  experimentalFeatures: false,
  newDashboard: true,
} as const;

Cross-References

Part of the Chrome Extension Guide by theluckystrike. Built at zovo.one.