Commercio Docs

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.

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"

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");
}

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