Index: database/drizzle/queries/builds.ts
===================================================================
--- database/drizzle/queries/builds.ts	(revision b0685a8a59fe7808efb0fea93b4fdaad4d6b44d9)
+++ database/drizzle/queries/builds.ts	(revision e03e6fbabb22b34ee8ba0221488b003cb9d13bb2)
@@ -200,5 +200,6 @@
             .select({
                 componentId: buildComponentsTable.componentId,
-                component: componentsTable
+                component: componentsTable,
+                quantity: buildComponentsTable.numComponents
             })
             .from(buildComponentsTable)
@@ -292,5 +293,8 @@
         return {
             ...buildDetails,
-            components: components.map(c => c.component),
+            components: components.map(c => ({
+                    ...c.component,
+                    quantity: c.quantity
+            })),
             reviews: reviews.map(r => ({
                 username: r.username,
@@ -419,5 +423,8 @@
 
         const existing = await tx
-            .select({ componentId: buildComponentsTable.componentId })
+            .select({
+                componentId: buildComponentsTable.componentId,
+                numComponents: buildComponentsTable.numComponents
+            })
             .from(buildComponentsTable)
             .where(eq(buildComponentsTable.buildId, buildId));
@@ -428,4 +435,5 @@
                     buildId: newBuild.id,
                     componentId: r.componentId,
+                    numComponents: r.numComponents
                 })),
             );
@@ -545,5 +553,6 @@
         const components = await tx
             .select({
-                componentId: buildComponentsTable.componentId
+                componentId: buildComponentsTable.componentId,
+                quantity: buildComponentsTable.numComponents
             })
             .from(buildComponentsTable)
@@ -554,5 +563,8 @@
         return {
             build,
-            componentIds: components.map(c => c.componentId)
+            components: components.map(c => ({
+                id: c.componentId,
+                quantity: c.quantity
+            }))
         };
     });
Index: database/drizzle/queries/components.ts
===================================================================
--- database/drizzle/queries/components.ts	(revision b0685a8a59fe7808efb0fea93b4fdaad4d6b44d9)
+++ database/drizzle/queries/components.ts	(revision e03e6fbabb22b34ee8ba0221488b003cb9d13bb2)
@@ -196,4 +196,5 @@
             id: componentsTable.id,
             type: componentsTable.type,
+            quantity: buildComponentsTable.numComponents
         })
         .from(buildComponentsTable)
@@ -231,4 +232,5 @@
         componentsDetails.push({
             ...comp,
+            quantity: comp.quantity,
             details: details
         });
@@ -256,6 +258,4 @@
 
     if(!existingComponents) return null;
-
-
 
     const existing = {
@@ -278,9 +278,12 @@
         ...existing.networkAdapters,
         ...existing.soundCards
-    ].filter(Boolean).length;
+    ].reduce((sum: number, c: any) => {
+        if (!c) return sum;
+        return sum + (c.quantity || 1);
+    }, 0);
 
     const existingTDP = existingComponents.reduce((sum, c) => {
         const tdp = c.details?.tdp ? Number(c.details.tdp) : 0;
-        return sum + tdp;
+        return sum + (tdp * (c.quantity || 1));
     }, 0);
 
@@ -456,8 +459,8 @@
         if (existing.memory.length > 0) {
             const totalModules = existing.memory.reduce((sum: number, m: any) =>
-                sum + Number(m.details.modules), 0
+                sum + (Number(m.details.modules) * m.quantity), 0
             );
             const totalCapacity = existing.memory.reduce((sum: number, m: any) =>
-                sum + Number(m.details.capacity), 0
+                sum + (Number(m.details.capacity) * m.quantity), 0
             );
 
@@ -704,7 +707,7 @@
             if (!caseStorageFormFactor) return false;
 
-            const usedSlots = existing.storage.filter(
-                (s: any) => s.details.formFactor === stor.formFactor
-            ).length;
+            const usedSlots = existing.storage
+                .filter((s: any) => s.details.formFactor === stor.formFactor)
+                .reduce((sum: number, s: any) => sum + s.quantity, 0);
 
             return usedSlots < Number(caseStorageFormFactor.numSlots);
@@ -821,7 +824,7 @@
                 if (!storageFF) return false;
 
-                const usedSlots = existing.storage.filter(
-                    (s: any) => s.details.formFactor === stor.details.formFactor
-                ).length;
+                const usedSlots = existing.storage
+                    .filter((s: any) => s.details.formFactor === stor.details.formFactor)
+                    .reduce((sum: number, s: any) => sum + s.quantity, 0);;
 
                 return usedSlots <= Number(storageFF.numSlots);
@@ -963,5 +966,12 @@
             .values({
                 buildId,
-                componentId
+                componentId,
+                numComponents: 1
+            })
+            .onConflictDoUpdate({
+                target: [buildComponentsTable.buildId, buildComponentsTable.componentId],
+                set: {
+                    numComponents: sql`${buildComponentsTable.numComponents} + 1`
+                }
             });
 
@@ -969,4 +979,5 @@
             .select({
                 price:  componentsTable.price,
+                quantity: buildComponentsTable.numComponents
             })
             .from(buildComponentsTable)
@@ -979,5 +990,7 @@
             );
 
-        const totalPrice = buildComponents.reduce((sum, c) => sum + Number(c.price), 0);
+        const totalPrice = buildComponents.reduce((sum, c) =>
+            sum + (Number(c.price) * c.quantity), 0
+        );
 
         await tx
@@ -1009,6 +1022,9 @@
         if(!build || build.isApproved) return null;
 
-        const result = await tx
-            .delete(buildComponentsTable)
+        const [existing] = await tx
+            .select({
+                quantity: buildComponentsTable.numComponents
+            })
+            .from(buildComponentsTable)
             .where(
                 and(
@@ -1016,11 +1032,36 @@
                     eq(buildComponentsTable.componentId, componentId)
                 )
-            );
-
-        if(result.rowCount === 0) return null;
+            )
+            .limit(1);
+
+        if (!existing) return null;
+
+        if (existing.quantity > 1) {
+            await tx
+                .update(buildComponentsTable)
+                .set({
+                    numComponents: sql`${buildComponentsTable.numComponents} - 1`
+                })
+                .where(
+                    and(
+                        eq(buildComponentsTable.buildId, buildId),
+                        eq(buildComponentsTable.componentId, componentId)
+                    )
+                );
+        } else {
+            await tx
+                .delete(buildComponentsTable)
+                .where(
+                    and(
+                        eq(buildComponentsTable.buildId, buildId),
+                        eq(buildComponentsTable.componentId, componentId)
+                    )
+                );
+        }
 
         const buildComponents = await tx
             .select({
                 price:  componentsTable.price,
+                quantity: buildComponentsTable.numComponents
             })
             .from(buildComponentsTable)
@@ -1033,5 +1074,7 @@
             );
 
-        const totalPrice = buildComponents.reduce((sum, c) => sum + Number(c.price), 0);
+        const totalPrice = buildComponents.reduce((sum, c) =>
+            sum + (Number(c.price) * c.quantity), 0
+        );
 
         await tx
@@ -1044,5 +1087,5 @@
             );
 
-        return result;
+        return componentId;
     })
 }
