Skip to content
2026

DataForge

A browser-based tool for generating related e-commerce seed data as JSON, CSV or SQL.

Overview

I initially built DataForge as a side project to supply realistic seed data for my full-stack e-commerce application. It grew into a standalone browser tool for configuring product catalogues, generating related customers, orders and reviews, and exporting them without a backend or account.

context
Personal project
role
Solo
started
Feb 2026
setting
Client-side seed-data tool with a public GitHub Pages demo; configuration is stored locally in the browser.
built with
  • TypeScript 5.9
  • React 19.2
  • Zustand 5
  • Faker 9
  • Vite 7.3
  • Tailwind CSS 4
  • +1

Screenshots

Select an image to inspect the full-resolution screenshot.

DataForge light workspace with smartphone catalogue controls beside generated product JSON and tabs for five related tables.
The smartphone demo combines brand and model controls with generated products, customers, orders, order lines and reviews. The selected product table can be inspected before export. Original in project repository
Output Fields inspector renaming weight_kg to w_kg, with w_kg visible in the adjacent JSON preview.
The Fields inspector maps weight_kg to w_kg in the output preview. The underlying generated dataset keeps its canonical field names. Original in project repository
DataForge dark theme showing the smartphone configuration and output field mapping interface.
The same configuration and field-mapping workspace in dark mode. Theme preference is saved locally, separately from dataset configuration. Original in project repository

Key decisions

Generate related rows from one canonical dataset
Products and customers are generated before orders, order lines and reviews, so dependent rows can reference existing IDs.
Rename fields at the output boundary
A shared mapping transform feeds the preview, clipboard and exporters without mutating the generated rows.
Separate generation logic from the interface
Core generation, validation and serialization modules are independent of React and the browser adapters.

Demonstrated results

Relationships and totals are covered by tests
Dataset tests check references across all five tables, order totals, decimal precision and repeatability with a fixed seed and clock.
Mapping behaviour is shared across output formats
Serialization tests cover mapped JSON keys, flattened CSV columns, PostgreSQL and MySQL column identifiers, identity output and source immutability.

Known limitations

A seed does not freeze the clock
Timestamp fields depend on generation time. Exact repeatability requires the same configuration, seed and time input, not the seed alone.
SQL output assumes an existing schema
The exporter creates INSERT statements with canonical table names. It does not create tables or adapt every database constraint automatically.
Generated data stays in browser memory
Configuration persists, but the dataset does not. Reloading requires regeneration, and large datasets remain subject to browser resource limits.

From e-commerce fixture to standalone tool

The original use case came from my full-stack e-commerce project. A storefront needs more than unrelated random product rows: customers place orders, order lines refer to products, and reviews belong to both a product and a customer. I wanted configurable data that I could regenerate and export for development.

The repository starts in February 2026. Later work extracted the generation logic, added related tables and export formats, and introduced output field mapping. The current interface exposes six category templates, editable brands and models, weighted brand selection, price overrides and typed attributes. Presets package the configuration so it can be reused rather than rebuilt by hand.

generateDataset() builds products and customers first. The order generator then selects from those existing rows, and review generation receives the same product and customer collections. The returned dataset has five tables: products, customers, orders, order_lines and reviews.

The distinction matters at export time. An order line carries a product ID and an order ID, not independently generated lookalikes. Dataset tests check that each reference exists and that each order total matches the sum of its line totals. Additional cases check cent precision and empty related datasets.

These are generation and unit-test guarantees in the reviewed source, rather than evidence that every export has been imported into every possible target schema. The dataset tests make the checked relationships explicit.

Field mapping without changing the dataset

A consumer may need w_kg rather than weight_kg, or camelCase instead of snake_case. Changing the internal row types for each consumer would couple generation to export preferences. DataForge instead retains canonical rows and applies an output mapping immediately before serialization.

The same mapping-aware wrappers serve preview, clipboard, JSON, CSV and SQL. Validation rejects invalid identifiers, duplicate names and collisions, including the attr_* columns produced when CSV flattens product attributes. Invalid mappings block data copy and download until corrected. Table names stay canonical, and the attributes container is fixed.

The serialization tests check each format, unchanged output under an identity mapping, and that the transformation does not mutate source rows. Preset version 2 carries the mapping; older version 1 presets migrate with an identity mapping.

Repeatability and the clock

The random-number wrapper owns a seeded Faker instance. Reusing the seed and configuration reproduces catalogue choices and relationships, but timestamps use a separate now input that defaults to the current time.

The complete dataset test therefore fixes all three inputs:

generateDataset(category, brands, selectedBrandIds, config, new SeededRng(42), now);

This is useful for fixtures whose exact values matter. In the browser, running the same configuration on another day should not be described as byte-for-byte reproduction of every timestamp.

Export boundaries

JSON can contain the full dataset; CSV exports the active table and flattens product attributes into columns. SQL writes the full dataset in dependency order: products, customers, orders, order lines, then reviews.

The SQL exporter quotes identifiers for PostgreSQL or MySQL and emits INSERT statements. It does not generate DDL. The receiving database needs compatible tables, columns and constraints, and output field mappings need to match that schema.

A browser tool with a testable core

The core modules contain generation, normalization, field validation, presets and serialization. React components use a Zustand store, while small browser adapters handle downloads, theme and panel sizing. This lets the test suite exercise data behaviour without rendering the entire interface.

Configuration persists in localStorage, including output mappings. The generated dataset is deliberately excluded from persisted state. Reloading returns to the configuration and preview flow instead of restoring old generated rows.

All generation happens locally in memory. There is no backend or account, and no server-side job queue for large datasets. The repository's tests focus on logic and helpers; they should not be presented as a full end-to-end browser test suite or a benchmark of large-dataset performance.

The public architecture notes describe the module boundaries, persistence keys and deployment pipeline.

Stack and source figures

how it fits together

generation
  • Faker + TypeScript A seeded Faker wrapper supplies random values to declarative catalogue templates and the related-row generators.
interface and state
  • React + Zustand Catalogue editors, dataset tabs and field mapping share a store; configuration persists in localStorage while generated rows stay in memory.
  • Tailwind CSS Light and dark themes, a resizable desktop split and a configuration drawer for smaller screens.
verification and delivery
  • Vitest Tests generation, output formats, field validation, presets, persistence migrations and browser-adapter helpers.
  • Vite + GitHub Actions Builds a static application; CI gates deployment to GitHub Pages on lint, typecheck, tests and build.