Online store scaling
Online store scaling and launch checklist
An online store stays fast by paginating every list, indexing the main questions, and deferring heavy work until a measured trigger fires. At launch, apply 6 rules, watch 7 signals and hold the performance targets below.
Last checked
Rules to apply at launch
- Idempotency: Stock reservation is a single conditional UPDATE (WHERE on_hand - reserved >= qty) whose rowCount decides success; no read-then-write; a CHECK constraint (reserved <= on_hand, on_hand >= 0) backs it; a concurrency test with N parallel buyers of the last unit must produce exactly one success.
- Caching: Catalog, collection and product pages are ISR/edge cached with stale-while-revalidate and tag revalidation on merchant edits; the cart, checkout and the availability badge are never cached; price shown in cached HTML is display-only and re-read at checkout.
- Caching: Flash-sale protection: product pages stay static, availability is one small uncached primary-key read, add-to-cart does not touch inventory, and only checkout contends on the inventory row (bounded by a per-IP and per-user checkout rate limit).
- Pagination: Collections, search, orders and admin tables use keyset pagination on an indexed (sort_key, id) cursor; page size 24 default, capped at 60; no OFFSET and no unbounded count(*).
- Search: Text search uses tsvector + GIN with trigram fallback; facets are bounded queries cached 60 s per filter combination; the dedicated search engine is deferred until the catalog crosses the stated trigger.
- Storage: Per-merchant media quota, max image dimensions and bytes, unreferenced uploads swept after 24 h.
Performance targets
| What to measure | Target |
|---|---|
| Collection and product page LCP | < 2.5 s on 4G mobile; TTFB < 200 ms from edge cache |
| Add to cart API | p95 < 150 ms, <= 3 queries, no inventory write |
| Inventory reserve under contention | p99 < 50 ms with 200 concurrent buyers on one variant, zero oversells |
| Search API | p95 < 250 ms at 100k products, facets cached |
| Image weight | hero image <= 150 KB, product grid image <= 40 KB at the displayed width |
What to watch
- Metric checkout funnel: cart -> checkout started -> payment session -> paid counts and drop-off, by device class.
- Metric oversell attempts and reservation expiry: failed reserves, expiries and committed counts per variant; any negative available stock is a bug.
- Metric payment success ratio: paid / payment sessions created, with failure reason breakdown.
- Log order and payment audit log: order id, idempotency key, state transition, actor; no card data, no full addresses.
- Trace checkout trace: one trace id across cart read, reserve, payment session and webhook completion.
- Slo checkout availability: 99.9% of checkout API requests succeed; 99% of paid payments reach status paid within 60 s.
- Alert email and media budget: email sends or media jobs above 80% of the daily cap.
Recurring work
- release_expired_reservations: runs cron 1m. Guard: claims active reservations past expires_at with SKIP LOCKED, status predicate makes each release happen exactly once, batch of 500, also cancels the stale pending_payment order.
- process_product_media: runs queue (jobs kind=media). Guard: magic-byte and pixel-count limits, resource-limited container, idempotent by object_key, daily cap per merchant.
- send_order_email: runs queue (jobs kind=email). Guard: dedupe_key = order:<id>:<template>, attempt cap 5, platform daily email cap, no PII in job logs.
- rollup_sales_daily: runs cron hourly. Guard: recompute today and yesterday only, upsert by day.
- recover_abandoned_carts: runs cron hourly. Guard: carts idle 1-24 h with an email and consent, at most one email per cart, global daily email cap.
- rebuild_collection_products: runs cron 15m + on product change. Guard: set-based insert/delete for automated collections, bounded per run.
Add when the numbers say so
- Read replicas: Send catalog, search and order-history reads to a read replica once primary CPU or read p95 crosses the trigger; checkout, inventory and payment paths always use the primary.
- Search: Adopt a dedicated search engine (OpenSearch/Typesense) for typo-tolerant faceted search once the catalog or query load crosses the trigger.
- Cdn: Edge-render the storefront from regional caches and add a regional read tier for global audiences.
Deferred until it is needed
| Deferred | Adopt it when |
|---|---|
| Dedicated search engine (OpenSearch/Typesense) | > 500k products or search p95 > 300 ms. |
| Read replicas for catalog and order history | primary CPU > 60% sustained or storefront read p95 > 200 ms. |
| Multi-location inventory and fulfilment routing | second warehouse or 3PL integration. |
| Subscriptions and B2B price lists | recurring-product or wholesale customer requirement. |
| Personalised recommendations (pgvector embeddings) | > 10k monthly buyers. |
On Forge64
Forge64 matches your description to one of 12 reference architectures, writes the plan and data model into the project, generates the app, and runs a quality gate over the code before you see it. Each app gets its own Postgres database and sign-in with no per-user fee. Hosting on Forge Cloud and Forge Payments are rolling out.
Every metered resource on Forge64 has a hard cap, so a traffic spike stops at your limit instead of becoming a surprise bill. This is a reference design for the category, not a promise that every item is generated today. Built-ins such as email, background jobs, file uploads and search are coming soon, so anything here that needs them is something you add yourself for now.
FAQ
- When should I worry about scale for an online store?
- Not before a measured trigger fires. For example, for "Dedicated search engine (OpenSearch/Typesense)": > 500k products or search p95 > 300 ms.
- What performance targets should an online store aim for?
- Collection and product page LCP: < 2.5 s on 4G mobile; TTFB < 200 ms from edge cache. Add to cart API: p95 < 150 ms, <= 3 queries, no inventory write. Inventory reserve under contention: p99 < 50 ms with 200 concurrent buyers on one variant, zero oversells.
- Does Forge64 cap my usage costs?
- Yes. Every metered resource has a hard cap, and paid plans add an overage spend cap that you set.
Build your app with Forge64
One prompt to a running app with auth, database, hosting and payments. Start free, no credit card required.
Start building for free