DEV Community

Hardi
Hardi

Posted on

JSON to CSV Converter: Transform API Data to Spreadsheet Format

Converting JSON to CSV is essential for data analysis, reporting, and business intelligence. From exporting API data to Excel-friendly formats to generating reports for non-technical stakeholders, JSON to CSV conversion bridges the gap between developer tools and business analytics. Let's master JSON to CSV transformation for practical data workflows.

Why JSON to CSV Conversion Matters

The Data Analysis Problem

// The business reality of data formats
const dataFormatChallenge = {
  developers: {
    prefer: 'JSON - structured, hierarchical, flexible',
    tools: ['APIs', 'databases', 'code', 'terminals'],
    comfort: 'High with nested objects and arrays'
  },

  business: {
    prefer: 'CSV/Excel - flat, tabular, familiar',
    tools: ['Excel', 'Google Sheets', 'Power BI', 'Tableau'],
    comfort: 'Low with JSON, high with spreadsheets'
  },

  problem: 'Developers produce JSON, business needs CSV',
  solution: 'JSON to CSV conversion bridges the gap',

  scenarios: [
    'Export API data for Excel analysis',
    'Generate monthly reports for management',
    'Import data into business tools (CRM, ERP)',
    'Share data with non-technical stakeholders',
    'Bulk data operations in spreadsheets',
    'Data visualization prep (Tableau, Power BI)',
    'Backup data in human-readable format',
    'Compliance reporting (CSV required)'
  ]
};

console.log('JSON to CSV: Bridge developers and business users');
Enter fullscreen mode Exit fullscreen mode

Real-World Impact

// Before JSON to CSV: Manual data entry nightmare
const beforeConversion = {
  task: 'Export 1,000 customer records for sales team',
  method: 'Manual copy-paste from API responses',
  time: '8 hours of tedious work',
  errors: 'Countless (typos, missing data, wrong format)',
  updateFrequency: 'Weekly',
  monthlyCost: '32 hours × $50/hour = $1,600',
  frustration: 'Extreme'
};

// With JSON to CSV: Automated export
const withConversion = {
  task: 'Export 1,000 customer records',
  method: 'Automated JSON to CSV script',
  time: '30 seconds (including API call)',
  errors: 'Zero (perfect data transfer)',
  updateFrequency: 'On-demand (instant)',
  monthlyCost: '$0 (automated)',
  savings: '$1,600/month = $19,200/year',
  frustration: 'Zero'
};

// Real production example
const realScenario = {
  company: 'E-commerce startup',
  need: 'Daily sales report for investors',
  before: {
    process: 'Developer manually exports data to Excel',
    time: '45 minutes daily',
    cost: '15 hours/month × $100/hour = $1,500/month',
    delays: 'Report available at 11am (blocking meetings)'
  },
  after: {
    process: 'Automated script runs at 6am, emails CSV',
    time: '0 minutes (fully automated)',
    cost: '$0',
    savings: '$1,500/month = $18,000/year',
    improvement: 'Report ready at 6am (no blockers)'
  }
};

console.log('JSON to CSV automation: $18K/year savings, zero manual work');
Enter fullscreen mode Exit fullscreen mode

Understanding JSON to CSV Conversion

The Flattening Challenge

// JSON is hierarchical, CSV is flat
const conversionChallenges = {
  simpleJSON: {
    input: {
      name: 'John',
      age: 30,
      city: 'New York'
    },
    csv: 'name,age,city\nJohn,30,New York',
    difficulty: 'Easy - flat structure'
  },

  nestedObjects: {
    input: {
      name: 'John',
      address: {
        street: '123 Main St',
        city: 'New York',
        zip: '10001'
      }
    },
    csvFlattened: 'name,address.street,address.city,address.zip\nJohn,123 Main St,New York,10001',
    difficulty: 'Medium - need to flatten nested objects'
  },

  arrays: {
    input: {
      name: 'John',
      skills: ['JavaScript', 'Python', 'SQL']
    },
    approaches: {
      joined: 'name,skills\nJohn,"JavaScript, Python, SQL"',
      separate: 'Multiple rows or multiple columns',
      json: 'name,skills\nJohn,"[""JavaScript"",""Python"",""SQL""]"'
    },
    difficulty: 'Hard - arrays require decisions'
  },

  arrayOfObjects: {
    input: [
      { name: 'John', age: 30 },
      { name: 'Jane', age: 25 },
      { name: 'Bob', age: 35 }
    ],
    csv: 'name,age\nJohn,30\nJane,25\nBob,35',
    difficulty: 'Easy - natural table structure'
  },

  inconsistentKeys: {
    input: [
      { name: 'John', age: 30, city: 'NYC' },
      { name: 'Jane', age: 25 },  // Missing city
      { name: 'Bob', email: 'bob@example.com' }  // Different keys
    ],
    csv: 'name,age,city,email\nJohn,30,NYC,\nJane,25,,\nBob,,,bob@example.com',
    difficulty: 'Medium - need to handle missing values'
  }
};

console.log('⚠️  JSON to CSV: Multiple strategies needed');
Enter fullscreen mode Exit fullscreen mode

CSV Escaping Rules

// CSV requires proper escaping
const csvEscapingRules = {
  commas: {
    value: 'Last, First',
    escaped: '"Last, First"',
    rule: 'Wrap in quotes if contains comma'
  },

  quotes: {
    value: 'He said "Hello"',
    escaped: '"He said ""Hello"""',
    rule: 'Wrap in quotes and double any quotes inside'
  },

  newlines: {
    value: 'Line 1\nLine 2',
    escaped: '"Line 1\nLine 2"',
    rule: 'Wrap in quotes if contains newline'
  },

  leadingSpaces: {
    value: '  Indented',
    escaped: '"  Indented"',
    rule: 'Wrap in quotes if starts with space'
  },

  examples: {
    safe: ['John', '30', 'NYC'],
    needsEscape: [
      'Smith, John',        // Has comma
      'She said "Hi"',      // Has quotes
      'Line 1\nLine 2',     // Has newline
      '  Spaced'            // Leading space
    ]
  }
};

console.log('CSV escaping: Critical for data integrity');
Enter fullscreen mode Exit fullscreen mode

Implementation Methods

1. JavaScript JSON to CSV Converter

// Production-ready JSON to CSV converter
class JSONToCSV {
  // Convert JSON array to CSV
  static convert(jsonArray, options = {}) {
    const {
      delimiter = ',',
      newline = '\n',
      header = true,
      flattenObjects = true,
      flattenArrays = 'join',  // 'join', 'json', or 'separate'
      arraySeparator = '; ',
      excludeKeys = [],
      includeKeys = null,  // null = all keys
      sortKeys = false
    } = options;

    if (!Array.isArray(jsonArray) || jsonArray.length === 0) {
      return '';
    }

    // Get all unique keys
    let keys = this.getAllKeys(jsonArray, flattenObjects);

    // Filter keys
    if (includeKeys) {
      keys = keys.filter(k => includeKeys.includes(k));
    }
    keys = keys.filter(k => !excludeKeys.includes(k));

    // Sort keys if requested
    if (sortKeys) {
      keys.sort();
    }

    // Build CSV
    const rows = [];

    // Header row
    if (header) {
      rows.push(keys.map(k => this.escapeValue(k, delimiter)).join(delimiter));
    }

    // Data rows
    jsonArray.forEach(obj => {
      const flattened = flattenObjects ? this.flatten(obj, flattenArrays, arraySeparator) : obj;

      const values = keys.map(key => {
        let value = flattened[key];

        if (value === undefined || value === null) {
          return '';
        }

        if (Array.isArray(value)) {
          if (flattenArrays === 'join') {
            value = value.join(arraySeparator);
          } else if (flattenArrays === 'json') {
            value = JSON.stringify(value);
          }
        } else if (typeof value === 'object') {
          value = JSON.stringify(value);
        }

        return this.escapeValue(String(value), delimiter);
      });

      rows.push(values.join(delimiter));
    });

    return rows.join(newline);
  }

  // Get all unique keys from array of objects
  static getAllKeys(jsonArray, flatten = true) {
    const keysSet = new Set();

    jsonArray.forEach(obj => {
      const keys = flatten ? Object.keys(this.flatten(obj)) : Object.keys(obj);
      keys.forEach(k => keysSet.add(k));
    });

    return Array.from(keysSet);
  }

  // Flatten nested object
  static flatten(obj, arrayHandling = 'join', arraySeparator = '; ', prefix = '') {
    const flattened = {};

    Object.keys(obj).forEach(key => {
      const value = obj[key];
      const newKey = prefix ? `${prefix}.${key}` : key;

      if (value === null || value === undefined) {
        flattened[newKey] = value;
      } else if (Array.isArray(value)) {
        if (arrayHandling === 'join') {
          flattened[newKey] = value.join(arraySeparator);
        } else if (arrayHandling === 'json') {
          flattened[newKey] = JSON.stringify(value);
        } else {
          flattened[newKey] = value;
        }
      } else if (typeof value === 'object' && !(value instanceof Date)) {
        // Recursively flatten nested objects
        Object.assign(flattened, this.flatten(value, arrayHandling, arraySeparator, newKey));
      } else {
        flattened[newKey] = value;
      }
    });

    return flattened;
  }

  // Escape CSV value
  static escapeValue(value, delimiter = ',') {
    // Convert to string
    const str = String(value);

    // Check if escaping needed
    const needsEscape = 
      str.includes(delimiter) ||
      str.includes('"') ||
      str.includes('\n') ||
      str.includes('\r') ||
      str.startsWith(' ') ||
      str.endsWith(' ');

    if (!needsEscape) {
      return str;
    }

    // Escape quotes by doubling them
    const escaped = str.replace(/"/g, '""');

    // Wrap in quotes
    return `"${escaped}"`;
  }

  // Convert single object to CSV
  static objectToCSV(obj, options = {}) {
    return this.convert([obj], options);
  }

  // Parse CSV back to JSON (bonus utility)
  static parseCSV(csv, options = {}) {
    const { delimiter = ',', header = true } = options;

    const lines = csv.split(/\r?\n/).filter(line => line.trim());

    if (lines.length === 0) return [];

    const headers = header ? this.parseCSVLine(lines[0], delimiter) : null;
    const startIndex = header ? 1 : 0;

    const result = [];

    for (let i = startIndex; i < lines.length; i++) {
      const values = this.parseCSVLine(lines[i], delimiter);

      if (header && headers) {
        const obj = {};
        headers.forEach((key, index) => {
          obj[key] = values[index] || '';
        });
        result.push(obj);
      } else {
        result.push(values);
      }
    }

    return result;
  }

  // Parse CSV line handling quoted values
  static parseCSVLine(line, delimiter = ',') {
    const values = [];
    let current = '';
    let inQuotes = false;

    for (let i = 0; i < line.length; i++) {
      const char = line[i];
      const next = line[i + 1];

      if (char === '"') {
        if (inQuotes && next === '"') {
          // Escaped quote
          current += '"';
          i++; // Skip next quote
        } else {
          // Toggle quote state
          inQuotes = !inQuotes;
        }
      } else if (char === delimiter && !inQuotes) {
        // End of value
        values.push(current);
        current = '';
      } else {
        current += char;
      }
    }

    // Add last value
    values.push(current);

    return values;
  }
}

// Usage examples
const users = [
  {
    id: 1,
    name: 'John Doe',
    email: 'john@example.com',
    age: 30,
    address: {
      street: '123 Main St',
      city: 'New York',
      zip: '10001'
    },
    skills: ['JavaScript', 'Python', 'SQL']
  },
  {
    id: 2,
    name: 'Jane Smith',
    email: 'jane@example.com',
    age: 25,
    address: {
      street: '456 Oak Ave',
      city: 'Boston',
      zip: '02101'
    },
    skills: ['React', 'Node.js']
  }
];

// Basic conversion
const csv = JSONToCSV.convert(users);
console.log('Basic CSV:');
console.log(csv);

// Custom options
const customCSV = JSONToCSV.convert(users, {
  delimiter: ';',
  flattenObjects: true,
  flattenArrays: 'join',
  arraySeparator: ' | ',
  sortKeys: true,
  excludeKeys: ['id']
});

console.log('\nCustom CSV:');
console.log(customCSV);

// Without header
const noHeaderCSV = JSONToCSV.convert(users, { header: false });
console.log('\nNo header CSV:');
console.log(noHeaderCSV);
Enter fullscreen mode Exit fullscreen mode

2. Express API for JSON to CSV Conversion

const express = require('express');
const app = express();

app.use(express.json({ limit: '50mb' }));

// Convert JSON to CSV
app.post('/api/json-to-csv', (req, res) => {
  try {
    const { json, options = {} } = req.body;

    // Parse JSON if string
    const data = typeof json === 'string' ? JSON.parse(json) : json;

    // Ensure array
    const jsonArray = Array.isArray(data) ? data : [data];

    // Convert to CSV
    const csv = JSONToCSV.convert(jsonArray, options);

    res.set({
      'Content-Type': 'text/csv',
      'Content-Disposition': 'attachment; filename="export.csv"'
    });

    res.send(csv);
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});

// Convert JSON file to CSV
app.post('/api/json-to-csv/file', async (req, res) => {
  try {
    const { url, options = {} } = req.body;

    // Fetch JSON from URL
    const response = await fetch(url);
    const data = await response.json();

    // Convert to CSV
    const csv = JSONToCSV.convert(Array.isArray(data) ? data : [data], options);

    res.set({
      'Content-Type': 'text/csv',
      'Content-Disposition': 'attachment; filename="export.csv"'
    });

    res.send(csv);
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});

// Preview conversion (first 10 rows)
app.post('/api/json-to-csv/preview', (req, res) => {
  try {
    const { json, options = {} } = req.body;

    const data = typeof json === 'string' ? JSON.parse(json) : json;
    const jsonArray = Array.isArray(data) ? data : [data];

    // Convert only first 10 rows
    const preview = JSONToCSV.convert(jsonArray.slice(0, 10), options);

    res.json({
      preview,
      totalRows: jsonArray.length,
      showing: Math.min(10, jsonArray.length)
    });
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});

// Get CSV info (keys, row count, etc.)
app.post('/api/json-to-csv/info', (req, res) => {
  try {
    const { json } = req.body;

    const data = typeof json === 'string' ? JSON.parse(json) : json;
    const jsonArray = Array.isArray(data) ? data : [data];

    const keys = JSONToCSV.getAllKeys(jsonArray);

    res.json({
      totalRows: jsonArray.length,
      columns: keys.length,
      columnNames: keys,
      hasNestedObjects: keys.some(k => k.includes('.')),
      sampleRow: jsonArray[0]
    });
  } catch (error) {
    res.status(400).json({ error: error.message });
  }
});

app.listen(3000, () => {
  console.log('JSON to CSV API running on port 3000');
  console.log('POST /api/json-to-csv - Convert JSON to CSV');
  console.log('POST /api/json-to-csv/file - Convert from URL');
  console.log('POST /api/json-to-csv/preview - Preview conversion');
  console.log('POST /api/json-to-csv/info - Get conversion info');
});
Enter fullscreen mode Exit fullscreen mode

3. Node.js CLI Tool

#!/usr/bin/env node
const fs = require('fs').promises;
const path = require('path');

// CLI for JSON to CSV conversion
async function jsonToCSVCLI() {
  const args = process.argv.slice(2);

  if (args.length === 0 || args.includes('--help')) {
    console.log(`
JSON to CSV Converter CLI

Usage:
  json-to-csv <input.json> [options]

Options:
  -o, --output <file>      Output CSV file (default: input.csv)
  -d, --delimiter <char>   Delimiter character (default: ,)
  --no-header             Omit header row
  --flatten               Flatten nested objects
  --sort-keys             Sort columns alphabetically
  --array-join            Join arrays with separator
  --array-json            Keep arrays as JSON

Examples:
  json-to-csv users.json
  json-to-csv data.json -o export.csv
  json-to-csv api-response.json --flatten --sort-keys
    `);
    process.exit(0);
  }

  const inputFile = args[0];

  // Parse options
  const options = {
    delimiter: ',',
    header: true,
    flattenObjects: args.includes('--flatten'),
    flattenArrays: args.includes('--array-json') ? 'json' : 'join',
    sortKeys: args.includes('--sort-keys')
  };

  // Get output file
  let outputFile = inputFile.replace('.json', '.csv');
  const outputIndex = args.indexOf('-o') !== -1 ? args.indexOf('-o') : args.indexOf('--output');
  if (outputIndex !== -1 && args[outputIndex + 1]) {
    outputFile = args[outputIndex + 1];
  }

  // Get delimiter
  const delimiterIndex = args.indexOf('-d') !== -1 ? args.indexOf('-d') : args.indexOf('--delimiter');
  if (delimiterIndex !== -1 && args[delimiterIndex + 1]) {
    options.delimiter = args[delimiterIndex + 1];
  }

  // Check for no-header
  if (args.includes('--no-header')) {
    options.header = false;
  }

  try {
    console.log(`\nReading: ${inputFile}`);

    // Read JSON file
    const jsonContent = await fs.readFile(inputFile, 'utf8');
    const data = JSON.parse(jsonContent);

    // Ensure array
    const jsonArray = Array.isArray(data) ? data : [data];

    console.log(`Found ${jsonArray.length} records`);

    // Convert to CSV
    const csv = JSONToCSV.convert(jsonArray, options);

    // Write CSV file
    await fs.writeFile(outputFile, csv, 'utf8');

    console.log(`✓ CSV written: ${outputFile}`);
    console.log(`  Rows: ${jsonArray.length}`);
    console.log(`  Size: ${(csv.length / 1024).toFixed(2)}KB\n`);

  } catch (error) {
    console.error(`\n❌ Error: ${error.message}\n`);
    process.exit(1);
  }
}

// Run if called directly
if (require.main === module) {
  jsonToCSVCLI();
}
Enter fullscreen mode Exit fullscreen mode

4. Python Implementation

import json
import csv
from typing import List, Dict, Any

class JSONToCSV:
    @staticmethod
    def convert(json_array: List[Dict], options: Dict[str, Any] = None) -> str:
        """Convert JSON array to CSV string"""
        if not json_array:
            return ''

        options = options or {}
        delimiter = options.get('delimiter', ',')
        header = options.get('header', True)
        flatten = options.get('flatten', True)

        # Get all keys
        keys = JSONToCSV.get_all_keys(json_array, flatten)

        # Build CSV
        output = []

        # Header
        if header:
            output.append(delimiter.join(keys))

        # Rows
        for obj in json_array:
            flattened = JSONToCSV.flatten(obj) if flatten else obj

            values = []
            for key in keys:
                value = flattened.get(key, '')

                if isinstance(value, (list, dict)):
                    value = json.dumps(value)

                values.append(JSONToCSV.escape_value(str(value), delimiter))

            output.append(delimiter.join(values))

        return '\n'.join(output)

    @staticmethod
    def get_all_keys(json_array: List[Dict], flatten: bool = True) -> List[str]:
        """Get all unique keys"""
        keys_set = set()

        for obj in json_array:
            obj_keys = JSONToCSV.flatten(obj).keys() if flatten else obj.keys()
            keys_set.update(obj_keys)

        return sorted(keys_set)

    @staticmethod
    def flatten(obj: Any, prefix: str = '') -> Dict[str, Any]:
        """Flatten nested object"""
        flattened = {}

        for key, value in obj.items():
            new_key = f"{prefix}.{key}" if prefix else key

            if isinstance(value, dict):
                flattened.update(JSONToCSV.flatten(value, new_key))
            elif isinstance(value, list):
                flattened[new_key] = ', '.join(str(v) for v in value)
            else:
                flattened[new_key] = value

        return flattened

    @staticmethod
    def escape_value(value: str, delimiter: str = ',') -> str:
        """Escape CSV value"""
        if not value:
            return value

        needs_escape = (
            delimiter in value or
            '"' in value or
            '\n' in value or
            value.startswith(' ') or
            value.endswith(' ')
        )

        if needs_escape:
            escaped = value.replace('"', '""')
            return f'"{escaped}"'

        return value

    @staticmethod
    def to_file(json_array: List[Dict], filename: str, options: Dict[str, Any] = None):
        """Convert JSON to CSV file"""
        csv_content = JSONToCSV.convert(json_array, options)

        with open(filename, 'w', encoding='utf-8') as f:
            f.write(csv_content)

        print(f"✓ CSV written: {filename}")

# Usage
data = [
    {"name": "John", "age": 30, "city": "New York"},
    {"name": "Jane", "age": 25, "city": "Boston"}
]

csv = JSONToCSV.convert(data)
print(csv)

# To file
JSONToCSV.to_file(data, 'output.csv')
Enter fullscreen mode Exit fullscreen mode

5. Quick Online Conversion

For rapid testing, data exploration, or one-off conversions, using a JSON to CSV converter can quickly transform data without writing code. This is particularly useful when:

  • API exploration: Convert responses to spreadsheet format
  • Data analysis: Quickly analyze JSON data in Excel
  • Client deliverables: Export data for non-technical stakeholders
  • Prototyping: Test data transformations before coding

For production systems, integrate automated JSON to CSV conversion into your data pipelines for scalability and reliability.

Real-World Applications

1. Automated Report Generation

// Generate daily sales report
async function generateDailySalesReport() {
  console.log('Generating daily sales report...\n');

  // Fetch sales data from API
  const response = await fetch('https://api.example.com/sales/today');
  const sales = await response.json();

  console.log(`Fetched ${sales.length} sales records`);

  // Convert to CSV
  const csv = JSONToCSV.convert(sales, {
    flattenObjects: true,
    sortKeys: true,
    includeKeys: ['id', 'customer', 'product', 'amount', 'date']
  });

  // Save to file
  const filename = `sales-${new Date().toISOString().split('T')[0]}.csv`;
  await fs.writeFile(filename, csv);

  console.log(`✓ Report saved: ${filename}`);

  // Email to stakeholders
  await emailReport(filename, 'Daily Sales Report');

  console.log('✓ Report emailed to stakeholders\n');
}

// Run daily at 6am
// schedule.scheduleJob('0 6 * * *', generateDailySalesReport);
Enter fullscreen mode Exit fullscreen mode

2. API Data Export

// Export all users to CSV
app.get('/admin/users/export', async (req, res) => {
  try {
    // Fetch all users
    const users = await db.query('SELECT * FROM users');

    // Convert to CSV
    const csv = JSONToCSV.convert(users, {
      flattenObjects: true,
      excludeKeys: ['password_hash', 'reset_token']  // Security!
    });

    // Send as download
    res.set({
      'Content-Type': 'text/csv',
      'Content-Disposition': `attachment; filename="users-${Date.now()}.csv"`
    });

    res.send(csv);

    // Log export
    await db.query(
      'INSERT INTO audit_log (action, user_id, timestamp) VALUES ($1, $2, NOW())',
      ['user_export', req.user.id]
    );

  } catch (error) {
    res.status(500).json({ error: 'Export failed' });
  }
});
Enter fullscreen mode Exit fullscreen mode

3. Data Migration Tool

// Migrate data between systems
async function migrateCustomers(sourceAPI, targetCSV) {
  console.log('Starting customer migration...\n');

  let page = 1;
  let allCustomers = [];

  // Fetch all pages
  while (true) {
    const response = await fetch(`${sourceAPI}?page=${page}&limit=100`);
    const data = await response.json();

    if (data.customers.length === 0) break;

    allCustomers = allCustomers.concat(data.customers);
    console.log(`Fetched page ${page}: ${data.customers.length} customers`);

    page++;
  }

  console.log(`\nTotal customers: ${allCustomers.length}`);

  // Transform data
  const transformed = allCustomers.map(c => ({
    'Customer ID': c.id,
    'Full Name': `${c.first_name} ${c.last_name}`,
    'Email': c.email,
    'Phone': c.phone || '',
    'Address': `${c.address.street}, ${c.address.city}, ${c.address.state} ${c.address.zip}`,
    'Status': c.active ? 'Active' : 'Inactive',
    'Created': new Date(c.created_at).toLocaleDateString()
  }));

  // Convert to CSV
  const csv = JSONToCSV.convert(transformed);

  // Save
  await fs.writeFile(targetCSV, csv);

  console.log(`✓ Migration complete: ${targetCSV}`);
  console.log(`  Total records: ${transformed.length}\n`);
}
Enter fullscreen mode Exit fullscreen mode

4. Business Intelligence Export

// Export analytics data for Power BI
async function exportAnalyticsForBI() {
  // Fetch analytics data
  const analytics = await db.query(`
    SELECT 
      date,
      page_views,
      unique_visitors,
      bounce_rate,
      avg_session_duration,
      conversions,
      revenue
    FROM analytics
    WHERE date >= CURRENT_DATE - INTERVAL '90 days'
    ORDER BY date DESC
  `);

  // Convert to CSV
  const csv = JSONToCSV.convert(analytics, {
    delimiter: ',',
    sortKeys: false  // Keep order from query
  });

  // Save to BI folder
  const filename = 'analytics_export.csv';
  await fs.writeFile(`/bi/data/${filename}`, csv);

  console.log('✓ Analytics exported for Power BI');
}
Enter fullscreen mode Exit fullscreen mode

Testing JSON to CSV Conversion

// Jest tests
describe('JSON to CSV Conversion', () => {
  test('converts simple array to CSV', () => {
    const data = [
      { name: 'John', age: 30 },
      { name: 'Jane', age: 25 }
    ];

    const csv = JSONToCSV.convert(data);

    expect(csv).toContain('name,age');
    expect(csv).toContain('John,30');
    expect(csv).toContain('Jane,25');
  });

  test('handles missing values', () => {
    const data = [
      { name: 'John', age: 30, city: 'NYC' },
      { name: 'Jane', age: 25 }  // Missing city
    ];

    const csv = JSONToCSV.convert(data);

    expect(csv.split('\n')[2].split(',')[2]).toBe('');
  });

  test('flattens nested objects', () => {
    const data = [{
      name: 'John',
      address: { city: 'NYC', zip: '10001' }
    }];

    const csv = JSONToCSV.convert(data, { flattenObjects: true });

    expect(csv).toContain('address.city');
    expect(csv).toContain('address.zip');
  });

  test('escapes special characters', () => {
    const data = [{ name: 'Smith, John', note: 'He said "Hi"' }];

    const csv = JSONToCSV.convert(data);

    expect(csv).toContain('"Smith, John"');
    expect(csv).toContain('"He said ""Hi"""');
  });

  test('handles arrays', () => {
    const data = [{ name: 'John', skills: ['JS', 'Python'] }];

    const csv = JSONToCSV.convert(data, { flattenArrays: 'join' });

    expect(csv).toContain('JS; Python');
  });
});
Enter fullscreen mode Exit fullscreen mode

Conclusion: Bridge JSON and Business Tools

JSON to CSV conversion is essential for modern data workflows. From automated reports to data migration, business intelligence to stakeholder deliverables, converting JSON to CSV bridges the gap between developer tools and business analytics platforms.

Business-friendly format (Excel, Google Sheets)

Universal compatibility (every BI tool reads CSV)

Automated reporting (eliminate manual export)

Data analysis (spreadsheet functions)

Time savings (seconds vs hours)

Error elimination (perfect data transfer)

Stakeholder access (non-technical users)

Cost reduction ($18K+/year savings)

Conversion Best Practices:

✓ Flatten nested objects for compatibility
✓ Handle missing values (empty strings)
✓ Escape special characters (commas, quotes)
✓ Exclude sensitive data (passwords, tokens)
✓ Sort keys for consistent output
✓ Add audit logging for exports
✓ Validate data before conversion
✓ Use appropriate array handling
✗ Never include passwords/tokens
✗ Don't skip CSV escaping
✗ Avoid deeply nested structures
Enter fullscreen mode Exit fullscreen mode

The Bottom Line:
JSON is perfect for APIs. CSV is perfect for business users. Converting between them automates workflows, eliminates manual work, and enables data-driven decisions. One automated export saves hours weekly. Multiply that across a team, and you're saving tens of thousands of dollars annually—all while delivering better, faster insights to stakeholders.


How much time would JSON to CSV automation save your team? Share your export workflows in the comments!

Top comments (0)