Reproducible benchmarks
We run SynthForge against the open-source CTGAN baseline (a GAN-based tabular synthesizer from the SDV project) on two canonical public datasets (UCI Adult and Credit Card Default), across statistical fidelity, ML utility, privacy, and constraint conformance. The raw JSON powering this page is published alongside it. We run these ourselves and publish the raw results so you can check every number.
Last run: 2026-05-05T18:57:11.295000+00:00 ยท
raw results.json
How to read these numbers
SynthForge is schema-driven, not data-fitted. For each dataset we hand-author a schema from the public data dictionary and never show the generator the real CSV. CTGAN trains on the real data. The benchmark exists to measure that asymmetry, not to hide it.
So the fidelity and utility tables below are where a trained model wins, and it does. The privacy and constraint tables are where a generator that never saw the data wins: it cannot memorise rows it never read, and every row it emits satisfies the schema by construction.
A higher DCR means synthetic rows are far from real ones. An NNDR near 1 means no synthetic row hugs one specific real row. A validity rate of 1.000 means every row passed every range and enum constraint.
Headline
Four numbers per dataset, SynthForge against CTGAN. Constraint validity and privacy distance are where a generator that never saw the data wins. Fidelity and utility are where a model trained on it does.
adult
| Metric | SynthForge | CTGAN |
| Constraint validity | 1.000 | 0.729 |
| DCR p5 | 18.788 | 0.278 |
| Fidelity (overall) | 0.517 | 0.881 |
| LogReg TSTR | 0.685 | 0.889 |
credit
| Metric | SynthForge | CTGAN |
| Constraint validity | 1.000 | 1.000 |
| DCR p5 | 7.245 | 0.380 |
| Fidelity (overall) | 0.645 | 0.940 |
| LogReg TSTR | 0.513 | 0.705 |
adult
Constraint conformance
| Synthesizer | Validity rate |
| synthforge | 1.000 |
| ctgan | 0.729 |
Privacy
| Synthesizer | DCR p5 (normalised) | NNDR (median) |
| synthforge | 18.788 | 0.998 |
| ctgan | 0.278 | 0.951 |
ML utility (TSTR vs TRTR, AUC)
| Synthesizer | LogReg TRTR | LogReg TSTR | GBM TRTR | GBM TSTR |
| synthforge | 0.902 | 0.685 | 0.916 | 0.668 |
| ctgan | 0.902 | 0.889 | 0.916 | 0.891 |
Statistical fidelity
| Synthesizer | Overall | Column shapes | Column pair trends |
| synthforge | 0.517 | 0.573 | 0.461 |
| ctgan | 0.881 | 0.896 | 0.866 |
credit
Constraint conformance
| Synthesizer | Validity rate |
| synthforge | 1.000 |
| ctgan | 1.000 |
Privacy
| Synthesizer | DCR p5 (normalised) | NNDR (median) |
| synthforge | 7.245 | 0.971 |
| ctgan | 0.380 | 0.915 |
ML utility (TSTR vs TRTR, AUC)
| Synthesizer | LogReg TRTR | LogReg TSTR | GBM TRTR | GBM TSTR |
| synthforge | 0.716 | 0.513 | 0.780 | 0.485 |
| ctgan | 0.716 | 0.705 | 0.780 | 0.756 |
Statistical fidelity
| Synthesizer | Overall | Column shapes | Column pair trends |
| synthforge | 0.645 | 0.682 | 0.609 |
| ctgan | 0.940 | 0.919 | 0.960 |
Run history
Every benchmark run is appended here so you can see how the numbers change over time. We rerun whenever the generator changes meaningfully, or on a schedule. One run so far; future runs append below.
adult
| Date | Fidelity (overall) | TSTR (LogReg AUC) | DCR (privacy) | Integrity |
| Run date | SF | CTGAN | SF | CTGAN | SF | CTGAN | SF | CTGAN |
| 2026-05-05 | 0.517 | 0.881 | 0.685 | 0.889 | 18.788 | 0.278 | 1.000 | 0.729 |
credit
| Date | Fidelity (overall) | TSTR (LogReg AUC) | DCR (privacy) | Integrity |
| Run date | SF | CTGAN | SF | CTGAN | SF | CTGAN | SF | CTGAN |
| 2026-05-05 | 0.645 | 0.940 | 0.513 | 0.705 | 7.245 | 0.380 | 1.000 | 1.000 |
Full per-run reports: results-history.json.
Methodology
What we measure
| Family | Metric | Direction |
| Statistical fidelity | SDMetrics QualityReport: overall, column shapes, column pair trends | higher = better |
| ML utility | TSTR (Train-Synthetic-Test-Real) and TRTR AUC, for logistic regression and gradient boosting | higher = better; closer TSTR-to-TRTR is the meaningful signal |
| Privacy | DCR (5th-percentile distance to closest record, normalised by intra-real median) and NNDR (median nearest-neighbour distance ratio) | DCR higher = better; NNDR closer to 1 = better |
| Constraint conformance | Fraction of synthetic rows that satisfy all schema constraints (range, enum membership) | higher = better |
The caveat about schema authoring, and how to read the privacy numbers, are at the top of the page.
What we run
- SynthForge, with the same generator the product runs.
- CTGAN via SDV's
CTGANSynthesizer, default hyperparameters, 300 epochs, seed 42.
Both synthesizers produce a synthetic dataset of the same size as the real dataset, then every metric is run on the (real, synthetic) pair.
Datasets
- UCI Adult (Census Income, 1994). After dropping rows with missing values: 30,162 rows, 14 features, binary income target.
- UCI Credit Card Default (Taiwan, 2005). 30,000 rows, 23 features, binary default target.
Reproducibility
- The real datasets are the public UCI downloads linked above.
- All randomness uses seed 42.
- The numbers above come from the most recent run, and the full output of that run is in results.json.
What we explicitly do not measure (and why)
- Differential privacy guarantees. Differential privacy (DP) is a mathematical bound on how much any single record in the training data can change the output, expressed as numbers like "(epsilon=2, delta=1e-6)." SynthForge does not yet ship a DP-aware path; SmartNoise integration is on the roadmap. Claiming DP numbers without the math behind them would be misleading, so we don't.
- Image, text, time-series datasets. Out of scope for tabular synthetic data benchmarks.
- Membership-inference attacks against DP baselines. Same gap as DP.
Want to inspect the raw numbers? Download results.json.
The field-type catalog and these result snapshots are also staged as an MIT package under
github.com/synthforgeio/benchmarks
(MIT; field catalog + results).
Full harness source is still private; reach out at support@synthforge.io to review methodology.