
Variant Matrix
- 65 installs
- 41 repo stars
- Updated March 13, 2026
- finsilabs/awesome-ecommerce-skills
Generates and manages all size, color, and material combinations for a product with bulk price and inventory management using platform variant tools.
About
Builds and maintains full product variant matrices across attributes like size, color, and material with bulk pricing and inventory. A developer uses it when managing complex product catalogs.
- Generates all size/color/material combinations
- Bulk price and inventory management
Variant Matrix by the numbers
- 65 all-time installs (skills.sh)
- Ranked #3,110 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/finsilabs/awesome-ecommerce-skills --skill variant-matrixAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 65 |
|---|---|
| repo stars | ★ 41 |
| Last updated | March 13, 2026 |
| Repository | finsilabs/awesome-ecommerce-skills ↗ |
What it does
Generates and manages all size, color, and material combinations for a product with bulk price and inventory management using platform variant tools.
Files
Variant Matrix
Overview
Product variants let one product listing cover all size/color/material combinations — each with its own price, SKU, and inventory. Platforms generate the full matrix of combinations from your option values and handle the variant selector UI automatically. The main tasks are: entering options correctly, generating all SKUs, setting per-variant pricing and inventory, and managing large matrices efficiently.
When to Use This Skill
- When modeling apparel, footwear, or accessories where products have multiple option axes
- When importing products from a supplier CSV with flat variant rows that need to be grouped
- When building an admin interface for merchants to manage variant pricing and inventory
- When a variant selector on the product page needs to disable unavailable combinations
Core Instructions
Step 1: Determine platform and understand the variant model
| Platform | Options | Max Variants | Variant Fields |
|---|---|---|---|
| Shopify | Up to 3 options (e.g., Size, Color, Style) | 100 per product | Price, SKU, barcode, inventory, weight, image |
| WooCommerce | Unlimited attributes used as variations | Practically unlimited (performance degrades at ~50+) | Price, sale price, SKU, stock, weight, dimensions, image |
| BigCommerce | Unlimited options per product | 600 SKUs per product | Price adjustment, SKU, stock, weight, image |
| Custom / Headless | Design your own | Unlimited | Design your own variant fields |
---
Step 2: Platform-specific variant setup
---
Shopify
Creating variants from options:
1. Go to Admin → Products → [Product] 2. Scroll to the Options section 3. Click Add option to add the first axis (e.g., Size) 4. Enter the option values: XS, S, M, L, XL 5. Add a second option (e.g., Color): Red, Blue, Black 6. Shopify generates all combinations automatically (5 × 3 = 15 variants) 7. Scroll to the Variants section to see the generated matrix
Setting per-variant details:
- Click any variant row to edit its price, SKU, inventory, weight, and image
- Or use Edit variants bulk view to update multiple variants at once
Bulk variant management:
- Select multiple variants using checkboxes → Edit to update price or inventory for a group
- For large catalogs: use Matrixify (App Store) to import a CSV with one row per variant — the most efficient way to set up a large matrix
Disabling unavailable combinations:
- Variants that have no inventory automatically show "Sold Out" on the product page
- Shopify's variant selector does not auto-disable unavailable combinations by default — most themes require adding logic or using a theme app to grey out sold-out options
Adding/removing option values after launch:
- Add a new size (e.g., "XXL"): go to the Options section, add the value
- Shopify adds new variants for the new value; existing variants are unchanged
- Archive discontinued variants instead of deleting — deletion removes order history links
---
WooCommerce
Creating variations from attributes:
1. Create global attributes: Products → Attributes → Add Attribute (e.g., Size with values XS, S, M, L, XL) 2. On your product, go to the Attributes tab 3. Select your attribute (Size), check Used for variations, click Add 4. Add all values this product uses 5. Go to the Variations tab 6. Click Generate variations → WooCommerce creates one variation per combination 7. Expand each variation to set price, SKU, stock, and image
Bulk variation updates:
- WooCommerce's variation editor can be slow for products with 20+ variations
- Use WP All Import Pro for importing large variation matrices via CSV
- Or use the Variable Product Bulk Edit plugin for batch price/inventory updates
SKU generation: WooCommerce doesn't auto-generate SKUs. Enter them manually or use a pattern:
- Convention:
[PRODUCT-CODE]-[SIZE]-[COLOR]→ e.g.,SHIRT-M-RED - Use WP All Import to set SKUs in bulk from a spreadsheet
---
BigCommerce
Creating options and variants:
1. Go to Products → [Product] → Variations tab 2. Click Create options and add your option set (Size, Color, etc.) 3. BigCommerce generates the matrix of SKUs automatically 4. Click any SKU row to set:
- Price adjustment (e.g., +$5 for XL)
- SKU code
- Stock quantity
- Image
Option Sets:
- Go to Products → Option Sets to create reusable option groups
- Create a "Clothing Sizes" option set with XS–3XL once, then assign it to all apparel products
- Saves significant time when managing large catalogs
Bulk SKU management:
- Go to Products → Import & Export to export the catalog with all variant SKUs
- Edit in Excel and re-import for bulk price/inventory/SKU updates
---
Custom / Headless
Build variant generation from Cartesian product of options, with diff logic to safely update existing catalogs:
// lib/variantMatrix.ts
// Generate all variant combinations from option value arrays
// Input: [['S','M','L'], ['Red','Blue']]
// Output: [['S','Red'], ['S','Blue'], ['M','Red'], ['M','Blue'], ['L','Red'], ['L','Blue']]
export function cartesianProduct(arrays: string[][]): string[][] {
return arrays.reduce(
(acc, values) => acc.flatMap(combo => values.map(v => [...combo, v])),
[[]] as string[][]
);
}
// Generate variant records with auto-generated SKUs
export function generateVariants(baseSku: string, optionNames: string[], optionValues: string[][]) {
const combinations = cartesianProduct(optionValues);
return combinations.map(combo => ({
sku: [baseSku, ...combo].join('-').toUpperCase().replace(/\s+/g, '-'),
options: Object.fromEntries(optionNames.map((name, i) => [name, combo[i]])),
price: null, // Set individually or via bulk rule
inventoryQuantity: 0,
published: true,
}));
}
// Compute what to create vs. archive when option values change
export function diffVariants(
existingVariants: { options: Record<string, string> }[],
newCombinations: string[][],
optionNames: string[]
) {
const existingKeys = new Set(existingVariants.map(v => optionNames.map(n => v.options[n]).join('|')));
const newKeys = new Set(newCombinations.map(c => c.join('|')));
const toCreate = newCombinations.filter(combo => !existingKeys.has(combo.join('|')));
const toArchive = existingVariants.filter(v => !newKeys.has(optionNames.map(n => v.options[n]).join('|')));
return { toCreate, toArchive };
}
// Variant selector logic — which values are available given current selections?
export function getAvailableOptionValues(
variants: { options: Record<string, string>; inventoryQuantity: number }[],
currentSelections: Record<string, string>,
targetOptionName: string
): string[] {
return variants
.filter(v =>
Object.entries(currentSelections)
.filter(([name]) => name !== targetOptionName)
.every(([name, value]) => v.options[name] === value)
&& v.inventoryQuantity > 0
)
.map(v => v.options[targetOptionName])
.filter(Boolean);
}---
Step 3: Define a SKU naming convention
Consistent SKUs are critical for warehouse operations, reporting, and supplier communication. Establish a naming pattern before importing products.
Recommended format:
[PRODUCT-CODE]-[OPTION1]-[OPTION2]
Rules:
- Max 20 characters total
- All uppercase
- Hyphens between segments, no spaces
- Use standard size abbreviations: XS, S, M, L, XL, 2XL
- Use 3-letter color codes: RED, BLU, BLK, WHT, NVY, GRN
- Example: SHIRT-M-BLU → Blue shirt, Medium
SHOE-10-NVY → Navy shoe, Size 10Use Matrixify (Shopify) or WP All Import (WooCommerce) to bulk-assign SKUs following this pattern for an existing catalog.
---
Step 4: Manage large variant matrices
For products with many combinations (50+ variants):
Shopify: The 100-variant limit may be an issue for products with 3+ options. Strategies:
- Combine two options into one (e.g., "Size/Width" instead of separate Size and Width options)
- Create separate product records for each color and use metafields to link them
- Use Shopify's native Bundles for configurable products that require more flexibility
WooCommerce: Performance degrades with 50+ variations on one product. Use WooCommerce Performance Optimizations or YITH WooCommerce Variations Table to improve the admin and storefront experience.
Lazy variant creation: For extremely large matrices (e.g., custom paint colors × finish × size = 500+ SKUs), generate variants on demand when first ordered rather than pre-creating all combinations:
// For very large matrices: create variants on first request rather than upfront
export async function ensureVariantExists(productId: string, options: Record<string, string>) {
const key = Object.values(options).join('|');
const existing = await db.productVariants.findFirst({ where: { productId, variantKey: key } });
if (existing) return existing;
const product = await db.products.findUnique({ where: { id: productId } });
return db.productVariants.create({
data: {
productId,
sku: generateSku(product.baseSku, options),
variantKey: key,
options,
price: applyPricingRules(product, options),
inventoryQuantity: 0,
},
});
}Best Practices
- Archive variants, never delete them — deleted variants break historical orders that reference them; mark as
published: falsewhen discontinued - Use the platform's bulk edit tools for price and inventory updates — editing 100 variants one at a time is impractical; all platforms support bulk edits
- Limit options to 2–3 axes — beyond 3 options (e.g., size × color × material), the variant selector becomes confusing and the matrix grows exponentially
- Test the variant selector before launch — verify that selecting an unavailable combination shows the correct "sold out" state and that the price/image updates correctly
- Validate SKU uniqueness before bulk importing — a SKU collision during import silently skips the conflicting row or throws an error depending on the platform
Common Pitfalls
| Problem | Solution |
|---|---|
| Shopify 100-variant limit reached | Combine options or create separate products per color; use metafields to group related products in the storefront |
| Variant image not switching on option select | Assign variant-specific images explicitly per variant; the platform can only switch images if the variant has its own image set |
| Adding a new option value creates duplicate variants | Use diff logic to detect which combinations are genuinely new; Shopify handles this correctly in the admin, but custom imports need deduplication |
| Large matrix slows product page load | For 100+ variants, fetch variant availability via API on option change rather than embedding all variants in the initial page HTML |
| SKU collisions during bulk import | Normalize SKU segments before generating: toUpperCase().replace(/[^A-Z0-9]/g, '-'); check for duplicates before saving |
Related Skills
- @product-data-modeling
- @inventory-tracking
- @catalog-import-export
{
"context": "Tests whether the agent implements bulk variant update rules (set_price, adjust_price_pct, set_inventory) with optional filtering, uses lazy/on-demand variant generation for large matrices, applies Promise.all for concurrent updates, and respects the 3-axis limit.",
"type": "weighted_checklist",
"checklist": [
{
"name": "set_price rule",
"max_score": 7,
"description": "bulkVariantUpdate.js supports a rule type that sets an absolute price value on matching variants"
},
{
"name": "adjust_price_pct rule",
"max_score": 7,
"description": "bulkVariantUpdate.js supports a rule type that adjusts price by a percentage (e.g., +8% means multiply by 1.08) on matching variants"
},
{
"name": "set_inventory rule",
"max_score": 7,
"description": "bulkVariantUpdate.js supports a rule type that sets inventory quantity on matching variants"
},
{
"name": "Filter by option name/value",
"max_score": 8,
"description": "bulkVariantUpdate.js accepts an optional filter parameter restricting updates to variants where a specified option name equals a specified value (e.g., only Gloss finish)"
},
{
"name": "Filter applied correctly",
"max_score": 8,
"description": "output/bulk-update-report.json shows that at least one update was applied with a filter — variants NOT matching the filter retain their original values"
},
{
"name": "Price rounding to 2 decimal places",
"max_score": 6,
"description": "Percentage-adjusted prices in the output are rounded to 2 decimal places (e.g., using .toFixed(2) or equivalent)"
},
{
"name": "Concurrent updates via Promise.all",
"max_score": 8,
"description": "If the bulk update function is async, updates are executed concurrently using Promise.all() rather than sequentially in a loop"
},
{
"name": "Lazy variant creation",
"max_score": 10,
"description": "lib/lazyVariants.js returns an existing variant if the combination is already in the store, or creates and stores a new one only on first request"
},
{
"name": "Lazy store grows on demand",
"max_score": 8,
"description": "output/lazy-variants-store.json contains a variant that was not in the initial store (created on first request in the demo)"
},
{
"name": "SKU generated in lazy creation",
"max_score": 7,
"description": "Lazily created variants in output/lazy-variants-store.json include a generated sku field (not null or undefined)"
},
{
"name": "3-axis limit documented or enforced",
"max_score": 8,
"description": "The code or demo includes a comment, validation, or documentation note indicating that variant option axes should be limited to 3 dimensions"
},
{
"name": "variantKey or equivalent lookup",
"max_score": 8,
"description": "The lazy variant resolver uses a composite key derived from option values (e.g., joining with '|') to look up existing variants — not iterating and comparing object properties"
},
{
"name": "Pricing rules applied in report",
"max_score": 8,
"description": "output/bulk-update-report.json shows before/after prices (or the updated variant list) demonstrating that at least two different rule types were applied"
}
]
}
Variant Management for a Large Paint Product Catalog
Problem/Feature Description
A paint manufacturer sells their products across three option dimensions: color (80+ named colors), finish (Matte, Satin, Gloss, Semi-Gloss), and container size (1L, 2.5L, 5L, 10L). Their previous e-commerce solution stored every possible combination in the database at product setup time and embedded all that data in the product page HTML, which made their store pages load painfully slowly and caused import jobs to time out.
The new system needs two capabilities. First, a pricing management tool that their admin team can use to update prices and stock levels across large groups of variants in one operation — for instance, targeting only a specific finish or a specific container size. Second, a smarter approach to variant storage that doesn't require pre-generating thousands of records up front. The product team has flagged that they may eventually want to add more product dimensions, but three has already proven to be the practical ceiling for what their merchants can manage through the UI.
Output Specification
Write two JavaScript modules:
1. lib/bulkVariantUpdate.js — exports a function that accepts an array of variant objects, an update rule, and an optional filter targeting a subset of variants, then returns the updated array
2. lib/lazyVariants.js — exports a function that resolves a specific variant by its option combination from a store, generating and persisting a new record if one does not yet exist
Write a demo.js script that:
- Creates an in-memory store with a handful of pre-existing paint variants (at least 4, across different finishes and sizes)
- Applies at least two separate bulk operations with different rule types and different filters
- Requests a variant combination that is not in the initial store, demonstrating on-demand creation
- Writes results to
output/bulk-update-report.jsonandoutput/lazy-variants-store.json
Run demo.js so both output files are present on disk.
{
"context": "Tests whether the agent implements SKU generation following the prescribed naming conventions (uppercase, hyphens, max 20 chars, standard abbreviations), uses the correct cartesian product algorithm, normalizes special characters in option values, and structures variant objects with the expected fields.",
"type": "weighted_checklist",
"checklist": [
{
"name": "Cartesian product via reduce/flatMap",
"max_score": 10,
"description": "The cartesian product function uses arrays.reduce() with flatMap() internally — not nested for-loops or a recursive approach"
},
{
"name": "SKU all uppercase",
"max_score": 8,
"description": "All generated SKU strings in output/variants.json are fully uppercase (no lowercase letters)"
},
{
"name": "SKU uses hyphens only",
"max_score": 8,
"description": "SKU strings in output/variants.json use hyphens as separators — no spaces, underscores, or other separators between segments"
},
{
"name": "SKU max 20 chars",
"max_score": 8,
"description": "Every SKU string in output/variants.json is at most 20 characters long"
},
{
"name": "Special chars normalized",
"max_score": 10,
"description": "Option values containing spaces or non-alphanumeric characters (e.g. 'Navy Blue', 'Light Grey') are normalized before being included in the SKU — the raw space or special character does NOT appear in any SKU in output/variants.json"
},
{
"name": "Normalization regex pattern",
"max_score": 8,
"description": "The code applies .toUpperCase().trim().replace(/[^A-Z0-9]/g, '-') (or equivalent) to each option value segment before joining into the SKU"
},
{
"name": "SKU format structure",
"max_score": 8,
"description": "SKUs follow the [PRODUCT-CODE]-[OPTION1]-[OPTION2] pattern: base code first, then option value segments, joined with hyphens"
},
{
"name": "Variant options object",
"max_score": 8,
"description": "Each variant object in output/variants.json includes an 'options' field that is an object mapping option axis names (e.g. 'Size', 'Color') to their values"
},
{
"name": "Full combination coverage",
"max_score": 10,
"description": "The number of variants in output/variants.json equals the product of the counts of all option value arrays (all combinations are represented)"
},
{
"name": "generateVariants export",
"max_score": 8,
"description": "lib/variantMatrix.js exports a named function (generateVariants or similar) that accepts baseSku, option names, and option value arrays as parameters"
},
{
"name": "cartesianProduct export",
"max_score": 8,
"description": "lib/variantMatrix.js exports a separate named cartesianProduct (or equivalent) function distinct from the variant-generation function"
},
{
"name": "Size abbreviations",
"max_score": 6,
"description": "If size option values are present, standard abbreviations are used (S, M, L, XL, XS, etc.) rather than spelled-out words like 'Small' or 'Large' in the SKU segments"
}
]
}
Product Variant Library for Fashion Catalog
Problem/Feature Description
A fashion startup is building a Node.js backend for their e-commerce catalog. They sell apparel and footwear across multiple option dimensions — sizes, colors, and sometimes materials — and need a reusable JavaScript library that generates the complete set of product variants from a product's option configuration. Currently, their team generates variant records by hand in spreadsheets, which leads to inconsistent SKU codes and missed combinations.
The library will be used by their import pipeline and admin API. The team has warehouse staff who scan and print barcode labels, so the generated SKUs must be machine-readable and work reliably with their label printer system. Option values like "Navy Blue" or "Light Grey" come directly from the buyer's color naming system and need to be encoded into SKUs in a way that remains consistent and collision-free.
Output Specification
Write a JavaScript module at lib/variantMatrix.js that exports the following:
- A function that generates all combinations of option values (the Cartesian product)
- A function that takes a base product code, option axis names, and option value arrays and returns an array of variant objects — each with a
skustring and anoptionsobject mapping axis names to values
Also write a short demo.js script that calls the library with a sample product (at least 2 option axes, at least one option value containing a space or special character) and writes the resulting variants to output/variants.json.
Run demo.js so that output/variants.json is present on disk with actual variant data.
{
"context": "Tests whether the agent uses diff-based variant update logic (computing new vs. archived rather than delete-and-recreate), archives discontinued variants by marking published=false instead of removing them, and validates option value completeness to surface unpublished combinations.",
"type": "weighted_checklist",
"checklist": [
{
"name": "Diff function present",
"max_score": 10,
"description": "lib/variantLifecycle.js exports a function that accepts existing variants and new combinations and returns distinct 'toCreate' and 'toArchive' (or equivalent) collections"
},
{
"name": "toCreate uses set-difference logic",
"max_score": 8,
"description": "The diff function identifies variants to create by finding new combinations that do NOT already exist in the existing variant set — not by recreating all combinations from scratch"
},
{
"name": "toArchive uses set-difference logic",
"max_score": 8,
"description": "The diff function identifies variants to archive by finding existing variants whose combination is NOT in the new option set"
},
{
"name": "Archive sets published=false",
"max_score": 12,
"description": "The demo output (lifecycle-report.json) shows archived variants represented with published: false (or an equivalent archival flag), NOT as deleted/absent records"
},
{
"name": "No hard delete of variants",
"max_score": 10,
"description": "The code does NOT use any delete, remove, or splice operation on existing variant records — discontinued variants are retained and marked as archived/unpublished"
},
{
"name": "Completeness check function",
"max_score": 8,
"description": "lib/variantLifecycle.js exports a separate function that checks whether all option value combinations are represented and published, returning any missing or unpublished combinations"
},
{
"name": "Completeness warnings in report",
"max_score": 8,
"description": "output/lifecycle-report.json includes a field listing unpublished or missing combinations (not just an empty array) given the demo input that has at least one unpublished variant"
},
{
"name": "Report includes toCreate",
"max_score": 8,
"description": "output/lifecycle-report.json contains a field (toCreate or equivalent) listing the newly added variant combinations"
},
{
"name": "Report includes toArchive",
"max_score": 8,
"description": "output/lifecycle-report.json contains a field (toArchive or equivalent) listing the discontinued variant combinations"
},
{
"name": "Unchanged variants preserved",
"max_score": 8,
"description": "Variants whose option combination exists in both the old and new option set appear in neither toCreate nor toArchive — they are left unchanged"
},
{
"name": "Key-based comparison",
"max_score": 6,
"description": "The diff logic compares variants using a derived key (e.g., joining option values with a separator) rather than comparing full object references or IDs"
},
{
"name": "deleted_at or similar timestamp",
"max_score": 6,
"description": "Archived variants in the report or code include a deleted_at, archivedAt, or equivalent timestamp field alongside published: false"
}
]
}
Variant Option Management for an E-Commerce Admin Backend
Problem/Feature Description
An online apparel retailer has been running their store for two years and has thousands of orders in their database. Their product variants (sizes, colors) were set up when products were first listed, and now merchants need the ability to update option values over time — adding a new colorway to an existing product, or retiring a size that's being discontinued. However, their current system simply deletes and re-creates variants whenever options change, which has caused panicked support tickets from their fulfillment team when historical order line items start pointing to missing records.
The engineering team needs a robust variant management service. When a merchant changes the option configuration of a product, the backend must correctly reconcile the existing variant records with the new desired configuration. The service should also be able to surface any gaps in a product's variant setup to the admin UI, so merchants don't accidentally end up with a product grid where some combinations cannot be purchased.
Output Specification
Write a JavaScript module lib/variantLifecycle.js that exports:
- A function that, given an existing list of variant records and a new desired option configuration, determines what changes need to be made to the variant database
- A function that, given a product's option configuration and current variant records, identifies any gaps or issues in the variant set that the merchant should be aware of
Write a demo.js script that: 1. Sets up a product with Size (S, M) × Color (Red, Blue) — 4 possible combinations, with one variant not currently visible to customers 2. Simulates a merchant updating the product to add "Green" and remove "Red" as color options 3. Calls your functions and writes a report to output/lifecycle-report.json that documents the reconciliation results and any warnings
Run demo.js so that output/lifecycle-report.json is present on disk.
{
"name": "finsi/variant-matrix",
"version": "0.1.0",
"summary": "Generate and manage variant combinations (size x color x material) with SKU strategies",
"skills": {
"variant-matrix": {
"path": "SKILL.md"
}
}
}