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

Book a call with an Expert
Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.
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.
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.
// 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”.
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>
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.
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.
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"))
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"))
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"))

Book a call with an Expert
Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.
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).
Create the following files and folders inside your Replit project:
npm init -y
npm install express replit-db
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"));
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>
If you connect to an external database (MongoDB, Supabase, etc.), do not hardcode credentials. Instead, store them in Replit Secrets:
Then in your server file you can safely access them:
const dbUrl = process.env.DB_URL; // Replit automatically injects this secret
Replit supports live collaboration, which is useful for working with teammates. To keep code stable:
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.
When it comes to serving you, we sweat the little things. That’s why our work makes a big impact.