Skip to main content

Builder Overview

The DDEX Builder generates deterministic, industry-compliant DDEX XML files from structured data. Built with Rust for maximum performance and featuring byte-perfect reproducibility, it's the perfect companion to the DDEX Parser for complete metadata workflows.

What is DDEX Builder?

DDEX Builder transforms structured data (JSON, objects, DataFrames) into valid DDEX XML messages that are guaranteed to be byte-identical on every generation. Whether you're building music distribution systems, content management platforms, or analytics pipelines, the builder ensures your DDEX deliveries meet industry standards while maintaining perfect consistency.

Key Features

🎯 Deterministic Output

  • 100% reproducible XML generation with stable, content-based IDs
  • DB-C14N/1.0 canonicalization ensures byte-perfect consistency across platforms
  • Content-addressable resource references for reliable cross-references
  • Stable ordering of all XML elements and attributes

🏭 Industry Presets

Pre-configured settings for major music platforms:

  • Spotify: Streaming platform requirements with explicit content flags
  • YouTube Music: Content ID and monetization compliance
  • Apple Music: iTunes Store requirements and Mastered for iTunes specs
  • Amazon Music: Prime and Unlimited platform requirements
  • Universal: Generic preset for broad distributor compatibility

🚀 High Performance

  • Native Rust core with optimized language bindings
  • Sub-millisecond builds for typical releases (<15ms average)
  • Streaming generation for massive catalogs (>100,000 tracks)
  • Memory-efficient processing with configurable limits

🔒 Comprehensive Validation

  • Real-time DDEX schema validation with detailed error messages
  • Business rule enforcement for industry compliance
  • Reference integrity checking across entire message structure
  • Territory and rights validation with intelligent suggestions

🌐 Universal Language Support

  • JavaScript/TypeScript: Native Node.js performance with full type safety
  • Python: PyO3 bindings with pandas DataFrame integration
  • WebAssembly: Browser-ready bundle optimized at <400KB
  • Rust: Direct access to the core building engine

Core Concepts

Deterministic Generation

Traditional XML generation produces different output for the same data due to:

  • Non-deterministic hash functions
  • Unstable element ordering
  • Platform-specific timestamp formats
  • Memory address-based IDs

DDEX Builder solves this with:

// These calls produce IDENTICAL XML every time
const xml1 = await builder.build(releaseData);
const xml2 = await builder.build(releaseData);
console.assert(xml1 === xml2); // ✅ Always true

// Even across different machines/platforms
const xmlLinux = buildOnLinux(data);
const xmlMacOS = buildOnMacOS(data);
const xmlWindows = buildOnWindows(data);
// All three XML strings are byte-identical

DB-C14N/1.0 Canonicalization

The builder implements the Database Canonicalization 1.0 specification:

  • Lexicographic ordering of attributes
  • Normalized whitespace handling
  • Consistent namespace declarations
  • Standardized character encoding
  • Deterministic element ordering

This ensures that semantically identical XML produces identical bytes:

<!-- Input A -->
<Release territoryCode="US" upc="123456789">
<Title>Album</Title>
</Release>

<!-- Input B -->
<Release upc="123456789" territoryCode="US">
<Title>Album</Title>
</Release>

<!-- Both produce IDENTICAL canonicalized output -->

Content-Based IDs

Rather than random UUIDs, the builder generates deterministic IDs based on content:

const releaseData = {
title: "My Album",
artist: "Artist Name",
upc: "123456789012"
};

// ID is generated from content hash: REL_a1b2c3d4e5f6...
// Same data = same ID, every time
const xml = await builder.build(releaseData);

Architecture

Core Components

  1. Rust Builder Core: High-performance XML generation with canonicalization
  2. Validation Engine: Schema and business rule validation
  3. Preset System: Platform-specific configuration templates
  4. Language Bindings: Native interfaces for JavaScript, Python, and WASM
  5. Streaming Engine: Memory-efficient processing for large datasets

Data Flow

Structured Data → Validation → Content IDs → XML Generation → Canonicalization
↓ ↓ ↓ ↓ ↓
JSON/Object Schema Check Content Hash Raw XML DB-C14N/1.0
DataFrame Business Rules Deterministic Elements Byte-perfect

Use Cases

Music Distribution Platforms

Generate DDEX deliveries for record labels and distributors:

import { DdexBuilder } from 'ddex-builder';

const builder = new DdexBuilder();
builder.applyPreset('spotify'); // Platform-specific requirements

const delivery = await builder.build({
messageHeader: {
messageId: 'DELIVERY_2024_001',
messageSenderName: 'My Record Label'
},
releases: [{
title: 'New Album',
artist: 'Amazing Artist',
upc: '123456789012',
territories: ['WorldWide'],
releaseDate: '2024-01-15'
}],
resources: [{
title: 'Hit Single',
isrc: 'US1234567890',
duration: 'PT3M45S'
}]
});

console.log('Generated delivery:', delivery.length, 'bytes');

Content Management Systems

Build administrative interfaces for managing music metadata:

from ddex_builder import DdexBuilder
import pandas as pd

# Load catalog from database
catalog_df = pd.read_sql('SELECT * FROM releases', connection)

# Build DDEX messages from DataFrame
builder = DdexBuilder(preset='generic_audio_album', validate=True)
xml = builder.from_dataframe(catalog_df, version='4.3')

# Save for distribution
with open('catalog_delivery.xml', 'w') as f:
f.write(xml)

Analytics and Reporting

Generate DDEX reports from analytics data:

// Transform analytics data to DDEX format
const analyticsData = await fetchAnalyticsData();

const reportBuilder = new DdexBuilder({
preset: 'analytics_report',
canonical: true
});

const ddexReport = await reportBuilder.build({
reportingPeriod: {
startDate: '2024-01-01',
endDate: '2024-01-31'
},
performances: analyticsData.map(item => ({
isrc: item.track_isrc,
territory: item.country,
playCount: item.streams,
revenue: item.net_revenue
}))
});

Round-Trip Workflows

Perfect integration with DDEX Parser for complete workflows:

import { DDEXParser } from 'ddex-parser';
import { DdexBuilder } from 'ddex-builder';

// Parse existing DDEX file
const parser = new DDEXParser();
const parsed = await parser.parseFile('original.xml');

// Modify specific data
const modified = { ...parsed.flat };
modified.releases[0].title = 'Remastered Edition';
modified.releases[0].releaseDate = '2024-02-01';

// Build new deterministic XML
const builder = new DdexBuilder({ canonical: true });
const newXml = await builder.build(parsed.toBuildRequest());

// Verify round-trip integrity
const reparsed = await parser.parseString(newXml);
console.assert(reparsed.flat.releases[0].title === 'Remastered Edition');

Performance Characteristics

Build Speed Benchmarks

Dataset SizeNode.jsPythonRust CoreBrowser (WASM)
Single release (10 tracks)3ms5ms0.8ms8ms
Album catalog (100 releases)25ms40ms12ms85ms
Label catalog (1,000 releases)180ms280ms95ms650ms
Large catalog (10,000 releases)1.8s2.8s950ms6.5s

Memory Efficiency

Traditional XML builders vs DDEX Builder:

Dataset SizeTraditionalDDEX BuilderImprovement
1,000 releases450MB120MB73% reduction
10,000 releases4.2GB300MB93% reduction
100,000 releases>16GB500MB*>97% reduction

*With streaming mode enabled

Determinism Performance

The canonicalization process adds minimal overhead:

OperationWithout CanonicalizationWith DB-C14N/1.0Overhead
Small release (10 tracks)2.1ms2.3ms+9%
Medium catalog (100 releases)18ms21ms+17%
Large catalog (1000 releases)140ms165ms+18%

Supported DDEX Versions

The builder supports all major DDEX ERN versions with full compliance:

VersionStatusCoverageNotes
ERN 4.3✅ Full100%Latest specification, recommended
ERN 4.2✅ Full100%Stable version, widely adopted
ERN 3.8.2✅ Full100%Legacy support for older systems

Version-Specific Features

// ERN 4.3 - Latest features
const ern43Builder = new DdexBuilder({ version: '4.3' });
// Supports: Enhanced territories, streaming-specific metadata

// ERN 4.2 - Stable production
const ern42Builder = new DdexBuilder({ version: '4.2' });
// Supports: Standard territories, established metadata fields

// ERN 3.8.2 - Legacy compatibility
const ern382Builder = new DdexBuilder({ version: '3.8.2' });
// Supports: Core functionality, basic territory handling

Industry Compliance

Platform Requirements

The preset system ensures compliance with major platforms:

Spotify Requirements

  • Explicit content flagging (required)
  • Territory restrictions for streaming
  • Artist ID validation
  • Genre normalization to Spotify taxonomy

YouTube Music Requirements

  • Content ID metadata
  • Monetization policy compliance
  • Territory-specific rights handling
  • Revenue reporting integration

Apple Music Requirements

  • iTunes Store compliance rules
  • Mastered for iTunes specifications
  • Region-specific pricing tiers
  • Album artwork requirements

Business Rules Engine

The builder enforces industry best practices:

const builder = new DdexBuilder({
businessRules: {
enforceISRC: true, // Require ISRC for all tracks
validateTerritoryRights: true, // Check territory/rights consistency
requireUPCForAlbums: true, // UPC mandatory for album releases
genreNormalization: true, // Standardize genre classifications
explicitContentFlag: true // Require parental advisory flags
}
});

Integration Patterns

Microservices Architecture

Deploy as a dedicated building service:

// Express.js microservice
app.post('/build', async (req, res) => {
try {
const builder = new DdexBuilder({
preset: 'generic_audio_album',
validate: true
});

const xml = await builder.build(req.body.data);

res.json({
success: true,
xml: xml,
metadata: {
sizeBytes: xml.length,
version: req.body.data.version || '4.3',
generatedAt: new Date().toISOString()
}
});
} catch (error) {
res.status(400).json({
success: false,
error: error.message,
type: error.constructor.name
});
}
});

Event-Driven Processing

React to catalog changes with automatic DDEX generation:

import asyncio
from ddex_builder import DdexBuilder

async def handle_catalog_update(event):
"""Generate DDEX when catalog changes."""
builder = DdexBuilder(
preset=event.platform,
validate=True,
canonical=True
)

try:
# Build DDEX from updated catalog
xml = await builder.build_async(event.catalog_data)

# Emit built DDEX event
await emit_event('ddex.generated', {
'xml': xml,
'platform': event.platform,
'catalog_id': event.catalog_id,
'size_bytes': len(xml)
})

except Exception as e:
await emit_event('ddex.build_failed', {
'error': str(e),
'catalog_id': event.catalog_id
})

Batch Processing Pipelines

Process large catalogs efficiently:

import { batchBuild } from 'ddex-builder';

async function processCatalogBatch(catalogItems: any[]) {
// Prepare build requests
const buildRequests = catalogItems.map(item => ({
messageId: `MSG_${item.id}`,
releases: item.releases,
resources: item.resources
}));

// Batch build with parallel processing
const results = await batchBuild(buildRequests, {
preset: 'generic_audio_album',
parallel: true,
maxConcurrency: 10
});

// Process results
results.forEach((result, index) => {
if (result.success) {
console.log(`✅ Built catalog ${catalogItems[index].id}: ${result.xml.length} bytes`);
saveToDisk(result.xml, `catalog_${catalogItems[index].id}.xml`);
} else {
console.error(`❌ Failed catalog ${catalogItems[index].id}:`, result.error);
}
});
}

Getting Started

Ready to start building DDEX files? Choose your path:

For complete workflows, combine with the DDEX Parser for parsing existing files and round-trip operations.