Author: By Raj
Part of our Apps Script Web Apps guides. Need this built for your team? Hire a Google Apps Script developer.
Estimated reading time: 10 minutes
Build a Full CRUD Web App with Apps Script and Google Sheets
A CRUD web app treats Google Sheets as a lightweight database: Create appends rows, Read lists filtered data, Update sets values by primary key, Delete removes or soft-deletes with IsActive column.
Primary keys should be UUIDs generated with Utilities.getUuid(), not fragile row numbers after sorts. Soft delete preserves audit history finance teams expect.
Build UI with HtmlService per /blog/apps-script-html-service-guide and secure with /blog/apps-script-user-authentication.
Sheet schema for CRUD
Columns: id, createdAt, updatedAt, createdBy, fields..., deleted. Protect header row. Use data validation on enums.
Index scans by reading column A into a map id→rowNumber updated each Read if dataset modest.
Create and Update server functions
createRecord(data) appends row with UUID. updateRecord(id, patch) finds row via map and setValues on specific columns.
Use LockService during writes to prevent double-submit from double-click.
Delete strategies
Soft delete sets deleted=true and hides via filter views. Hard delete deleteRow only for GDPR erasure requests with admin role.
Archive sheet receives copy before hard delete.
UI table pagination
Client requests page size 50 with offset. Server returns { rows, total } to keep payloads small.
Sort server-side by reading all IDs if under few thousand rows, beyond that, split tabs by year.
Example code
function updateRecord(id, patch) {
const lock = LockService.getScriptLock();
lock.waitLock(10000);
try {
const sh = SpreadsheetApp.openById('SHEET_ID').getSheetByName('Data');
const ids = sh.getRange('A2:A').getValues().flat();
const idx = ids.indexOf(id);
if (idx < 0) throw new Error('Not found');
const row = idx + 2;
if (patch.name) sh.getRange(row, 2).setValue(patch.name);
sh.getRange(row, 4).setValue(new Date());
} finally {
lock.releaseLock();
}
}| Approach | Best for | Tradeoff |
|---|---|---|
| Apps Script native | Google Workspace-centric workflows | 6-min limit, quotas |
| Zapier / Make | No-code, many connectors | Per-task cost, vendor lock-in |
| Python + Cloud | Heavy data / ML | Hosting cost, separate auth |
| Apps Script web app development | Production custom logic | Build cost, you own code |
FAQ
Is Sheets a real database?
It is fine for internal tools under ~50k rows with low concurrency. Beyond that, consider Cloud SQL with Sheets as reporting export.
Concurrent edit conflicts?
LockService plus updatedAt checks, reject update if client stale updatedAt.
Can I expose REST JSON?
Yes via doGet/doPost returning JSON, same backend as HtmlService CRUD.
Attachment fields?
Store Drive file IDs in cells; upload via DriveApp in server function from base64 client payload.
Examples?
See /blog/apps-script-internal-tool-examples for intake portal patterns.
Need this done for you? I handle this as part of my consulting work, fixed-price quote within 24 hours.
Book a call with Raj →Get the full Build a Full CRUD Web App with Apps Script and Google Sheets script template
I'll email you a production-ready, commented version you can deploy in 10 minutes.
Continue reading
Web Apps & Internal Tools
Google Apps Script Web App Development: Use Google Sheets as a Backend
Web Apps & Internal Tools
Build a Custom CRM in Google Sheets with Apps Script
Web Apps & Internal Tools
Build Your First Google Apps Script Web App: Step-by-Step Guide
From another topic
How to Automate Google Sheets with Apps Script (Beginner Guide) →Need help with this? I handle this as part of my Apps Script Web Apps service.
Internal tools, CRUD apps, HtmlService UIs, and Google SSO.
See how it works →