#User cart in convex vs client side state

1 messages · Page 1 of 1 (latest)

keen cliff
#

I am wondering how should I implement cart in my e-commerce web app - using client side state, or keep the cart in convex? What is the good practice

rose scarabBOT
#

Hi @keen cliff. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

For an e-commerce web app, it is considered best practice to keep the shopping cart in Convex (i.e., server-side), rather than solely in client-side state.

Why?

  • Consistency and Reactivity: Convex ensures that your app always displays a consistent view of the data. For example, if you have a product listing showing stock and a cart showing items, Convex will keep both in sync. When a user adds an item to the cart, the mutation runs in a transaction, and all relevant queries (stock, cart contents) are invalidated and rerun. The results are pushed to the client in real time, so you never have a moment where the numbers don't add up or the UI is out of sync with the backend state. This is difficult to guarantee with only client-side state management, especially in collaborative or multi-tab scenarios Convex Overview: Beyond reactivity.

  • Persistence and Multi-Device Support: Storing the cart in Convex means the cart persists across sessions, devices, and browser tabs. If you only use client-side state (like React's useState), the cart is ephemeral and will be lost on refresh, navigation, or if the user switches devices Use real persistence, not useState.

  • Collaboration and Multi-Tab Use: Convex enables real-time updates across multiple tabs or users. For example, a user can have two tabs open with different carts, or multiple users can interact with the same cart, and Convex will keep everything in sync Session Tracking Via Parameter Injection.

#
  • Automatic Caching and Performance: Convex automatically caches query results and updates them when the underlying data changes, reducing the need for manual state management and improving performance Realtime.

Client-side state (e.g., useState) is still useful for ephemeral UI state, such as the value of an input field before adding an item to the cart, but not for the cart itself if you want persistence, consistency, and collaboration.

Summary:
Keep your cart in Convex for persistence, consistency, and real-time updates. Use client-side state only for temporary, local UI state.

“With Convex, most of the time, you won't end up needing [a local cache or state aggregation layer]. More often than not, you can bind your components to Convex functions in pretty simple ways and things will Just Work and be plenty fast.”
The Zen of Convex


Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@keen cliff Kapa.ai is still learning and improving, please let me know how I did by reacting below.

keen cliff
#

@rose scarab What is the common flow for keeping the stock in sync with user orders as well as keeping the UI and carts in sync with stock

rose scarabBOT
#

Let me check the knowledge base for you again. One moment! :books:

#

The common flow for keeping stock in sync with user orders—and ensuring the UI and carts are always consistent with stock—in Convex is as follows:

  1. Cart and Stock State in Convex:
    Both the cart and the stock inventory are stored in Convex. When a user adds an item to their cart, a mutation function (e.g., addCart) is called. This mutation runs as a transaction, atomically updating both the cart and the stock count in the database.

  2. Transactional Consistency:
    Convex ensures that all reads and writes in a mutation are grouped into a single serializable transaction. This means that race conditions (e.g., two users trying to buy the last item at the same time) are prevented. Only one transaction will succeed in decrementing the stock, and the other will receive an error if the item is out of stock How Convex Works: Transactions.

  3. Reactive Queries and Subscriptions:
    The UI uses reactive queries (e.g., useQuery) to subscribe to both the cart and the stock data. When the underlying data changes (such as after a successful order), Convex automatically re-runs the affected queries and pushes the updated results to all subscribed clients in real time. This ensures that the UI always reflects the latest state of both the cart and the stock, with no manual refresh or polling required Realtime, How Convex Works: Subscriptions.

#
  1. Consistent UI Updates:
    Convex’s client libraries ensure that all relevant UI components are updated in a single pass, so there’s never a moment where, for example, the cart shows an item that is no longer in stock, or the stock count is out of sync with the cart Convex Overview: Beyond reactivity, Sync: Robust conflict and consistency handling.

Example Flow:

  • User clicks "Add to Cart."
  • The addCart mutation checks stock and updates both the cart and stock in a transaction.
  • If successful, Convex invalidates and re-runs the relevant queries (cart and stock).
  • The UI receives updated data via subscriptions and re-renders, showing the new cart contents and updated stock count instantly and consistently for all users.

This architecture eliminates common bugs like stale UI, double-selling, or inconsistent cart/stock state, and requires no manual sync logic from the developer.

For a concrete example, see the Swaghaus sample app and the code snippets in the knowledge sources Convex at rest, How Convex Works: Subscriptions.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@keen cliff Kapa.ai is still learning and improving, please let me know how I did by reacting below.

keen cliff
#

@rose scarab the problem is, what if somebody adds some items to the cart but then abandons it. A logic needs to be added to empty the cart after some time I guess?

rose scarabBOT
#

Let me check the knowledge base for you again. One moment! :books:

#

You're correct—if users add items to their cart but abandon it, you may want to implement logic to automatically empty or expire abandoned carts after a certain period. This prevents stock from being held indefinitely by inactive users.

How to handle abandoned carts in Convex:

  • Use a Cron Job:
    Convex supports cron jobs that can run periodic cleanup tasks. You can set up a cron job to regularly scan for carts that haven't been updated in a certain amount of time (e.g., 1 hour, 24 hours) and remove or reset them. This is similar to how waitlists and other session-based features are managed in Convex, where a cron job periodically checks for stale sessions and cleans them up Waitlist: How does it work?, Shop Talk: Cron jobs.

  • Track Last Activity:
    Store a lastActive or updatedAt timestamp on each cart. Update this timestamp whenever the user interacts with their cart. The cron job can then identify and clear carts that haven't been active for your chosen timeout period.

  • Example Pattern:
    This pattern is used in Convex waitlist implementations, where a cron job deletes stale sessions based on a lastActive timestamp Waitlist: How does it work?.

#

Summary:
Yes, you should add logic to clear abandoned carts, and the recommended approach in Convex is to use a cron job that periodically removes carts that have not been updated within a certain timeframe. This keeps your stock available for active users and prevents abandoned carts from holding inventory.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@keen cliff Kapa.ai is still learning and improving, please let me know how I did by reacting below.

keen cliff
#

@rose scarab I imagine this becomes problematic for items with limited stock. One user can easily block other users

rose scarabBOT
#

Let me check the knowledge base for you again. One moment! :books:

#

You're absolutely right—when items have limited stock, allowing users to add items to their cart and "hold" them indefinitely can block other users from purchasing those items. This is a well-known challenge in e-commerce systems.

The knowledge sources discuss this issue in the context of waitlists and session management. For example, the Convex waitlist implementation uses a lastActive timestamp and a cron job to periodically remove stale sessions, ensuring that resources (like access slots) are not held by inactive users. This same pattern can be applied to carts: by tracking activity and expiring abandoned carts, you can prevent users from blocking stock indefinitely Waitlist: How does it work?.

However, the knowledge sources do not provide a built-in or automatic solution for this specific cart-blocking problem with limited stock. They suggest that you need to implement logic (such as a cron job to clear abandoned carts) to mitigate this issue. Without such logic, yes, a user could block others from purchasing limited-stock items by simply adding them to their cart and leaving them there.

In summary:
Yes, this is a potential problem, and you should implement cart expiration logic (e.g., via cron jobs and activity tracking) to avoid users blocking limited stock. The knowledge sources confirm the pattern but do not describe a built-in solution for carts specifically.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: