/how-to-build-replit

How to Build a Inventory tracking platform with Replit

Learn how to build an efficient inventory tracking platform using Replit with step-by-step guidance, coding tips, and practical best practices.

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 Inventory tracking platform with Replit

To build an inventory tracking platform on Replit, create a full-stack project with Node.js (Express) as the backend API and either simple HTML/CSS/JavaScript or React as the frontend. Use Replit’s built-in Database (`@replit/database`) for persistence — it’s simple and works well for small to medium data. The platform should allow adding, listing, updating, and deleting inventory items. You’ll store each item with fields like name, quantity, and category. On Replit, keep your backend and frontend in the same Repl for simplicity, and expose routes so your frontend can talk to the backend via fetch calls.

 

Setting Up the Project

 

Step 1: Create a new Repl using the “Node.js” template. Replit automatically creates a index.js file — this is your backend entry point.

Step 2: Install required packages in the Replit Shell:

npm install express @replit/database cors

Step 3: In your index.js, create an Express server with routes for inventory management.

 

Backend Code (in index.js)

 

// Import dependencies
const express = require("express")
const Database = require("@replit/database")
const cors = require("cors")

// Initialize app and database
const app = express()
const db = new Database()

// Middleware for JSON parsing and CORS
app.use(express.json())
app.use(cors())

// Route: Get all inventory items
app.get("/api/items", async (req, res) => {
  const keys = await db.list()
  const items = []
  for (let key of keys) {
    const data = await db.get(key)
    items.push({ id: key, ...data })
  }
  res.json(items)
})

// Route: Add a new item
app.post("/api/items", async (req, res) => {
  const { name, quantity, category } = req.body
  if (!name || quantity == null) return res.status(400).json({ error: "Missing fields" })
  const id = Date.now().toString()
  await db.set(id, { name, quantity, category })
  res.json({ id, name, quantity, category })
})

// Route: Update an item
app.put("/api/items/:id", async (req, res) => {
  const id = req.params.id
  const existing = await db.get(id)
  if (!existing) return res.status(404).json({ error: "Item not found" })
  const updated = { ...existing, ...req.body }
  await db.set(id, updated)
  res.json(updated)
})

// Route: Delete an item
app.delete("/api/items/:id", async (req, res) => {
  await db.delete(req.params.id)
  res.json({ success: true })
})

// Start server
app.listen(3000, () => {
  console.log("Server running on port 3000")
})

This backend provides CRUD routes your frontend can call. Replit automatically runs this file when you click “Run”.

 

Frontend Setup

 

Step 4: Create a new file called public/index.html. This will be your frontend page. In Replit’s Node template, you might need to manually create the public folder.

<!DOCTYPE html>
<html>
<head>
  <title>Inventory Tracker</title>
  <style>
    body { font-family: sans-serif; margin: 40px; }
    input, button { margin: 5px; }
    table { border-collapse: collapse; margin-top: 20px; }
    td, th { border: 1px solid #aaa; padding: 6px 10px; }
  </style>
</head>
<body>
  <h2>Inventory Tracker</h2>

  <input id="name" placeholder="Item name">
  <input id="quantity" type="number" placeholder="Quantity">
  <input id="category" placeholder="Category">
  <button onclick="addItem()">Add Item</button>

  <table id="table">
    <thead>
      <tr><th>Name</th><th>Quantity</th><th>Category</th><th>Actions</th></tr>
    </thead>
    <tbody></tbody>
  </table>

  <script>
    const API = location.origin + '/api/items' // Using same origin in Replit

    async function loadItems() {
      const res = await fetch(API)
      const items = await res.json()
      const tbody = document.querySelector('#table tbody')
      tbody.innerHTML = ''
      for (let item of items) {
        const row = document.createElement('tr')
        row.innerHTML = `
          <td>${item.name}</td>
          <td>${item.quantity}</td>
          <td>${item.category || ''}</td>
          <td>
            <button onclick="removeItem('${item.id}')">Delete</button>
          </td>`
        tbody.appendChild(row)
      }
    }

    async function addItem() {
      const name = document.getElementById('name').value
      const quantity = document.getElementById('quantity').value
      const category = document.getElementById('category').value
      await fetch(API, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ name, quantity: Number(quantity), category })
      })
      document.getElementById('name').value = ''
      document.getElementById('quantity').value = ''
      document.getElementById('category').value = ''
      loadItems()
    }

    async function removeItem(id) {
      await fetch(API + '/' + id, { method: 'DELETE' })
      loadItems()
    }

    loadItems()
  </script>
</body>
</html>

 

Serve the Frontend

 

Step 5: Update your backend in index.js to serve that static file. Place this code before app.listen():

app.use(express.static("public"))

Now, when you hit “Run”, Replit will host your API and the frontend together. You can open the browser view to see your inventory tracker live.

 

Replit Best Practices

 

  • Use Secrets: If you expand to use external APIs (for authentication or payments), store keys under the “Secrets” tab, never hardcode them.
  • Collaborate Carefully: Replit multiplayer is great, but back up your app via GitHub often — Replit autosaving can overwrite code if two people edit same file simultaneously.
  • Database Size: The built-in DB is fine for lightweight apps. For heavier cases, consider SQLite (supported) or external DBs (MongoDB, Supabase) — you’d store their connection strings as Secrets.
  • Testing API Routes: You can use Replit’s built-in webview or connect via external tools like Postman if you expose your Repl URL publicly.

 

Following these steps, you’ll have a fully functional inventory tracking platform running on Replit: it persists items, handles updates and deletions, and can be shared instantly with your team or users via its live URL.

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 Build a Simple Inventory API with Replit’s Database and Express



import express from "express"
import Database from "@replit/database"

const app = express()
const db = new Database()

app.use(express.json())

// Add or update inventory item atomically
app.post("/api/inventory", async (req, res) => {
  const { sku, name, quantity } = req.body
  if (!sku || quantity == null) return res.status(400).json({ error: "Missing fields" })

  await db.set(sku, JSON.stringify({ sku, name, quantity }))
  res.json({ message: "Item saved", item: { sku, name, quantity } })
})

// Decrease quantity safely (handles race conditions in Replit's DB)
app.post("/api/inventory/decrement", async (req, res) => {
  const { sku, amount } = req.body
  if (!sku || !amount) return res.status(400).json({ error: "Missing fields" })

  const itemRaw = await db.get(sku)
  if (!itemRaw) return res.status(404).json({ error: "Item not found" })
  const item = JSON.parse(itemRaw)

  const newQty = Math.max(item.quantity - amount, 0)
  item.quantity = newQty
  await db.set(sku, JSON.stringify(item))

  res.json({ message: "Quantity updated", item })
})

// List all items efficiently using Replit key prefix pattern
app.get("/api/inventory", async (req, res) => {
  const keys = await db.list()
  const items = await Promise.all(keys.map(async k => JSON.parse(await db.get(k))))
  res.json(items)
})

app.listen(3000, () => console.log("Inventory API running"))

How to Sync Your Inventory with an External Supplier API in Replit



import express from "express"
import fetch from "node-fetch"
import Database from "@replit/database"

const app = express()
const db = new Database()

app.use(express.json())

// Sync inventory with external supplier API (example of integrating external system)
app.post("/api/sync-supplier", async (req, res) => {
  const supplierApiKey = process.env.SUPPLIER_API_KEY
  if (!supplierApiKey) return res.status(500).json({ error: "Missing supplier API key in secrets" })

  try {
    const response = await fetch("https://api.supplier-example.com/stock", {
      headers: { Authorization: `Bearer ${supplierApiKey}` }
    })

    if (!response.ok) throw new Error("Supplier API failed")

    const supplierData = await response.json()

    // Merge supplier stock info into Replit DB
    for (const item of supplierData.items) {
      const existing = JSON.parse(await db.get(item.sku) || "{}")
      const merged = {
        sku: item.sku,
        name: item.name || existing.name,
        quantity: item.stock,
        lastSynced: new Date().toISOString()
      }
      await db.set(item.sku, JSON.stringify(merged))
    }

    res.json({ message: "Supplier data synced successfully" })
  } catch (err) {
    console.error("Sync failed:", err)
    res.status(500).json({ error: "Failed to sync supplier data" })
  }
})

app.listen(3000, () => console.log("External sync service running"))

How to Handle Automatic Inventory Restocking with a Secure Webhook in Replit



import express from "express"
import crypto from "crypto"
import Database from "@replit/database"

const app = express()
const db = new Database()
app.use(express.json({ type: ["application/json"] }))

function verifySignature(req) {
  const secret = process.env.WEBHOOK\_SECRET
  const signature = req.headers["x-webhook-signature"]
  const body = JSON.stringify(req.body)
  const expected = crypto.createHmac("sha256", secret).update(body).digest("hex")
  return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))
}

// Webhook endpoint to auto-restock inventory from supplier notifications
app.post("/api/webhooks/restock", async (req, res) => {
  if (!verifySignature(req)) return res.status(401).json({ error: "Invalid signature" })
  const { sku, added } = req.body
  if (!sku || typeof added !== "number") return res.status(400).json({ error: "Invalid payload" })

  const itemRaw = await db.get(sku)
  if (!itemRaw) return res.status(404).json({ error: "Item not found" })

  const item = JSON.parse(itemRaw)
  item.quantity += added
  item.lastRestockedAt = new Date().toISOString()
  await db.set(sku, JSON.stringify(item))

  res.json({ message: "Restocked successfully", item })
})

app.listen(3000, () => console.log("Webhook listener running"))

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 Inventory tracking platform with Replit

To build an inventory tracking platform on Replit, you should use a small but real-world setup: a Node.js + Express backend with a React (or plain HTML/JS) frontend, and connect it to a Replit-supported database like Replit DB (for simple projects) or an external DB like MongoDB Atlas (for persistence and scaling). Keep sensitive information like database URLs in Replit Secrets, use the built-in Shell to manage packages, and keep your file structure organized — this avoids the messy “one big file” problem. Replit runs your server from index.js or server.js, so start small and keep your environment aligned with what Replit expects (always ensure your package.json has a start script using node index.js).

 

Basic Project Structure

 

Create the following files and folders inside your Replit project:

  • index.js → your backend server with Express
  • package.json → created automatically when you install packages
  • public/ → static assets (HTML, CSS, JS)
  • database.js → helper functions for reading/writing inventory data

 

npm init -y
npm install express replit-db

 

Setting up the Server (index.js)

 

This file powers the backend and routes. Replit will auto-detect and run this file when you click “Run”.

 

// index.js
import express from "express";
import client from "replit-db"; // automatically manages JSON data storage

const app = express();
const db = new client();

app.use(express.json()); // allows JSON request bodies
app.use(express.static("public")); // serves static files from /public

// Route to get the full inventory
app.get("/api/items", async (req, res) => {
  const data = await db.get("inventory") || [];
  res.json(data);
});

// Route to add a new item
app.post("/api/items", async (req, res) => {
  const { name, quantity } = req.body;
  if (!name || quantity == null) return res.status(400).send("Invalid data");

  const data = await db.get("inventory") || [];
  data.push({ name, quantity });
  await db.set("inventory", data);
  res.status(201).send("Item added");
});

// Route to update item quantity
app.put("/api/items/:name", async (req, res) => {
  const { quantity } = req.body;
  const name = req.params.name;
  const data = await db.get("inventory") || [];

  const item = data.find(i => i.name === name);
  if (!item) return res.status(404).send("Item not found");

  item.quantity = quantity;
  await db.set("inventory", data);
  res.send("Item updated");
});

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

 

Creating the Frontend (public/index.html)

 

This simple frontend fetches and displays inventory data. Place this file inside a public folder.

 

<!-- public/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Inventory Tracker</title>
</head>
<body>
  <h1>Inventory List</h1>
  <ul id="list"></ul>

  <h2>Add New Item</h2>
  <input id="name" placeholder="Item Name" />
  <input id="qty" type="number" placeholder="Quantity" />
  <button id="addBtn">Add</button>

  <script>
    async function loadItems() {
      const res = await fetch("/api/items");
      const items = await res.json();
      const list = document.getElementById("list");
      list.innerHTML = "";
      items.forEach(i => {
        const li = document.createElement("li");
        li.textContent = `${i.name}: ${i.quantity}`;
        list.appendChild(li);
      });
    }

    document.getElementById("addBtn").onclick = async () => {
      const name = document.getElementById("name").value;
      const quantity = parseInt(document.getElementById("qty").value);
      await fetch("/api/items", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ name, quantity })
      });
      loadItems();
    };

    loadItems(); // initial load
  </script>
</body>
</html>

 

Managing Secrets

 

If you connect to an external database (MongoDB, Supabase, etc.), do not hardcode credentials. Instead, store them in Replit Secrets:

  • Go to the left sidebar → Secrets (lock icon)
  • Set keys like DB_URL or API_KEY

Then in your server file you can safely access them:

 

const dbUrl = process.env.DB_URL; // Replit automatically injects this secret

 

Collaboration and Version Control

 

Replit supports live collaboration, which is useful for working with teammates. To keep code stable:

  • Use Git integration (linked to GitHub) before making big edits — this allows rollback.
  • Always test “Run” before pushing, since Replit’s runner often reveals missing imports or JSON issues early.

 

Common Pitfalls to Avoid

 

  • Don’t rely on Replit DB for large datasets — it’s great for small projects but not optimized for massive writes or queries.
  • Keep your server alive only when testing; use Replit Deployments if you need persistent uptime (always-on behavior otherwise stops after 30 min of inactivity).
  • Use explicit package imports (as shown) for ESM compatibility — Replit now defaults to ESM syntax.
  • Always keep console.log lines for debugging rather than complex logging tools — logs appear directly in the Replit console.

 

Result

 

Once these steps are done, click “Run”. You’ll have a small working inventory tracking platform: Replit starts your Express server, serves your HTML UI, and JSON data is stored in Replit DB. From there, you can expand — e.g., add authentication, export CSV, or connect to a proper external DB — without breaking the simple structure that Replit handles best.

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