Create realistic, analytics-ready retail data for Power BI, SQL, notebooks, lakehouses, demos, training, and benchmarking.
ContosoForge generates a complete dimensional model inspired by ContosoRetailDW: customers, products, stores, employees, dates, sales, returns, budgets, inventory, wishlists, complaints, and more. Every run is deterministic, schema-stable, and repeatable.
You can start with the web interface and never touch YAML, or use the full CLI and configuration system when you need precise control.
| I want to... | Recommended path |
|---|---|
| Generate a dataset without editing files | Use the web interface |
| Run a ready-made dataset from PowerShell | Use the one-command generator |
| Automate or precisely tune generation | Use the CLI and YAML configuration |
| Import the result into a database | Generate CSV, then use the SQL import tools |
If this is your first visit, use the web interface. It exposes the same generator through a friendlier workflow and includes configuration editors, presets, validation, progress, and logs.
Windows PowerShell is the project's primary and best-supported environment.
You need:
Install uv from PowerShell:
irm https://astral.sh/uv/install.ps1 | iexIf uv was just installed, fully close and reopen Windows Terminal, PowerShell,
or VS Code so the updated PATH is available.
git clone https://github.com/SharmaAntriksh/ContosoForge.git
cd ContosoForge
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned
.\scripts\create_venv.ps1The setup script creates .venv, provisions Python 3.13, and installs the
locked dependencies. Administrator rights are not required.
If you prefer not to change your PowerShell execution policy, run scripts with a one-time bypass:
powershell -ExecutionPolicy Bypass -File .\scripts\create_venv.ps1Choose either option below.
.\scripts\run_web.ps1Your browser opens to http://127.0.0.1:8502 in Quick Start. Work through
the six short steps:
- Pick a dataset size. Start with Quick sample.
- Choose the date range.
- Choose the business story you want the charts to show.
- Choose Parquet, CSV, or Delta Lake and a product catalog.
- Choose how many extra business tables you want.
- Review the estimate, select Apply these settings, then Generate dataset.
The choices are kept in server memory for this browser session; Quick Start
does not overwrite config.yaml or models.yaml. Progress and bounded live
logs appear below the review while generation is running.
Press Ctrl+C in PowerShell when you want to stop the web server.
The web interface is self-contained: its production JavaScript and styles are included in the repository, so launching it does not require Node.js or access to public CDNs.
Use Advanced Setup when you need every scale, model, YAML, or performance control. After a run, open Data Preview to browse any generated CSV, Parquet, or Delta table without leaving the web interface. CSV runs also expose the SQL Server and PostgreSQL wizard under Database Import.
Run the checked-in config.yaml and models.yaml:
.\scripts\run_generator.ps1The checked-in defaults showcase most of the available facts and dimensions. For a smaller, easier-to-explore first dataset:
.\scripts\run_generator.ps1 `
-Format parquet `
-SalesRows 100000 `
-Customers 1500 `
-Stores 25 `
-Products 500CLI overrides affect only that run; they do not modify config.yaml.
Before a large or unfamiliar run, validate the resolved configuration without generating data:
.\scripts\run_generator.ps1 -DryRunRuntime and disk usage depend on row count, date range, enabled facts, output format, and hardware. Start small before generating millions of sales rows.
Completed runs appear in a timestamped folder under generated_datasets/.
generated_datasets/
`-- <timestamped run>/
|-- Sales PBIP/ # CSV and Parquet only
| `-- Sales.pbip
|-- config/
| |-- config.yaml
| `-- models.yaml
|-- dimensions/
|-- facts/
`-- sql/ # CSV output only
For CSV and Parquet output, open Sales PBIP/Sales.pbip in Power BI Desktop.
The generated project already points to the files in its dataset folder.
Delta Lake output intentionally does not include a Power BI Project.
Each run can produce a complete retail analytics model rather than an isolated sales table.
| Area | Examples |
|---|---|
| Customers | Customers, profiles, organizations, loyalty tiers, acquisition channels, subscriptions |
| Products | Products, product profiles, categories, subcategories, suppliers, promotions |
| Retail operations | Stores, employees, store assignments, warehouses, geography |
| Time and currency | Calendar, fiscal and weekly-fiscal dates, time, currencies, exchange rates |
| Business facts | Sales, returns, budgets, inventory, wishlists, complaints |
Optional facts can be enabled or disabled independently. The full table list is available in Complete generated model.
If you are unsure, choose Parquet.
| Format | Choose it when... | Included extras |
|---|---|---|
parquet |
You use Power BI, Python, notebooks, DuckDB, or general analytics | Merged Parquet files and a Power BI Project |
csv |
You want plain-text files or plan to import into SQL Server/PostgreSQL | CSV chunks, database bootstrap scripts, and a Power BI Project |
deltaparquet |
You are testing Delta Lake or lakehouse workflows | Partitioned Delta tables; no Power BI Project |
delta is accepted as an alias for deltaparquet.
There are three levels of control. Start at the top and go deeper only when you need to.
These are the most useful controls for everyday runs:
.\scripts\run_generator.ps1 `
-Format parquet `
-SalesRows 1000000 `
-Customers 12000 `
-Stores 100 `
-Products 2000 `
-StartDate 2022-01-01 `
-EndDate 2025-12-31 `
-Workers 8The equivalent direct Python command is useful for automation and non-Windows systems:
uv run python main.py \
--format parquet \
--sales-rows 1000000 \
--customers 12000 \
--stores 100 \
--products 2000 \
--start-date 2022-01-01 \
--end-date 2025-12-31 \
--workers 8See the CLI reference for every flag and precedence rule.
--cleandeletes previous final output folders before generation. Use it only when you intentionally want to remove those generated datasets.
config.yaml controls what is generated and how large it is:
- Sales rows, customers, products, stores, and promotions
- Date range and output location
- CSV, Parquet, or Delta output
- Optional facts such as returns, budgets, inventory, wishlists, and complaints
- Product/customer history tracking
- Fiscal calendars, exchange rates, staffing, warehouses, and subscriptions
- Performance settings such as workers, chunk size, compression, and partitions
The first scale block is the safest place to begin. Most users should leave
the lower-level performance and modeling settings unchanged until they have run
the defaults successfully.
See the complete config.yaml guide.
models.yaml controls how the generated business behaves:
- Overall growth or decline
- Seasonality, shocks, and volatility
- Customer acquisition, participation, and churn
- Product demand and brand popularity
- Basket quantity and pricing behavior
- Discounts, markdowns, and returns
The most important setting is:
models:
macro_demand:
trend: gradual-growthUseful trend presets include:
| Desired story | Preset |
|---|---|
| Stable retail growth | steady-growth |
| Strong accelerating growth | strong-growth |
| Growth that eventually levels off | gradual-growth |
| Explosive late growth | hockey-stick |
| Strong retail seasonality plus growth | seasonal-with-growth |
| Mostly seasonal with little long-term growth | seasonal-dominant |
| Recession followed by recovery | recession-recovery |
| Rapid rise followed by a crash | boom-and-bust |
| Unpredictable year-to-year movement | volatile |
| Long-term erosion | decline or slow-decline |
The trend preset is not currently a CLI override. Change it in models.yaml or
through the web interface. See the models and trend preset guide.
The ratio between customers, sales rows, and months affects how convincing the result feels.
- Too many customers for the number of sales rows creates sparse purchase histories.
- Too few customers creates frequent repeat purchases and can make aggregate patterns appear overly smooth.
- Longer date ranges spread the same number of sales rows across more months.
A useful starting target for detailed customer analysis is approximately:
customers = sales rows / months / 1.5
This is guidance, not a validation rule. A broad customer dimension with sparse sales can be appropriate for acquisition or segmentation scenarios. See Scaling tips for examples.
Set the catalog in config.yaml:
scale:
products:
catalog: all
rows: 7930| Catalog | Base products | Description |
|---|---|---|
contoso |
2,517 | Original ContosoRetailDW products |
synthetic |
5,633 | Expanded retail, electronics, audio, and media catalog |
all |
About 7,930 | Combined catalog |
The generator can stratified-trim a catalog or create variants to reach the requested row count.
Dimensions are generated sequentially; sales facts use parallel workers. When iterating, you can build dimensions once and reuse them:
.\scripts\run_generator.ps1 -Only dimensions
.\scripts\run_generator.ps1 -Only salesSales-only generation requires existing dimensions.
Dimensions use configuration hashes to avoid unnecessary work. If you need to force a rebuild:
.\scripts\run_generator.ps1 -RegenDimensions products
.\scripts\run_generator.ps1 -RegenDimensions customers,products,stores
.\scripts\run_generator.ps1 -RegenDimensions allIf you change pricing bands in models.yaml, regenerate the product dimension
so dimension pricing and sales-time pricing remain synchronized.
uv run python main.py --refresh-fx-masterExchange-rate dates follow the global dataset date range.
workerscontrols parallel sales workers. Do not set it higher than your available CPU count.chunk_sizeis a performance and memory setting; it does not change the generated business shape.- Small chunks add overhead. Very large chunks increase memory pressure.
- The default chunk size of one million rows is a sensible starting point.
The model is lightly snowflaked and designed for BI, analytics engineering, data modeling, and database exercises.
| Group | Tables |
|---|---|
| Customers and accounts | Customers, CustomerProfile, OrganizationProfile, Plans, CustomerSubscriptions, LoyaltyTiers, CustomerAcquisitionChannels |
| Products and catalog | Products, ProductProfile, ProductCategory, ProductSubcategory, Suppliers, Promotions |
| Locations and organization | Stores, Warehouses, Employees, EmployeeStoreAssignments, Geography |
| Time | Dates with calendar/fiscal/weekly-fiscal attributes, Time |
| Currency | Currency, ExchangeRates, monthly exchange rates |
| Other lookups | Channels, ReturnReason |
- Sales, or split OrderHeader and OrderDetail output
- Returns
- BudgetYearly and BudgetMonthly
- InventorySnapshot
- CustomerWishlists
- Complaints
generated_datasets/
`-- <timestamped run>/
|-- Sales PBIP/ # CSV and Parquet only
|-- config/ # effective config.yaml and models.yaml
|-- dimensions/
|-- facts/
| |-- sales/
| |-- returns/
| |-- budget/
| |-- inventory/
| |-- customer_wishlists/
| `-- complaints/
`-- sql/ # CSV only
|-- sqlserver/
`-- postgres/
The packaged configuration records the settings used for that run.
CSV output includes generated SQL Server and PostgreSQL bundles with table DDL, load scripts, constraints, views, verification procedures, and indexes.
| Task | Command or documentation |
|---|---|
| Import from the web UI | Open Database Import, choose SQL Server or PostgreSQL, then select a CSV run |
| Import into SQL Server | scripts/run_sql_server_import.ps1 |
| Import into PostgreSQL | scripts/run_postgres_import.ps1 |
| Provision a SQL login for SSAS/Power BI | Tabular user guide |
| Manage keys and verify an import | Post-import procedures |
Generated identifiers are PascalCase. At import time you can choose
pascal or snake; the import tool regenerates the SQL bundle without changing
the CSV or Parquet data. The PostgreSQL wizard recommends snake so ordinary
queries do not need quoted identifiers.
| Task | Script | Guide |
|---|---|---|
| Recompress or change row groups in Parquet | scripts/optimize_parquet.py |
Parquet optimization |
| Compact small Delta Lake files | scripts/optimize_delta.py |
Delta optimization |
| Change Delta Lake partition layout | scripts/repartition_delta.py |
Delta repartitioning |
Install uv, clone the repository, and synchronize the locked environment:
git clone https://github.com/SharmaAntriksh/ContosoForge.git
cd ContosoForge
uv sync --extra sql --extra postgresGenerate data:
uv run python main.py --format parquet --sales-rows 100000Launch the web interface:
uv run python -m uvicorn web.api:app --port 8502Then open http://127.0.0.1:8502.
The database drivers are optional. For a smaller core-only environment, use:
uv syncFully close and reopen the terminal application. A new tab may inherit the old environment from Windows Terminal or VS Code.
For the current PowerShell session, you can also use:
$env:Path = "$env:USERPROFILE\.local\bin;$env:Path"Allow locally created scripts for your user:
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSignedOr use a one-time bypass:
powershell -ExecutionPolicy Bypass -File .\scripts\run_generator.ps1Use .\scripts\run_generator.ps1 or uv run python main.py so the project
environment is selected. A bare python main.py may use an unrelated system
Python.
The first Python start on Windows can take approximately 10–20 seconds while Windows Defender scans new package files, Python creates bytecode caches, and the operating system warms its file cache. Later starts are usually faster.
Dimension files are versioned by configuration hash. Force regeneration:
.\scripts\run_generator.ps1 -RegenDimensions productsWorkers use data/ for scratch output. Completed, self-contained datasets are
the timestamped folders under generated_datasets/.
CSV and Parquet runs include a Power BI Project with preconfigured file paths.
Open the .pbip file directly in Power BI Desktop.
The project includes tests for configuration, dimensions, facts, determinism, pricing, SQL generation, PostgreSQL behavior, packaging, the web API, and end-to-end integration.
On Windows, use the project interpreter directly:
.\.venv\Scripts\python.exe -m pytest
.\.venv\Scripts\python.exe -m pytest tests/test_geography.py
.\.venv\Scripts\python.exe -m pytest -k "deterministic"On macOS or Linux:
uv run pytestNode.js is needed only when changing files under web/frontend/. The checked-in
production assets are already used by run_web.ps1.
cd web\frontend
npm ci
npm run build
npm run build:checkThe build produces content-hashed assets under web/frontend/dist/. Commit
those generated files with the frontend source change. Use npm run dev to
rebuild automatically while working; see the
frontend development guide.
| Topic | Guide |
|---|---|
| Full CLI flag reference | CLI reference |
Every config.yaml setting |
Configuration guide |
| Business models and trend presets | Models guide |
| Pipeline architecture | Pipeline flowchart |
| Parquet, Delta, and database operations | Operations guides |
| Web log retention and preview performance | Web UI performance |
ContosoForge is licensed under the PolyForm Noncommercial License 1.0.0.
You may use, modify, and share it for noncommercial purposes. Commercial use,
including selling it, is not permitted. Keep the attribution notice
Copyright (c) 2026 Antriksh Sharma. See LICENSE.md for the full
terms.




