Home → Advanced JSON Merge

Advanced JSON Merge

Merge JSON objects with control over array handling and conflict resolution.

About This Tool

Merge JSON objects with control over array handling and conflict resolution. This tool runs entirely in your browser — no data is ever sent to a server. Free to use, no account required.

Advanced Merge Strategies

Beyond simple key overwrites, advanced merge provides fine-grained control over how conflicts and arrays are handled at every level of the JSON structure.

Array Merge Strategies

Choose how arrays under the same key are combined: replace (right wins entirely), concatenate (both arrays joined end-to-end), or union (joined with duplicates removed). Each strategy serves different use cases.

Conflict Resolution

When both objects have the same scalar key, choose which side wins, or keep both values as an array. This is useful when aggregating data from multiple sources where neither value should be discarded.

When to Use Advanced JSON Merge

Simple merge works for straightforward cases, but advanced merge is necessary when the data being combined requires more sophisticated rules.

Merging Configuration Layers

Environment-specific configuration files often need to override some keys while merging arrays (like plugin lists or middleware chains). Advanced merge handles both in a single pass.

Aggregating Data from Multiple Sources

When combining records from different API endpoints or database queries, advanced merge prevents duplicate entries in arrays while still merging the object fields correctly.

Frequently Asked Questions

What makes advanced merge different from regular JSON merge?+
Regular JSON merge always lets the right-hand object overwrite the left on conflicts. Advanced merge lets you choose: concatenate arrays instead of replacing them, deduplicate merged arrays, keep both conflicting scalar values as an array, or apply custom merge strategies. This control is essential when both sides contain valuable data.
How does advanced merge handle arrays?+
You can choose from three array strategies: replace (the right array completely replaces the left), concatenate (both arrays are joined into one), or union (arrays are joined and duplicates removed). The union strategy is ideal for merging tag lists, permission sets, or any array of unique identifiers.
Can I merge more than two JSON objects?+
Yes. Advanced merge can process multiple JSON objects sequentially, applying the chosen merge strategy at each step. The result is equivalent to merging all objects from left to right using the configured strategy.
Does advanced merge work with deeply nested JSON?+
Yes. Advanced merge operates recursively on all nested objects and arrays. Each nested object is merged according to the same strategy as the top level, ensuring consistent behavior throughout the entire document structure.

Merge Strategy Examples — Side by Side

The following examples use the same two input objects and show what each merge strategy produces. Understanding these outputs is the key to choosing the right strategy for your use case.

Input objects

// Object A (base / left)
{
  "name": "Alice",
  "role": "user",
  "tags": ["javascript", "react"],
  "settings": { "theme": "dark", "lang": "en" }
}

// Object B (override / right)
{
  "role": "admin",
  "tags": ["typescript", "react"],
  "settings": { "lang": "fr", "notifications": true }
}

Strategy 1: Shallow merge (right wins)

{
  "name": "Alice",
  "role": "admin",
  "tags": ["typescript", "react"],
  "settings": { "lang": "fr", "notifications": true }
  // ↑ settings from A is completely replaced — "theme" and "lang: en" are lost
}

Strategy 2: Deep merge + array replace (right array wins)

{
  "name": "Alice",
  "role": "admin",
  "tags": ["typescript", "react"],
  "settings": { "theme": "dark", "lang": "fr", "notifications": true }
  // ↑ settings is now a deep merge — "theme" is preserved from A, "lang" overridden by B
}

Strategy 3: Deep merge + array concatenate

{
  "name": "Alice",
  "role": "admin",
  "tags": ["javascript", "react", "typescript", "react"],
  // ↑ both tag arrays joined — contains "react" twice
  "settings": { "theme": "dark", "lang": "fr", "notifications": true }
}

Strategy 4: Deep merge + array union (deduplicated)

{
  "name": "Alice",
  "role": "admin",
  "tags": ["javascript", "react", "typescript"],
  // ↑ both arrays joined with duplicates removed — "react" appears only once
  "settings": { "theme": "dark", "lang": "fr", "notifications": true }
}

Merge Strategy Comparison Table

Strategy Nested objects Arrays Best for
Shallow mergeRight replaces left entirelyRight replaces leftSimple key overrides, no nested data
Deep merge + replaceRecursively mergedRight replaces leftConfig overrides where arrays are overridden
Deep merge + concatRecursively mergedBoth joinedAggregating lists from multiple sources
Deep merge + unionRecursively mergedJoined, deduplicatedTags, roles, permissions, feature flags

Deep Merge in JavaScript — Implementation

If you need deep merge in your own code without a library, here is a minimal implementation that handles the most common cases:

function deepMerge(target, source, arrayStrategy = 'replace') {
  const result = { ...target };

  for (const key of Object.keys(source)) {
    if (
      source[key] !== null &&
      typeof source[key] === 'object' &&
      !Array.isArray(source[key]) &&
      typeof result[key] === 'object' &&
      !Array.isArray(result[key])
    ) {
      // Both values are plain objects — recurse
      result[key] = deepMerge(result[key], source[key], arrayStrategy);
    } else if (Array.isArray(source[key]) && Array.isArray(result[key])) {
      // Both values are arrays — apply strategy
      if (arrayStrategy === 'concat') {
        result[key] = [...result[key], ...source[key]];
      } else if (arrayStrategy === 'union') {
        result[key] = [...new Set([...result[key], ...source[key]])];
      } else {
        result[key] = source[key]; // replace (default)
      }
    } else {
      result[key] = source[key]; // scalar: right wins
    }
  }

  return result;
}

// Usage
const merged = deepMerge(objectA, objectB, 'union');
console.log(JSON.stringify(merged, null, 2));

Advanced Merge Operations: Strategy Reference

Each strategy has different behavior for arrays and objects, making it suitable for different use cases. Choose based on whether you want to accumulate, deduplicate, or strictly replace data.

Strategy Array Behavior Object Behavior Use Case
ReplaceSource replaces targetSource properties overwriteStrict updates, one source of truth
AppendSource appended to targetDeep mergeAccumulating lists with full config merge
Combine (union)Deduplicated mergeDeep mergeTags, categories, feature flags
Keep targetTarget preservedSource fills missing keys onlyRead-only defaults
const base = { tags: ["a", "b"], config: { timeout: 30, retries: 3 } };
const update = { tags: ["b", "c"], config: { timeout: 60 } };

// Replace: tags: ["b","c"], config: {timeout:60}
// Append:  tags: ["a","b","b","c"], config: {timeout:60, retries:3}
// Union:   tags: ["a","b","c"], config: {timeout:60, retries:3}

Practical Advanced Merge Examples

Real-world scenarios where advanced merge strategies solve common configuration and data problems.

Scenario 1 — Merging environment configs

const base = {
  database: { host: 'localhost', port: 5432, name: 'myapp' },
  redis: { host: 'localhost', port: 6379 },
  debug: false
};

const production = {
  database: { host: 'db.prod.example.com', name: 'myapp_prod' },
  debug: false
};

// Deep merge result: production overrides, base fills missing fields
// database: { host: 'db.prod.example.com', port: 5432, name: 'myapp_prod' }

Scenario 2 — Merging user permission sets (union)

const roleA = { permissions: ["read", "write"] };
const roleB = { permissions: ["write", "delete"] };

// Union merge → { permissions: ["read", "write", "delete"] }
// No duplicates — "write" appears only once

Scenario 3 — Filling defaults without overriding user settings (keep target)

const defaults = { theme: "light", fontSize: 14, notifications: true };
const userPrefs = { theme: "dark", fontSize: 16 };

// Keep target merge → { theme: "dark", fontSize: 16, notifications: true }
// User's settings are preserved; only missing keys are filled from defaults

Explore more tools: All JSON Tools | Validator | Pretty Print | JSON Diff