Dev.to WebDev πŸ›  Dev πŸ‘ 1 πŸ“– 2 min read

Building a Scalable Inventory Web App with Google Sheets & Apps Script

For any growing business handling physical products, Google Sheets is the ultimate MVP database. It's free, highly flexible, and intuitive. However, as operations scale, using a raw spreadsheet as a multi-user interfac

For any growing business handling physical products, Google Sheets is the ultimate MVP database. It's free, highly flexible, and intuitive.

However, as operations scale, using a raw spreadsheet as a multi-user interface inevitably leads to data corruption and race conditions.

In a high-tempo warehouse environment where multiple employees are picking, packing, and receiving stock simultaneously, cell collisions are a mathematical certainty. A single accidental column sort can mismatch your entire SKU database, formulas get overwritten, and your system becomes highly unreliable.

The solution isn't moving to a bloated, expensive ERP. Instead, you can treat Google Sheets strictly as a backend database layer and build a hardened, asynchronous Web App frontend on top of it using Google Apps Script.

The System Architecture

By isolating your client-side UI from your database layer, you turn a simple spreadsheet into a secure corporate tool:

  • HTML5 Scanner Integration: The web interface leverages native browser APIs to use device cameras or USB hardware for real-time barcode scanning.
  • Input Validation & Sanitization: Front-end mutations prevent typical human errors (e.g., typing string values into numerical stock cells or generating negative inventory).
  • Immutable Audit Logging: Changes trigger server-side appends to hidden log sheets, tracking the exact timestamp, worker ID, and delta.
  • Mobile-First UX: Replaces massive 100-column grids with high-contrast, touch-optimized dashboards for warehouse tablets.

The Concurrency Bottleneck: Handling Simultaneous Mutations

The most critical engineering challenge in multi-user Apps Script environments is concurrency.

Imagine Worker A and Worker B both hit the "- Pick 1 Item" button for the exact same SKU at the exact same millisecond. Without a strict execution lock, both script instances read the current stock as 10, subtract 1, and write 9 back to the spreadsheet. Two physical items left the warehouse, but the database only accounted for one.

To prevent this data loss, we leverage LockServiceβ€”the ultimate secret weapon for enterprise Apps Script builds. It acts as a server-side semaphore:

function adjustInventory(sku, adjustmentAmount, workerName) {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const inventorySheet = ss.getSheetByName("Master Inventory");

  // 1. Acquire a Script Lock to prevent race conditions
  const lock = LockService.getScriptLock();
  lock.waitLock(10000); // Wait up to 10 seconds for concurrent tasks to clear

  try {
    const data = inventorySheet.getDataRange().getValues();
    let rowIndex = -1;
    let currentStock = 0;

    // Scan array for SKU match
    for (let i = 1; i < data.length; i++) {
      if (data[i][0] === sku) {
        rowIndex = i + 1; 
        currentStock = parseInt(data[i][2]);
        break;
      }
    }


    if (rowIndex === -1) throw new Error("SKU not found");

    const newStock = currentStock + parseInt(adjustmentAmount);
    if (newStock < 0) throw new Error("Insufficient stock level");

    // Commit the locked mutation natively
    inventorySheet.getRange(rowIndex, 3).setValue(newStock);
    return { success: true, newStock: newStock };

  } catch (e) {
    return { success: false, error: e.message };
  } finally {
    // 2. Safely release the execution token
    lock.releaseLock();
  }
}

Going Serverless with Zero Hosting Cost
By deploying your custom code using the doGet() architecture and setting the execution wrapper to run as the administrator account, you create a completely serverless, decoupled application paradigm.

Your warehouse staff gets an isolated, high-speed interface, while your data schema remains protected in the cloud without spending a dime on hosting infrastructure or database compute cycles.

Complete Blueprint & Patterns
If you want to dive deeper into the complete asynchronous update patterns, boilerplate client-side google.script.run implementations, and production-ready relational schemas, we have fully documented the entire system.

πŸ‘‰ Read the Full Step-by-Step Guide on the MageSheet Blog.

πŸ“° Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes β€” full credit and traffic to the original publisher.