How to build a grocery delivery app in 2026: Architecture, features, and what actually ships
What Matters
- -Grocery delivery has 5 separate surfaces to build - customer app, shopper app, driver app, vendor dashboard, admin panel. Most teams scope only the customer app.
- -Real-time inventory sync is the hardest engineering problem - it requires a two-way integration with the store's POS or inventory system.
- -Substitution logic must be designed before catalog data modeling - it changes your data schema significantly.
- -Build the data pipeline from day one even if you don't use AI features yet - 6 months of order data is what makes AI features actually work.
- -The shopper/picker workflow is what separates apps with 95% fill rates from apps with 70% fill rates.
Grocery delivery looks like a food delivery app with a bigger menu. It isn't. The product catalog is 100x larger. The inventory changes by the minute. A third of items can be substituted for something else. The shopper picking your order needs a different app than the driver delivering it.
Every quick commerce company that burned through VC money without surviving found the same set of problems: real-time inventory sync is hard, substitution logic is underestimated, and the shopper workflow is the production bottleneck nobody planned for.
This guide covers what it actually takes to build a grocery delivery app that ships to production and handles real order volume.
The 5 systems you're actually building
Before writing a line of code, understand that you're building 5 distinct products:
- Customer App - browse, search, cart, checkout, real-time tracking, substitution approval
- Shopper/Picker App - optimized pick list, substitution handling, handoff workflow
- Driver App - order assignment, routing, multi-drop optimization, proof of delivery
- Vendor/Store Dashboard - order queue, inventory management, slot management
- Admin Panel - analytics, promotions, zone management, financial reporting
Most initial scopes include only the customer app. Teams discover the shopper and driver apps are required at first operations day.
Architecture overview
Here's the high-level architecture for a production grocery delivery app:
Customer App (React Native) ←→ API Gateway ←→ Order Service
Shopper App (React Native) ←→ API Gateway ←→ Inventory Service
Driver App (React Native) ←→ API Gateway ←→ Dispatch Service
Web Dashboard ←→ API Gateway ←→ Analytics Service
↓
PostgreSQL (orders, users, catalog)
Redis (inventory cache, sessions)
Elasticsearch (catalog search)
S3 (images, reports)
The inventory service is the critical path. Everything else depends on knowing what's in stock.
Step 1: Data model design
Your data model decisions in week 1 determine how hard everything else is. Here's what most teams get wrong.
Product catalog schema
A grocery catalog isn't just name + price + image. You need:
Product
- id, sku, barcode
- name, description, brand
- category_id (nested: Produce > Fresh Vegetables > Leafy Greens)
- weight, unit_of_measure
- images[] (multiple angles, front of pack, nutrition label)
- allergens[], dietary_tags[]
- substitution_group_id ← most teams forget this
- price_by_weight: boolean ← critical for produce
- age_restricted: boolean ← alcohol, tobacco
- storage_temperature ← frozen, chilled, ambient
The substitution_group_id links products that can replace each other. Design this from day 1. Retrofitting substitution relationships into an existing catalog takes 3-6 weeks.
For price-by-weight items (loose produce, deli counter items), your cart needs to handle approximate quantities and adjust final prices at checkout. This alone adds 1-2 weeks of development.
Inventory schema
Inventory
- store_id
- product_id
- quantity_on_hand
- quantity_reserved ← items in active orders
- last_synced_at
- sync_source: enum (api, webhook, manual, scanner)
The quantity_reserved field is critical. When a customer adds an item to cart, reserve it. When they abandon cart, release it. This prevents overselling when 5 customers are ordering the last 3 avocados simultaneously.
Order schema
Orders in grocery delivery have more states than food delivery:
Order States:
placed → confirmed → picker_assigned → picking → ready_for_pickup
→ driver_assigned → in_transit → delivered
Possible exits: cancelled, partially_fulfilled, substitutions_pending
The substitutions_pending state is unique to grocery. The order can't be dispatched until the customer approves or rejects substitutions. Your dispatch system needs to hold orders in this state and notify customers.
Step 2: Catalog ingestion
How you get product data depends on who you're partnering with.
Scenario a: Partnering with an existing retailer
The retailer has a catalog. It's probably in one of these formats: product feed CSV (exported weekly), POS system API, or a category management system like Salsify or Syndigo.
Common problems you'll hit:
- Inconsistent category hierarchies across departments
- Missing images for 20-40% of SKUs
- No substitution relationships defined
- Prices in different formats across departments
Budget 2-4 weeks for catalog normalization. This is unglamorous but critical.
Scenario b: Running your own dark store
You control the inventory, which simplifies things enormously. You still need to input the catalog, but you define the data model from scratch. This is why dark store operators can move faster on the tech side.
Use a barcode scanner app for initial catalog creation. Staff scan products, enter prices and weights, snap photos. For 3,000-5,000 SKUs, this takes a team of 4 people about 2 weeks.
Catalog search
Use Elasticsearch or Algolia for product search. PostgreSQL full-text search works at small scale but degrades badly as the catalog grows and search patterns become complex (typo tolerance, synonym handling, "orange juice" vs "OJ").
Configure search to weight by: in-stock status (out-of-stock items ranked lower), purchase history (personalized ranking), relevance score, and margin (higher margin products get a small boost).
Step 3: Real-time inventory sync
This is where most grocery apps fail in production. A customer adds bananas to their cart. The bananas are actually out of stock. The order fails at the picker step. The customer is unhappy.
The fix is a real-time inventory sync system. Here's how to build it.
Integration options (best to worst)
Webhook push (best): The store's inventory system sends a webhook when any item's quantity changes. Your inventory service receives it, updates the quantity, clears the cache. Latency under 1 second.
Polling (acceptable): Your system calls the store's inventory API every 2-5 minutes and syncs changes. Works fine for stores with slower inventory turnover. Not suitable for fast-moving items in high-volume stores.
Daily file import (last resort): The store exports a CSV every night. Inventory is accurate at midnight and increasingly wrong throughout the day. Only use this if no API is available - and warn customers that inventory may be approximate.
Inventory cache layer
Raw inventory queries on every product page load will kill your database. Use Redis:
inventory:{store_id}:{product_id} = quantity_on_hand
TTL = sync_interval * 2
On cart add:
- Check Redis
- If quantity < requested: show "limited stock" warning
- If quantity = 0: show "out of stock"
- Reserve quantity: DECRBY inventory:{store_id}:{product_id} requested_qty
On cart abandon (30 min TTL):
- Release reservation: INCRBY inventory:{store_id}:{product_id} reserved_qty
Handling inventory discrepancies
Even with real-time sync, the picker will find items that are actually gone. Your shopper app needs to handle this gracefully:
- Picker marks item as unavailable
- System checks substitution group for alternatives
- Shopper sees ranked substitutes with stock levels
- Customer gets a push notification with substitution options
- Customer has 10 minutes to approve/reject before order proceeds
- After 10 minutes, default behavior applies (skip item, apply substitution, or call customer)
The timeout and default behavior is a business decision, not a technical one. Define it before you build.
Step 4: The shopper app
The shopper app is the production constraint most teams underestimate. A good shopper app doubles pick efficiency. A bad one creates a customer service crisis every shift.
Pick list optimization
Don't show pickers a list of items in the order they were added to the cart. That's random. Sort by aisle location.
To do this, you need a store map: which products are in which aisle, in what sequence. This sounds simple. Getting it is not - most stores don't have this data in a format you can use.
Options:
- Manual data entry (staff walk the store and record aisle positions for each SKU)
- Heuristic sorting (group by category, which correlates roughly with aisle layout)
- Machine learning (learn optimal sort order from picker behavior over time)
For an MVP, category-based sorting gets you 70% of the efficiency gain. Full aisle mapping gets you to 90%. Start with category sorting and add aisle mapping in v2.
Batch picking
As order volume grows, pickers will pick multiple orders simultaneously (batch picking). This reduces walking distance by 30-50% and dramatically improves throughput.
Batch picking requires:
- Algorithm to group orders by overlapping items and proximity
- Pick list view that groups by aisle, not by order
- Tote/bag assignment to keep orders separate while picking
- Handoff workflow that verifies each order before handoff to driver
Start with single-order picking. Add batching when your volume exceeds 30-40 orders per hour per picker - that's the threshold where batching ROI becomes clear.
Exception handling
The shopper app's most important screen is the exception screen. Teach it early:
- Item not found (wrong location, not on shelf)
- Item damaged (show substitution flow)
- Quantity unavailable (partial fill + substitution)
- Picker can't identify item (scan barcode, show image)
Every unhandled exception becomes a customer service call. Build solid exception flows and you cut CS volume by 40%.
Step 5: Driver dispatch and routing
Dispatch logic
Grocery delivery dispatch has one key difference from food delivery: bag/tote management. A driver picks up 3-4 grocery orders. They're in labeled totes. The dispatch system needs to know which totes go to which driver and which addresses.
Start simple:
- Orders ready for pickup appear in a queue
- Dispatcher assigns to available driver (manual or auto)
- Driver gets address list sorted by route efficiency
- Driver confirms each delivery with customer signature or photo
Routing
For sub-30-minute delivery (quick commerce), routing must run in real-time as orders complete. Use Google Maps Routes API or Mapbox Optimization API - don't build your own routing engine.
Key routing parameters for grocery:
- Max time window per order (30 min from store)
- Max orders per batch (3-4 bags fit in a car)
- Temperature sensitivity (frozen items need priority delivery)
- Customer time windows (scheduled deliveries)
For standard grocery delivery (1-2 hour windows), routing is easier. Calculate routes every 15-20 minutes with the current batch of ready orders.
Step 6: Payments and compliance
Payment flow
Grocery payments have a specific challenge: the final charge is often different from the estimated charge. Produce is sold by weight (actual weight differs from estimate). Substitutions change prices. Items get removed.
Use a two-step payment flow:
- Authorization hold at checkout (for estimated total + 10% buffer)
- Capture for actual total at order completion
Stripe handles this well with payment intents. The capture step happens after the picker completes the order and actual quantities/substitutions are confirmed.
Age-restricted items
If you're selling alcohol, you need:
- Age verification at checkout (DOB entry, or ID scan via third-party service like AgeID)
- Driver confirmation at delivery (ID check on delivery)
- Geofencing (verify delivery address is in a jurisdiction where delivery is legal)
This is a legal requirement, not a nice-to-have. Build it before you sell your first bottle.
Tech stack recommendations
Mobile apps (customer, shopper, driver): React Native - single codebase for iOS and Android reduces cost significantly. Use Expo for faster development, eject to bare workflow when you need native modules.
Backend API: Node.js (Express or Fastify) or Python (FastAPI). Go for the inventory service if you need high concurrency.
Database: PostgreSQL for orders and catalog. Redis for inventory cache and sessions. Elasticsearch for product search.
Real-time updates: Socket.io or Firebase Realtime Database for order tracking. Push notifications via Firebase Cloud Messaging.
Maps: Google Maps Platform. Budget $500-2,000/month at scale. Mapbox is cheaper but has less coverage in developing markets.
Payments: Stripe. Handles international payments, fraud detection, and the authorization/capture flow.
Hosting: AWS or GCP. Use ECS or Cloud Run for the application layer (auto-scaling). RDS for PostgreSQL. ElastiCache for Redis.
Build phases for an MVP
Phase 1: Core ordering (weeks 1-10)
- Customer app: catalog browse, search, cart, checkout, order tracking
- Vendor dashboard: order queue, manual inventory update
- Basic driver app: order view, confirm delivery
- Stripe payments (no authorization hold yet, simplified for MVP)
Ship this when you have a store partner and want to prove demand. Don't overthink it.
Phase 2: Operational reliability (weeks 11-22)
- Real-time inventory sync (webhook or polling integration)
- Shopper app with pick list and exception handling
- Substitution flow (catalog relationships, customer approval push)
- Authorization hold payment flow
- Automated dispatch (rule-based, not ML yet)
- Route optimization integration
This is the phase that makes you operationally viable. Don't scale marketing spend until this is live.
Phase 3: Scale (weeks 23+)
- Batch picking in shopper app
- ML-powered substitution suggestions
- AI demand forecasting for inventory management
- Promotional engine (discounts, bundles)
- Analytics dashboard (fill rate, substitution rate, picker efficiency)
Common mistakes that kill grocery apps
Building the customer app and skipping the shopper app: Manual picking with no picker app works at 20 orders/day. At 100 orders/day, you have full-time staff managing chaos. Build the picker app in Phase 1 or plan Phase 2 carefully.
Launching without a substitution strategy: "We'll handle it manually" is not a strategy. Manual substitution handling at 50+ orders/day overwhelms your team. Define the substitution rules and build the flow.
Ignoring the catalog data problem: "We'll get the data from the store" assumes the store has clean, structured data. Most don't. Build a catalog data pipeline and allocate time for normalization.
Underestimating the integration work: POS integrations are time-consuming and often delayed. Plan for 4-8 weeks of integration work per store partner. Have fallback options (manual inventory update) when the integration takes longer.
Skipping monitoring: At scale, you need real-time visibility into fill rates, substitution rates, picker times, and delivery times. Build operational dashboards from day one. Blind scaling leads to quality problems that are hard to diagnose.
Building a grocery delivery app is a 5-6 month project if you do it right. The teams that succeed move in phases, solve the inventory problem early, and don't underestimate the operational complexity of the shopper workflow.
At 1Raft, we've built food and grocery delivery apps from single-store MVPs to enterprise platforms. We scope every build in a free 30-minute call. If you're planning a grocery delivery app, we can tell you exactly what Phase 1 looks like and where the hidden complexity lives.
See also: Grocery Delivery App Development Cost for a full cost breakdown by feature set.
Related Articles
Grocery Delivery App Development Cost
Read articleFood Delivery App Development Cost
Read articleHow to Build a Food Delivery App
Read articleAI Agents for Ecommerce
Read articleFurther Reading
Related posts

How to build a food delivery app: The complete technical guide
A food delivery app is actually 3 apps -- customer, restaurant, and driver. Here's how they work together, what each costs to build, and where most projects go wrong.

How to build an app like Wise: Cross-border payments architecture explained
Wise moved $118 billion in 2024 on a simple promise - show the real exchange rate and charge a transparent fee. The engineering behind that promise is anything but simple. Here's what it takes to build a cross-border payment app.

React Native vs Flutter vs Native: How to choose
React Native, Flutter, or native? The wrong choice costs 6 months and a rewrite. Here's the comparison - benchmarks, costs, and when each one wins.