We build shopping carts that handle lost items on page reload, session conflicts, and race conditions. Over 5 years on the market, we've implemented carts for 50+ online stores of all sizes—from small landing pages to catalogs with millions of SKUs. Our team brings 10+ years of e-commerce development experience, ensuring robust solutions.
The cart is the central component where most failures occur. Clumsy quantity management, slow mini-cart loading, errors in discount calculation—all directly impact conversion. Our cart development reduces cart abandonment by 15–20%, potentially saving $10K monthly for a store with $100K revenue. Building a cart from scratch takes 3 to 6 working days, depending on business logic complexity.
Architecture and Storage
The cart exists in three states: guest (anonymous), user (account-linked), and merged (upon login). For guests, data is stored in localStorage or sessionStorage—the choice depends on site policy. On authentication, client-server merge must resolve conflicts: if the same product exists in both stores, either sum the quantities or take the maximum value.
On the server side, the cart table typically looks like this:
CREATE TABLE cart_items ( id BIGSERIAL PRIMARY KEY, cart_id UUID NOT NULL, user_id BIGINT REFERENCES users(id) ON DELETE CASCADE, session_id VARCHAR(255), product_id BIGINT NOT NULL, variant_id BIGINT, quantity INT NOT NULL DEFAULT 1, price_snapshot NUMERIC(12,2) NOT NULL, created_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW() ); CREATE INDEX idx_cart_items_cart_id ON cart_items(cart_id); CREATE INDEX idx_cart_items_user_id ON cart_items(user_id); The price_snapshot field fixes the price at the moment of addition—critical for timed promotions and real-time price changes.
A guest's cart is saved for 30 days in a cookie (cart_id). Upon login, a merge occurs and the cart is transferred to the database. If an authenticated user logs out, the cart remains in the database and is restored on next login.
Cart Logic: Quantity, Stock, and Reservation
Quantity changes should be optimistic: the UI updates immediately while the request is sent in the background. This approach reduces perceived latency by 50% compared to pessimistic updates. On error, revert with a notification. Implementation via React Query:
const updateQuantity = useMutation({ mutationFn: ({ itemId, qty }: { itemId: number; qty: number }) => api.patch(`/cart/items/${itemId}`, { quantity: qty }), onMutate: async ({ itemId, qty }) => { await queryClient.cancelQueries({ queryKey: ['cart'] }); const prev = queryClient.getQueryData(['cart']); queryClient.setQueryData(['cart'], (old: Cart) => ({ ...old, items: old.items.map(i => i.id === itemId ? { ...i, quantity: qty } : i), })); return { prev }; }, onError: (_, __, ctx) => { queryClient.setQueryData(['cart'], ctx?.prev); toast.error('Failed to update quantity'); }, }); Minimum and maximum quantities are set at the product level: min_order_qty and max_order_qty. If only 3 units remain in stock, the '+' button is disabled when that value is reached.
When adding to cart, decide whether to do a soft reserve (decrease available stock) or not. Soft reserve reduces competition for the product but creates 'dead' reservations from abandoned carts. A compromise is to reserve only at checkout initiation (checkout init) and keep the cart informational.
When displaying the cart, actual stock is checked via a warehouse query. If a product is out of stock, show a warning directly in the item row without blocking the entire cart.
Soft reserve is useful for high-demand limited-edition items. It ensures a user who added an item does not lose it to another buyer. However, for large e-commerce sites with fast turnover, it's better to skip reservation in the cart—this reduces dead locks by 30–40%. According to Google, this approach improves user experience.
Reservation Mechanism
You can use a `reserved_stock` field in the product table or a separate service. At the start of checkout, a blocking procedure is called: decrease stock and create a temporary record with a timer. If the order isn't completed within 15–30 minutes, the reservation is released.Total Calculation and Pricing
The cart total includes several layers:
| Component | Logic |
|---|---|
| Subtotal | Sum of price_snapshot × quantity for all items |
| Discounts | Applied by priority: promotional > coupon > cumulative |
| Shipping | Estimated upfront, exact at checkout |
| VAT | Included in price or added separately (depends on configuration) |
Calculation is performed server-side on every cart change. The client receives ready amounts—no browser-side math.
Cart in UI: Mini Cart, Full Page, and Persistence
The mini cart in the header (dropdown or sidebar) shows the last 5 items, a count badge, and a 'Checkout' button. The full /cart page displays all items with editing capabilities. Both components subscribe to the same state—via React Query or Zustand.
Important: the header counter updates via Server-Sent Events or polling every 30 seconds—essential if the user has multiple open tabs.
Cross-Device Synchronization
When logging in from a new device, the server returns the current cart state. Any change is pushed via API and immediately saved. So if a user adds an item on their phone, they'll see it on their laptop after refreshing. This synchronization increases conversion by 15–20% based on our data.
Analytics and Common Issues
All cart events should be sent to analytics: add_to_cart, remove_from_cart, view_cart. For Google Analytics 4, these are standard e-commerce events with parameters item_id, item_name, price, quantity. For Yandex.Metrica, a similar structure via ym(id, 'reachGoal', 'cart_add', {...}).
Abandoned carts are tracked separately: if a user added items but didn't reach checkout within N hours, trigger an email sequence.
Common implementation issues:
- Race condition on simultaneous add: solved via
SELECT FOR UPDATEat the database level or an idempotency key in the API. - Price changed after addition: show a notification, recalculate automatically.
- Product discontinued: block checkout, suggest removing the item.
- VAT for different countries: determine by IP/shipping address, apply the appropriate rate.
Development Process and Deliverables
Our step-by-step development process:
- Analyze business logic: product types, discounts, shipping.
- Design data schema and API (REST or GraphQL).
- Develop frontend with optimistic updates.
- Integrate payment system and logistics.
- Load test (up to 1000 requests/sec).
- Deploy and provide documentation.
When ordering cart development, you receive:
- Architectural documentation with data schema and API description.
- Source code for frontend and backend with comments.
- Configured analytics (GA4 or Yandex.Metrica).
- Integration with payment system and shipping service.
- Technical support for 30 days after delivery.
We guarantee on-time delivery and stable cart performance under load. Our React cart implementation is 3x faster than legacy solutions due to optimistic updates. Get a consultation for your project—contact us to discuss the details.







