/how-to-build-replit

How to Build a Shopping cart with Replit

Learn how to build a functional shopping cart using Replit. Follow this step-by-step guide to create, test, and deploy your online store easily.

Matt Graham, CEO of Rapid Developers

Book a call with an Expert

Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.

How to Build a Shopping cart with Replit

To build a simple yet functional shopping cart in Replit, create a small full-stack app using Node.js, Express, and a bit of frontend HTML/JavaScript. Replit automatically sets up Node for you if you pick the “Node.js” template. You’ll have a backend server (for handling cart and items) and frontend files (for displaying products and interacting with the cart). Start from your main index.js (or server.js) file, create a public folder for frontend files, and use Replit’s built-in web server preview to test it live. This approach works reliably in Replit — no complex setup, and it uses built-in Express serving and session logic properly.

 

Step 1: Set up your project structure in Replit

 

When you create a new Replit using the "Node.js" template, Replit gives you:

  • index.js: your server entry point file
  • package.json: manages dependencies
  • public/ folder: you’ll create this to hold your HTML, CSS, and client-side JS files

Create a folder named public manually (using the Replit file explorer) and inside it add these files:

  • index.html: your main page
  • script.js: handles frontend logic (fetching products, managing cart)
  • style.css: basic styling

 

Step 2: Install dependencies

 

npm install express body-parser

 

These two are enough for a simple cart backend. Express builds your web server, and body-parser helps to read JSON sent from frontend.

 

Step 3: Create server with routes (in index.js)

 

const express = require("express");
const bodyParser = require("body-parser");
const app = express();
const PORT = process.env.PORT || 3000;

// Middleware setup
app.use(bodyParser.json());
app.use(express.static("public")); // serve files from the "public" folder

// Pretend DB (in-memory for demo)
let products = [
  { id: 1, name: "T-Shirt", price: 20 },
  { id: 2, name: "Shoes", price: 50 },
  { id: 3, name: "Hat", price: 15 }
];

let cart = []; // will store added product IDs

// Route to get all products
app.get("/api/products", (req, res) => {
  res.json(products);
});

// Route to get cart contents
app.get("/api/cart", (req, res) => {
  res.json(cart);
});

// Route to add an item to the cart
app.post("/api/cart", (req, res) => {
  const { id } = req.body;
  const product = products.find(p => p.id === id);
  if (product) {
    cart.push(product);
    res.json({ message: "Item added", cart });
  } else {
    res.status(400).json({ error: "Product not found" });
  }
});

// Route to clear the cart
app.post("/api/cart/clear", (req, res) => {
  cart = [];
  res.json({ message: "Cart cleared" });
});

app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

Place this entire code in your existing index.js. Replit automatically runs this file. The app.use(express.static("public")) line serves your frontend automatically.

 

Step 4: Create simple frontend (in public/index.html)

 

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>Replit Shopping Cart</title>
  <link rel="stylesheet" href="style.css" />
</head>
<body>
  <h1>My Shop</h1>
  <div id="product-list"></div>
  <h2>Cart</h2>
  <div id="cart"></div>
  <button id="clear-cart">Clear Cart</button>

  <script src="script.js"></script>
</body>
</html>

This file shows the products, the cart, and a button to clear it. It loads script.js which we’ll create next.

 

Step 5: Add client-side logic (in public/script.js)

 

// Fetch and display products
async function loadProducts() {
  const res = await fetch("/api/products");
  const data = await res.json();
  const listDiv = document.getElementById("product-list");
  listDiv.innerHTML = "";
  data.forEach(p => {
    const div = document.createElement("div");
    div.innerHTML = `${p.name} - $${p.price} <button>Add to cart</button>`;
    div.querySelector("button").onclick = () => addToCart(p.id);
    listDiv.appendChild(div);
  });
}

// Fetch and display cart
async function loadCart() {
  const res = await fetch("/api/cart");
  const items = await res.json();
  const cartDiv = document.getElementById("cart");
  cartDiv.innerHTML = items.map(i => `${i.name} - $${i.price}`).join("<br>");
}

// Add product to cart
async function addToCart(id) {
  await fetch("/api/cart", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ id })
  });
  loadCart();
}

// Clear cart
document.getElementById("clear-cart").onclick = async () => {
  await fetch("/api/cart/clear", { method: "POST" });
  loadCart();
};

loadProducts();
loadCart();

All this code goes in public/script.js. It talks to your Express routes using fetch() requests. Replit previews it automatically when you click “Run”.

 

Step 6: Run the app

 

Click Replit’s green Run button. It will start your Express server and open the web view on the right side. You should see your shop, be able to add products, and watch them appear in the cart. The Run button in Replit uses the “run” command defined in package.json — keep it as "start": "node index.js" or let Replit manage it automatically.

 

How this maps to real-world structure

 

  • Backend (index.js): handles app logic and API routes
  • Frontend (public/): browser interface served by Express
  • State: stored for demo in-memory (in real apps, store in a database like Replit’s Database or PostgreSQL extension)
  • Environment variables (secrets tab): if you ever add authentication or an external API, store keys there (use process.env.MY\_KEY)

 

Common Replit-specific tips

 

  • Always keep your Express app on port 3000. Replit proxies that automatically.
  • Don’t rely on local filesystem writes — files reset when Replit restarts unless you save properly.
  • Use the Secrets tab for API keys instead of hardcoding them.
  • Replit auto-restarts your app if code changes, so your cart will reset unless saved in a database.
  • Public folder is the only place for serving static files — don’t serve files directly from root.

 

This setup gives you a working, understandable shopping cart directly in Replit — no external tools needed, just clear file structure, valid Express routes, and live reload experience that’s typical of a full Replit-based Node project.

Want to explore opportunities to work with us?

Connect with our team to unlock the full potential of no-code solutions with a no-commitment consultation!

Contact Us

How to Create a Simple Shopping Cart API with Express and Replit Database



import express from "express";
import bodyParser from "body-parser";
import Database from "@replit/database";

const app = express();
const db = new Database();
app.use(bodyParser.json());

app.post("/cart/:userId/add", async (req, res) => {
  const { userId } = req.params;
  const { productId, quantity } = req.body;

  const userCart = (await db.get(`cart_${userId}`)) || {};
  userCart[productId] = (userCart[productId] || 0) + quantity;

  await db.set(`cart_${userId}`, userCart);
  res.json({ message: "Item added", cart: userCart });
});

app.get("/cart/:userId", async (req, res) => {
  const { userId } = req.params;
  const userCart = (await db.get(`cart_${userId}`)) || {};
  res.json(userCart);
});

app.post("/cart/:userId/remove", async (req, res) => {
  const { userId } = req.params;
  const { productId } = req.body;

  const userCart = (await db.get(`cart_${userId}`)) || {};
  delete userCart[productId];

  await db.set(`cart_${userId}`, userCart);
  res.json({ message: "Item removed", cart: userCart });
});

app.listen(3000, () => console.log("Server running on port 3000"));

How to Handle Checkout and Payment Processing in Your Replit Shopping Cart



import express from "express";
import bodyParser from "body-parser";
import fetch from "node-fetch";
import Database from "@replit/database";

const app = express();
const db = new Database();
app.use(bodyParser.json());

async function createPaymentIntent(amount) {
  const response = await fetch("https://api.stripe.com/v1/payment\_intents", {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${process.env.STRIPE_SECRET_KEY}`,
      "Content-Type": "application/x-www-form-urlencoded"
    },
    body: new URLSearchParams({
      amount: Math.round(amount \* 100),
      currency: "usd"
    })
  });
  return response.json();
}

app.post("/checkout/:userId", async (req, res) => {
  const { userId } = req.params;
  const userCart = (await db.get(`cart_${userId}`)) || {};

  const productPrices = {
    "prod\_apple": 1.5,
    "prod\_orange": 2.0,
    "prod\_milk": 3.0
  };

  let total = 0;
  for (const [id, qty] of Object.entries(userCart)) {
    total += (productPrices[id] || 0) \* qty;
  }

  if (total === 0) {
    return res.status(400).json({ error: "Cart is empty" });
  }

  try {
    const paymentIntent = await createPaymentIntent(total);
    res.json({
      clientSecret: paymentIntent.client\_secret,
      total
    });
  } catch (err) {
    console.error("Payment creation failed:", err);
    res.status(500).json({ error: "Payment failed" });
  }
});

app.listen(3001, () => console.log("Checkout service running on port 3001"));

How to Sync a Shopping Cart Between Client and Server with Replit



import express from "express";
import bodyParser from "body-parser";
import Database from "@replit/database";

const app = express();
const db = new Database();
app.use(bodyParser.json());

app.post("/cart/:userId/sync", async (req, res) => {
  const { userId } = req.params;
  const { clientCart, lastUpdated } = req.body;

  const serverData = (await db.get(`cart_${userId}`)) || { items: {}, lastUpdated: 0 };
  const isClientFresher = lastUpdated > serverData.lastUpdated;
  const mergedCart = isClientFresher ? clientCart : serverData.items;

  await db.set(`cart_${userId}`, { items: mergedCart, lastUpdated: Date.now() });
  res.json({ syncedCart: mergedCart });
});

app.listen(3002, () => console.log("Cart sync service running on port 3002"));

Want to explore opportunities to work with us?

Connect with our team to unlock the full potential of no-code solutions with a no-commitment consultation!

Contact Us
Matt Graham, CEO of Rapid Developers

Book a call with an Expert

Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.

Best Practices for Building a Shopping cart with Replit

A good shopping cart built on Replit should separate the frontend (React or plain HTML + JS) and the backend (Node.js + Express), store secrets safely, and persist data either with a hosted database (like PostgreSQL or MongoDB Atlas) or with Replit’s built-in Replit Database for simple use cases. Always remember that Replit containers sleep, so don’t rely on in-memory variables for persistence. Use environment variables for API keys, and set them in the “Secrets” tab (padlock icon). The overall flow: your frontend sends requests to backend routes like /api/cart to add or fetch items, and the backend handles logic and storage.

 

Project Structure

 

In your Replit workspace, you can keep a simple folder layout:

  • server.js – your Express backend entry.
  • public/ – static files (your frontend HTML, CSS, JS).
  • package.json – for dependencies.
  • .replit and replit.nix – Replit setup (usually auto-created).

You can serve your frontend directly from Express for simplicity.

 

Backend (server.js)

 

Create a new file called server.js in the main directory if it doesn’t exist. Add this boilerplate code:

 

// server.js
import express from "express"
import bodyParser from "body-parser"
import Database from "@replit/database"

const app = express()
const db = new Database() // Replit's built-in key-value DB

app.use(bodyParser.json())
app.use(express.static("public")) // serve frontend files

// Add item to shopping cart
app.post("/api/cart", async (req, res) => {
  const { userId, productId, quantity } = req.body
  // Get current cart
  let cart = (await db.get(`cart_${userId}`)) || []
  const existing = cart.find(item => item.productId === productId)
  if (existing) {
    existing.quantity += quantity
  } else {
    cart.push({ productId, quantity })
  }
  await db.set(`cart_${userId}`, cart)
  res.json({ success: true, cart })
})

// Get user's shopping cart
app.get("/api/cart/:userId", async (req, res) => {
  const userId = req.params.userId
  const cart = (await db.get(`cart_${userId}`)) || []
  res.json(cart)
})

app.listen(3000, () => {
  console.log("Server running on http://localhost:3000")
})

 

Where this goes: Put this full code inside server.js. Every route (/api/cart) is called by your frontend.

 

Frontend (public/index.html)

 

Now create a folder named public and inside it create index.html. This will be your user interface.

 

<!-- public/index.html -->
<!DOCTYPE html>
<html>
  <head>
    <title>Shopping Cart</title>
  </head>
  <body>
    <h1>Shopping Cart Example</h1>

    <div>
      <input id="product-id" placeholder="Product ID" />
      <input id="quantity" type="number" value="1" />
      <button id="add-btn">Add to Cart</button>
    </div>

    <div>
      <button id="view-btn">View Cart</button>
    </div>

    <ul id="cart-list"></ul>

    <script>
      const userId = "user1" // simple static user for demo

      document.getElementById("add-btn").onclick = async () => {
        const productId = document.getElementById("product-id").value
        const quantity = parseInt(document.getElementById("quantity").value)
        await fetch("/api/cart", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ userId, productId, quantity })
        })
        alert("Item added!")
      }

      document.getElementById("view-btn").onclick = async () => {
        const res = await fetch(`/api/cart/${userId}`)
        const cart = await res.json()
        const list = document.getElementById("cart-list")
        list.innerHTML = ""
        cart.forEach(item => {
          const li = document.createElement("li")
          li.textContent = `${item.productId} x ${item.quantity}`
          list.appendChild(li)
        })
      }
    </script>
  </body>
</html>

 

This file goes inside the public/ folder. Express automatically serves it from the root path (/).

 

Installing Packages and Running

 

In the Replit Shell (bottom panel), install dependencies:

 

npm init -y
npm install express body-parser @replit/database

 

Then in the Replit “Run” button configuration (top of the editor), edit the .replit file if needed to look like this:

 

run = "node server.js"

 

Now click “Run”. It should show “Server running on http://localhost:3000” in the console, and the Replit webview will open showing your simple shopping cart demo.

 

Storing Secrets

 

  • Open Replit's left sidebar, click the padlock icon.
  • Add key-value pairs for things like database URLs, API keys, etc.
  • Access them in code via process.env.MY\_SECRET.

Never hardcode secrets directly in your repository.

 

Common Pitfalls and Tips

 

  • Don’t store state in variables only. When your Repl restarts, in-memory data is lost. Always persist to DB.
  • Replit Database is fine for demos or small projects, but for real e‑commerce, connect an external database.
  • Use the Replit “Deployments” tab when your app is stable. It makes your server run persistently.
  • Collaborate carefully. In Multiplayer mode, changes save for everyone live — commit often to GitHub if you’re working with teammates.
  • Use console.log() generously in Replit’s console for quick debugging.

 

With this setup, you can safely build and test a working cart system inside Replit, understand real backend/frontend communication, and later extend it with authentication, a real database, or payment integration.

Client trust and success are our top priorities

When it comes to serving you, we sweat the little things. That’s why our work makes a big impact.

Rapid Dev was an exceptional project management organization and the best development collaborators I've had the pleasure of working with. They do complex work on extremely fast timelines and effectively manage the testing and pre-launch process to deliver the best possible product. I'm extremely impressed with their execution ability.

CPO, Praction - Arkady Sokolov

May 2, 2023

Working with Matt was comparable to having another co-founder on the team, but without the commitment or cost. He has a strategic mindset and willing to change the scope of the project in real time based on the needs of the client. A true strategic thought partner!

Co-Founder, Arc - Donald Muir

Dec 27, 2022

Rapid Dev are 10/10, excellent communicators - the best I've ever encountered in the tech dev space. They always go the extra mile, they genuinely care, they respond quickly, they're flexible, adaptable and their enthusiasm is amazing.

Co-CEO, Grantify - Mat Westergreen-Thorne

Oct 15, 2022

Rapid Dev is an excellent developer for no-code and low-code solutions.
We’ve had great success since launching the platform in November 2023. In a few months, we’ve gained over 1,000 new active users. We’ve also secured several dozen bookings on the platform and seen about 70% new user month-over-month growth since the launch.

Co-Founder, Church Real Estate Marketplace - Emmanuel Brown

May 1, 2024 

Matt’s dedication to executing our vision and his commitment to the project deadline were impressive. 
This was such a specific project, and Matt really delivered. We worked with a really fast turnaround, and he always delivered. The site was a perfect prop for us!

Production Manager, Media Production Company - Samantha Fekete

Sep 23, 2022