Stop Hard-Coding Object Keys: Master Variable Keys in JavaScript

Learn 5 ways to use variable keys in JavaScript objects. Save hours debugging dynamic property names with working examples.

I spent 2 hours debugging a form handler because I didn't know how to use variable keys properly in JavaScript objects.

The form field names came from an API, but I kept hard-coding object properties. Every time the API changed, my code broke.

What you'll learn: 5 different ways to use variables as object keys Time needed: 20 minutes Difficulty: Beginner-friendly with real examples

Here's the exact techniques that saved me from rewriting object code every time requirements changed.

Why I Needed This

My situation:

  • Building dynamic forms where field names come from API responses
  • User preferences stored with keys I don't know at compile time
  • Shopping cart items with SKUs as property names

My setup:

  • JavaScript ES6+ (works in all modern browsers)
  • Real-world examples from e-commerce projects
  • Tested in production for 2+ years

What didn't work:

  • Hard-coding every possible key name (unmaintainable)
  • String concatenation hacks (error-prone and ugly)
  • Trying to modify object literals after creation (confusing)

Method 1: Bracket Notation (The Foundation)

The problem: You have a variable containing a key name, but dot notation won't work.

My solution: Use square brackets to access/create properties dynamically.

Time this saves: Eliminates need for switch statements or if/else chains.

Basic Bracket Notation

The simplest way to use a variable as an object key:

// Instead of this broken approach
const fieldName = 'email';
const user = {};
user.fieldName = 'john@example.com'; // Creates 'fieldName', not 'email'!

// Use brackets for variable keys
const fieldName = 'email';
const user = {};
user[fieldName] = 'john@example.com'; // Creates 'email' property ✅

console.log(user);
// Output: { email: 'john@example.com' }

What this does: The brackets tell JavaScript to evaluate the variable first, then use its value as the property name.

Expected output: An object with 'email' as the actual property name.

Personal tip: I use this pattern for every dynamic form handler. The brackets are your friend when the property name isn't known until runtime.

Real-World Example: Form Field Mapping

// API returns field configuration
const fieldConfig = {
  firstName: { type: 'text', required: true },
  email: { type: 'email', required: true },
  phoneNumber: { type: 'tel', required: false }
};

// User submits form data
const formData = new FormData(document.getElementById('myForm'));
const userData = {};

// Map form fields to user object dynamically
for (const [fieldName, config] of Object.entries(fieldConfig)) {
  if (formData.has(fieldName)) {
    userData[fieldName] = formData.get(fieldName);
  }
}

console.log(userData);
// Output: { firstName: 'John', email: 'john@example.com', phoneNumber: '555-0123' }

Personal tip: This approach scales perfectly. Add new fields to your API config, and the form handler automatically supports them without code changes.

Method 2: Computed Property Names (ES6 Magic)

The problem: You want to create objects with variable keys in object literals.

My solution: Use computed property names with square brackets inside object literals.

Time this saves: No need to create empty objects and add properties later.

Object Literal with Variable Keys

// The old way (still works, but verbose)
const keyName = 'productId';
const value = 'ABC123';
const oldWay = {};
oldWay[keyName] = value;

// ES6 computed property names (cleaner)
const keyName = 'productId';
const value = 'ABC123';
const newWay = {
  [keyName]: value,
  quantity: 2,
  price: 29.99
};

console.log(newWay);
// Output: { productId: 'ABC123', quantity: 2, price: 29.99 }

What this does: The brackets inside the object literal evaluate the variable and use its value as the property name.

Expected output: A complete object created in one statement.

Dynamic Shopping Cart Example

// Building a shopping cart with dynamic SKU keys
const addToCart = (sku, quantity, price) => {
  return {
    [sku]: {
      quantity: quantity,
      price: price,
      total: quantity * price
    },
    cartUpdated: new Date().toISOString()
  };
};

// Usage with real product data
const cartItem = addToCart('LAPTOP-001', 1, 999.99);
console.log(cartItem);
// Output: {
//   'LAPTOP-001': { quantity: 1, price: 999.99, total: 999.99 },
//   cartUpdated: '2025-09-04T10:30:00.000Z'
// }

Personal tip: I use this pattern for building API response objects where the key names come from database values or user input.

Method 3: Template Literals for Complex Keys

The problem: Your variable key needs formatting or combines multiple values.

My solution: Use template literals inside computed property names.

Time this saves: No string concatenation bugs or formatting errors.

Building Complex Object Keys

// Creating cache keys with multiple components
const buildCacheKey = (userId, action, timestamp) => {
  const cacheData = {
    [`user_${userId}_${action}_${timestamp}`]: {
      data: 'expensive_computation_result',
      expires: Date.now() + 3600000 // 1 hour
    }
  };
  
  return cacheData;
};

// Usage
const cache = buildCacheKey(123, 'profile_fetch', Date.now());
console.log(Object.keys(cache)[0]);
// Output: "user_123_profile_fetch_1725448200000"

What this does: Template literals let you build formatted keys from multiple variables in a readable way.

Expected output: Objects with descriptive, formatted property names.

API Response Grouping

// Group API data by formatted keys
const groupOrdersByMonth = (orders) => {
  return orders.reduce((grouped, order) => {
    const orderDate = new Date(order.createdAt);
    const monthKey = `${orderDate.getFullYear()}-${String(orderDate.getMonth() + 1).padStart(2, '0')}`;
    
    return {
      ...grouped,
      [monthKey]: [
        ...(grouped[monthKey] || []),
        order
      ]
    };
  }, {});
};

// Sample data
const orders = [
  { id: 1, total: 99.99, createdAt: '2025-08-15T10:00:00Z' },
  { id: 2, total: 149.99, createdAt: '2025-08-20T14:30:00Z' },
  { id: 3, total: 79.99, createdAt: '2025-09-02T09:15:00Z' }
];

const groupedOrders = groupOrdersByMonth(orders);
console.log(groupedOrders);
// Output: {
//   '2025-08': [{ id: 1, ...}, { id: 2, ...}],
//   '2025-09': [{ id: 3, ...}]
// }

Personal tip: Template literals in computed properties are perfect for building cache keys, database indexes, or any formatted identifiers.

Method 4: Object.assign() for Multiple Variable Keys

The problem: You have multiple variables that need to become object keys.

My solution: Use Object.assign() to merge objects with computed properties.

Time this saves: No repetitive bracket notation assignments.

Merging Objects with Dynamic Keys

// Building user preferences from multiple sources
const buildUserPreferences = (theme, language, timezone, currency) => {
  const preferences = Object.assign(
    {},
    { [theme + 'Theme']: true },
    { [language + 'Language']: true },
    { [timezone + 'Timezone']: true },
    { [currency + 'Currency']: true },
    {
      lastUpdated: new Date().toISOString(),
      version: '1.0'
    }
  );
  
  return preferences;
};

// Usage
const userPrefs = buildUserPreferences('dark', 'english', 'EST', 'USD');
console.log(userPrefs);
// Output: {
//   darkTheme: true,
//   englishLanguage: true,
//   ESTTimezone: true,
//   USDCurrency: true,
//   lastUpdated: '2025-09-04T10:30:00.000Z',
//   version: '1.0'
// }

What this does: Object.assign() merges multiple objects, each with computed property names, into one final object.

Expected output: A single object with all your dynamic properties combined.

Configuration Builder

// Build configuration objects from environment variables
const buildConfig = () => {
  const env = process.env.NODE_ENV || 'development';
  const port = process.env.PORT || 3000;
  const dbName = process.env.DB_NAME || 'myapp_dev';
  
  return Object.assign(
    {},
    { [`${env}Mode`]: true },
    { [`port${port}`]: 'active' },
    { [`database${dbName}`]: 'connected' },
    {
      // Static properties
      startTime: new Date().toISOString(),
      version: '2.1.0'
    }
  );
};

// Usage
const config = buildConfig();
console.log(config);
// Output: {
//   developmentMode: true,
//   port3000: 'active',
//   databaseMyapp_dev: 'connected',
//   startTime: '2025-09-04T10:30:00.000Z',
//   version: '2.1.0'
// }

Personal tip: Object.assign() is my go-to when building configuration objects or combining user settings from multiple sources.

Method 5: Map Objects for Complex Key Operations

The problem: You need to perform operations on objects where the keys are variables.

My solution: Use Map objects for advanced key manipulation with full variable support.

Time this saves: No conversion between strings and other data types for keys.

Advanced Key Operations with Map

// Using non-string keys (objects, numbers, etc.)
const createAdvancedCache = () => {
  const cache = new Map();
  
  // Objects as keys
  const userQuery = { userId: 123, includeProfile: true };
  const productQuery = { category: 'electronics', minPrice: 100 };
  
  // Store data with object keys
  cache.set(userQuery, {
    data: { name: 'John Doe', email: 'john@example.com' },
    timestamp: Date.now()
  });
  
  cache.set(productQuery, {
    data: [{ id: 1, name: 'Laptop' }, { id: 2, name: 'Phone' }],
    timestamp: Date.now()
  });
  
  return cache;
};

// Usage
const cache = createAdvancedCache();

// Retrieve using object keys
const userQuery = { userId: 123, includeProfile: true };
const userData = cache.get(userQuery);
console.log(userData);
// Output: undefined (different object reference!)

// Better approach: Use JSON strings as keys
const betterCache = new Map();
const queryKey = JSON.stringify({ userId: 123, includeProfile: true });
betterCache.set(queryKey, { name: 'John Doe', email: 'john@example.com' });

const retrieved = betterCache.get(JSON.stringify({ userId: 123, includeProfile: true }));
console.log(retrieved);
// Output: { name: 'John Doe', email: 'john@example.com' }

What this does: Map objects allow any data type as keys, not just strings like regular objects.

Expected output: More flexible key-value storage for complex scenarios.

Dynamic Property Management

// Managing object properties dynamically
class DynamicObject {
  constructor() {
    this.properties = new Map();
  }
  
  // Set property with variable key
  setProp(key, value) {
    this.properties.set(key, value);
    return this;
  }
  
  // Get property with variable key
  getProp(key) {
    return this.properties.get(key);
  }
  
  // Check if variable key exists
  hasProp(key) {
    return this.properties.has(key);
  }
  
  // Convert to regular object
  toObject() {
    const obj = {};
    for (const [key, value] of this.properties) {
      obj[key] = value;
    }
    return obj;
  }
}

// Usage
const dynamicObj = new DynamicObject();

// Keys from variables
const fieldName = 'email';
const settingName = 'darkMode';
const apiKey = 'user_preferences_v2';

dynamicObj
  .setProp(fieldName, 'john@example.com')
  .setProp(settingName, true)
  .setProp(apiKey, { theme: 'dark', notifications: true });

console.log(dynamicObj.toObject());
// Output: {
//   email: 'john@example.com',
//   darkMode: true,
//   user_preferences_v2: { theme: 'dark', notifications: true }
// }

Personal tip: I use Maps when I need to store metadata about object keys or when the keys might be complex data types.

Common Mistakes I Made (So You Don't Have To)

Mistake 1: Forgetting Quotes in Bracket Notation

// Wrong - this looks for a variable named myKey
const obj = {};
obj[myKey] = 'value'; // ReferenceError: myKey is not defined

// Right - use quotes for literal strings
const obj = {};
obj['myKey'] = 'value'; // ✅

// Right - use variables without quotes
const keyName = 'myKey';
obj[keyName] = 'value'; // ✅

Mistake 2: Mixing Dot and Bracket Notation

// Wrong - creates 'keyName' property instead of using the variable
const keyName = 'email';
const user = {};
user.keyName = 'john@example.com'; // Creates { keyName: 'john@example.com' }

// Right - use brackets for variable keys
const keyName = 'email';
const user = {};
user[keyName] = 'john@example.com'; // Creates { email: 'john@example.com' } ✅

Mistake 3: Forgetting to Handle Undefined Variables

// Dangerous - undefined variable creates 'undefined' property
let dynamicKey; // undefined
const obj = {
  [dynamicKey]: 'some value'
};
console.log(obj); // { undefined: 'some value' }

// Better - provide defaults
const dynamicKey = userInput || 'defaultKey';
const obj = {
  [dynamicKey]: 'some value'
};

Personal tip: Always validate your variable keys before using them. I've debugged objects with 'undefined' and 'null' properties more times than I care to admit.

What You Just Built

You now know 5 different ways to use variables as object keys in JavaScript:

  • Bracket notation for basic dynamic property access
  • Computed property names for cleaner object literals
  • Template literals for formatted, complex keys
  • Object.assign() for merging multiple dynamic properties
  • Map objects for advanced key operations

Key Takeaways (Save These)

  • Always use brackets: Variable keys require square bracket notation, never dot notation
  • Validate your keys: Check for undefined variables before using them as property names
  • ES6 computed properties: Use { [variableKey]: value } for cleaner object creation
  • Template literals work: Perfect for building formatted keys like cache_${userId}_${action}
  • Maps for complex keys: When you need non-string keys or advanced key operations

Your Next Steps

Pick one based on your experience:

  • Beginner: Practice bracket notation with a simple form handler
  • Intermediate: Build a dynamic settings object using computed property names
  • Advanced: Create a caching system using Maps with complex keys

Tools I Actually Use

  • VS Code: With JavaScript intellisense for catching key-related errors early
  • Chrome DevTools: Console for testing dynamic object creation patterns
  • ESLint: Catches common mistakes like undefined variables in bracket notation
  • MDN Documentation: Object property accessors reference