Product Variants
Create variations of products with different attributes like Size, Color, Material, etc. Each variant has its own SKU and can be managed independently.
Important
Product Variant Model
Structure and properties of a Product Variant
class ProductVariant {
id: string; // Unique UUID identifier
productId: string; // Parent product ID (required)
sku: string; // Unique SKU for this variant (required)
attributeValues: Record<string, string>; // e.g., { "Size": "L", "Color": "Red" }
isActive: boolean; // Active status (default: true)
createdAt: Date;
updatedAt: Date;
// Helper methods
getDisplayName(): string; // Returns "Size: L, Color: Red"
matchesAttributes(attributes: Record<string, string>): boolean;
}Variant Attributes
Create attribute types before creating variants
Create variant attributes:
import { createVariantAttributeService } from "commercio";
const variantAttributeService = createVariantAttributeService();
// Create attribute types (e.g., Size, Color, Material)
const sizeAttribute = await variantAttributeService.createVariantAttribute("Size");
const colorAttribute = await variantAttributeService.createVariantAttribute("Color");
// Get all attributes
const allAttributes = await variantAttributeService.getAllVariantAttributes();
const activeAttributes = await variantAttributeService.getAllVariantAttributes(true);Get attribute by name:
// Get attribute by name
const sizeAttr = await variantAttributeService.getVariantAttributeByName("Size");Create Product Variant
Create a variant with attribute values and unique SKU
Basic example:
import { createServices } from "commercio";
const {
categoryService,
productService,
productVariantService,
variantAttributeService,
} = createServices();
// 1. Create category and product first
const category = await categoryService.createCategory("Clothing");
const product = await productService.createProduct(
"T-Shirt",
"SKU-TSHIRT-001",
category.id
);
// 2. Create variant attributes (optional, but recommended)
await variantAttributeService.createVariantAttribute("Size");
await variantAttributeService.createVariantAttribute("Color");
// 3. Create product variant
const variant = await productVariantService.createProductVariant(
product.id,
"SKU-TSHIRT-001-L-RED",
{
Size: "L",
Color: "Red",
}
);
console.log(variant.id); // UUID
console.log(variant.productId); // Product ID
console.log(variant.sku); // "SKU-TSHIRT-001-L-RED"
console.log(variant.attributeValues); // { Size: "L", Color: "Red" }
console.log(variant.isActive); // true
console.log(variant.getDisplayName()); // "Size: L, Color: Red"Error Handling
// 1. Product doesn't exist
try {
await productVariantService.createProductVariant(
"non-existent-product-id",
"SKU-001",
{ Size: "L" }
);
} catch (error) {
// Error: Product with ID "..." not found
}
// 2. SKU already exists
try {
await productVariantService.createProductVariant(
product.id,
"SKU-ALREADY-EXISTS",
{ Size: "L" }
);
await productVariantService.createProductVariant(
product.id,
"SKU-ALREADY-EXISTS", // Same SKU!
{ Size: "M" }
);
} catch (error) {
// Error: Product variant with SKU "SKU-ALREADY-EXISTS" already exists
}
// 3. Same attribute values for same product
try {
await productVariantService.createProductVariant(
product.id,
"SKU-001",
{ Size: "L", Color: "Red" }
);
await productVariantService.createProductVariant(
product.id,
"SKU-002",
{ Size: "L", Color: "Red" } // Same attributes!
);
} catch (error) {
// Error: Product variant with attributes already exists
}Variant Operations
Get Variant
Retrieve variants by ID, SKU, or attributes
Get by ID:
// Get variant by ID
const variant = await productVariantService.getProductVariantById(variantId);
console.log(variant.sku);
console.log(variant.attributeValues);
console.log(variant.getDisplayName());Get by SKU:
// Get variant by SKU
const variant = await productVariantService.getProductVariantBySku("SKU-TSHIRT-001-L-RED");
console.log(variant.id);
console.log(variant.productId);Find by attributes:
// Find variant by product and attribute values
const variant = await productVariantService.findVariantByAttributes(
product.id,
{ Size: "L", Color: "Red" }
);
if (variant) {
console.log(variant.sku);
} else {
console.log("Variant not found");
}Error Handling
try {
await productVariantService.getProductVariantById("non-existent-id");
} catch (error) {
// Error: Product variant with ID "..." not found
}
try {
await productVariantService.getProductVariantBySku("NON-EXISTENT-SKU");
} catch (error) {
// Error: Product variant with SKU "NON-EXISTENT-SKU" not found
}Complete Example
Full workflow: Creating products with variants
import { createServices } from "commercio";
const {
categoryService,
productService,
productVariantService,
variantAttributeService,
} = createServices();
// 1. Create category
const category = await categoryService.createCategory(
"Clothing",
"Apparel and fashion items"
);
// 2. Create base product
const product = await productService.createProduct(
"Premium T-Shirt",
"SKU-TSHIRT-BASE",
category.id
);
// 3. Create variant attributes (optional but recommended)
await variantAttributeService.createVariantAttribute("Size");
await variantAttributeService.createVariantAttribute("Color");
// 4. Create multiple variants
const variants = [
{ size: "S", color: "Red", sku: "SKU-TSHIRT-S-RED" },
{ size: "M", color: "Red", sku: "SKU-TSHIRT-M-RED" },
{ size: "L", color: "Red", sku: "SKU-TSHIRT-L-RED" },
{ size: "S", color: "Blue", sku: "SKU-TSHIRT-S-BLUE" },
{ size: "M", color: "Blue", sku: "SKU-TSHIRT-M-BLUE" },
{ size: "L", color: "Blue", sku: "SKU-TSHIRT-L-BLUE" },
];
for (const variant of variants) {
await productVariantService.createProductVariant(product.id, variant.sku, {
Size: variant.size,
Color: variant.color,
});
}
// 5. Get all variants for the product
const allVariants = await productVariantService.getVariantsByProduct(product.id);
console.log(`Created ${allVariants.length} variants`);
// 6. Find specific variant by attributes
const redLarge = await productVariantService.findVariantByAttributes(
product.id,
{ Size: "L", Color: "Red" }
);
if (redLarge) {
console.log(`Found: ${redLarge.sku} - ${redLarge.getDisplayName()}`);
}
// 7. Update a variant
await productVariantService.updateProductVariant(redLarge!.id, {
attributeValues: { Size: "XL", Color: "Red" },
});
// 8. Deactivate a variant
await productVariantService.deactivateProductVariant(redLarge!.id);Best Practices
Important guidelines for working with product variants
1. Create Products Before Variants
Variants require an existing product. Always create the product first:
// Good: Create product first
const product = await productService.createProduct("T-Shirt", "SKU-001", category.id);
const variant = await productVariantService.createProductVariant(
product.id,
"SKU-001-L",
{ Size: "L" }
);
// Bad: This will fail
const variant = await productVariantService.createProductVariant(
"non-existent-product-id",
"SKU-001-L",
{ Size: "L" }
);2. Unique SKUs and Attribute Combinations
Each variant must have a unique SKU globally, and unique attribute values per product:
// Good: Different SKUs
await productVariantService.createProductVariant(product.id, "SKU-001-L", { Size: "L" });
await productVariantService.createProductVariant(product.id, "SKU-001-M", { Size: "M" });
// Bad: Duplicate SKU
await productVariantService.createProductVariant(product.id, "SKU-001-L", { Size: "L" });
await productVariantService.createProductVariant(product.id, "SKU-001-L", { Size: "M" }); // Error!
// Bad: Same attributes for same product
await productVariantService.createProductVariant(product.id, "SKU-001-L", { Size: "L" });
await productVariantService.createProductVariant(product.id, "SKU-002-L", { Size: "L" }); // Error!3. Use Variant Attributes for Consistency
Create variant attributes first to ensure consistent naming:
// Create attributes first
await variantAttributeService.createVariantAttribute("Size");
await variantAttributeService.createVariantAttribute("Color");
// Then use them consistently in variants
await productVariantService.createProductVariant(product.id, "SKU-001", {
Size: "L", // Matches attribute name
Color: "Red", // Matches attribute name
});4. Use getDisplayName() for User-Facing Labels
The getDisplayName() method provides a formatted string for displaying variants:
const variant = await productVariantService.getProductVariantById(variantId);
// Display in UI
console.log(`${product.name} - ${variant.getDisplayName()}`);
// Output: "T-Shirt - Size: L, Color: Red"5. Deactivate Instead of Delete When Possible
Use deactivation to hide variants temporarily instead of deleting them permanently:
// Good: Deactivate for temporary hiding
await productVariantService.deactivateProductVariant(variantId);
// Can be reactivated later
// Warning: Use delete only when permanently removing
await productVariantService.deleteProductVariant(variantId);
// Cannot be undone