Use Google Sheets as a database (with a REST API) - SheetDB

How to use Google Sheets as a database for your website or app

Google Sheets is a decent database for a surprising number of projects: landing pages, prototypes, small CRMs, product catalogs, event sign-ups, internal tools and any content that non-developers need to edit. The spreadsheet is the admin panel, the data lives in your Google Drive, and your website or app reads and writes rows through an API.

This guide shows how to do that with SheetDB, which turns a sheet into a JSON REST API without OAuth, a Google Cloud project or a server of your own. It also covers the limits honestly, so you know when a spreadsheet is the wrong tool.

Good fit: up to a few tens of thousands of rows, a handful of writes per second, data that people edit in a spreadsheet anyway, projects where setup time matters more than raw performance.

Bad fit: sensitive personal data, financial transactions, anything that needs atomic updates across rows, high-concurrency writes, or tables that will grow into the millions of rows.

Can Google Sheets be used as a database?

Yes, with a few caveats. A Google Sheet is a table: the first row holds column names and each following row is a record. Through an API you can query rows by column value, insert new rows, update matching rows and delete them, which covers everything a simple CRUD application needs. What a sheet does not give you is relational integrity, transactions, indexes or fine-grained permissions. It also has hard size limits and Google throttles how often it can be read. If your project can live with those constraints, a spreadsheet is the fastest database you will ever set up.

Step 1: prepare the sheet

Treat every tab as one table and design it like one:

  • Column names in the first row. They become the keys in your JSON. Use short, lowercase names without spaces (first_name, not First Name) so they are easy to reference in code and URLs.
  • One tab, one table. Keep customers in one tab and orders in another instead of mixing them. Each tab is queried separately with the sheet parameter.
  • Add an id column. Sheets have no primary key, so give every row a unique value you can update and delete by. SheetDB can fill it for you with the INCREMENT keyword when inserting.
  • Keep types consistent. Everything comes back as a string by default. Store dates in one format (for example 2026-09-28) and use cast_numbers when you need real numbers in the response.
  • No merged cells, no blank header cells. Formatting is fine, but the structure must stay a plain grid.

The examples below use this public spreadsheet: https://docs.google.com/spreadsheets/d/1YiMOrIFnMaksK032-zv6Sch2tTVTRhEpsFom_5qSLXM/edit. It has four columns: id, name, age and comment.

Step 2: create the API

  1. Sign in to SheetDB with the Google account that owns the sheet (or has edit access to it).
  2. Click Create new API, pick the Existing spreadsheet tab and paste the spreadsheet URL from your browser's address bar. If you do not have a sheet yet, the Create new spreadsheet tab makes an empty one in your Drive, and Create new spreadsheet from JSON builds the sheet from data you already have (see how to import JSON into Google Sheets).
  3. Click Create API. You get an endpoint like https://sheetdb.io/api/v1/58f61be4dda40. That URL is your database connection string.

Open the endpoint in a browser and you should see the rows as a JSON array. Nothing else to install or deploy.

Step 3: read, search, insert, update, delete

Every operation is a single HTTP request. Below is a curl and a JavaScript fetch() example for each, followed by a link to the full reference in the docs.

Read all rows

curl https://sheetdb.io/api/v1/58f61be4dda40
const rows = await fetch('https://sheetdb.io/api/v1/58f61be4dda40')
  .then((response) => response.json());

// [{ "id": "1", "name": "Tom", "age": "15", "comment": "" }, ...]
console.log(rows);

Add ?limit=20&offset=40 for pagination and ?sort_by=age&sort_order=desc for ordering. Reference: Read.

Search rows (WHERE)

curl "https://sheetdb.io/api/v1/58f61be4dda40/search?age=>18&comment=special"
const params = new URLSearchParams({ age: '>18', comment: 'special' });

const rows = await fetch('https://sheetdb.io/api/v1/58f61be4dda40/search?' + params)
  .then((response) => response.json());

// [{ "id": "4", "name": "Steve", "age": "22", "comment": "special" }]
console.log(rows);

/search matches all conditions (AND) and /search_or matches any of them (OR). Values accept * wildcards, ! for negation and >, <, >=, <= comparisons. Reference: Search.

Insert rows (INSERT)

curl -X POST https://sheetdb.io/api/v1/58f61be4dda40 \
  -H "Content-Type: application/json" \
  -d '{"data": [{"id": "INCREMENT", "name": "Mark", "age": "35", "comment": "new customer"}]}'
await fetch('https://sheetdb.io/api/v1/58f61be4dda40', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    data: [
      { id: 'INCREMENT', name: 'Mark', age: '35', comment: 'new customer' },
    ],
  }),
});

// { "created": 1 }

data is always an array, so you can insert many rows in one request. INCREMENT assigns the next id and TIMESTAMP or DATETIME fill in the current time. Reference: Create.

Update rows (UPDATE ... WHERE)

curl -X PATCH https://sheetdb.io/api/v1/58f61be4dda40/id/5 \
  -H "Content-Type: application/json" \
  -d '{"data": {"age": "36"}}'
await fetch('https://sheetdb.io/api/v1/58f61be4dda40/id/5', {
  method: 'PATCH',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ data: { age: '36' } }),
});

// { "updated": 1 }

The path is /{column}/{value}, so /id/5 means where id equals 5. Only the columns you send are changed; the rest of the row is untouched. Reference: Update.

Delete rows (DELETE ... WHERE)

curl -X DELETE https://sheetdb.io/api/v1/58f61be4dda40/id/5
await fetch('https://sheetdb.io/api/v1/58f61be4dda40/id/5', { method: 'DELETE' });

// { "deleted": 1 }

Deleting by a wildcard such as /name/* removes every matching row, so be careful with the condition. Reference: Delete.

Use it from your language

Because the database is a plain HTTP API, any language works. We keep step-by-step guides for the most common ones:

No-code tools use the same API. There are guides for Bubble (API Connector), Adalo (External Collections) and n8n and Make (HTTP Request node and HTTP module), each with the read, add, update and delete calls configured step by step.

Limits, performance and caching

Two sets of limits apply. Google's limits: a spreadsheet holds at most 10 million cells, and Google throttles how many API reads a user and a project can make per minute. You cannot raise that quota. SheetDB's limits: each plan includes a monthly number of requests, and bursts of requests are rate limited. The current numbers are on the limits page.

The practical consequence: a busy website that calls the API on every page view would exhaust Google's quota within minutes. That is what the SheetDB cache is for. Read responses are cached (15 seconds by default, configurable per API), the cache is shared by all read endpoints, and it is cleared automatically when you write through the API. Cached requests never touch Google, so a landing page with thousands of visitors an hour stays well within the quota. If you edit the sheet by hand and want the change visible immediately, purge the cache in the API settings or send ignore_cache=1 on that one request.

For large sheets, remember that every read fetches the entire tab from Google before filtering, so response time grows with row count. Split data into tabs, archive old rows to another spreadsheet, and use limit and offset instead of loading everything into the browser.

Google Sheets vs a real database

Google Sheets + SheetDB PostgreSQL / MySQL
Setup timeMinutes: paste a URLHours: server, schema, migrations, an API layer
RowsComfortable up to tens of thousandsHundreds of millions
ConcurrencyLow: a few writes per second, Google quotasHigh: thousands of transactions per second
Relations and constraintsNone, enforced in your codeForeign keys, unique indexes, transactions
AuthPer-endpoint permissions and Basic Auth, no OAuthDatabase users, roles, row-level security
Admin UIThe spreadsheet itself, shareable with anyoneYou build it or install a separate tool
CostFree plan, then paid by requestsHosting from a few dollars a month plus maintenance

The rule of thumb: start with a sheet when the people editing the data are not developers and the data is small. Move to a database when you need transactions, relations or you hit the row and quota limits. Because SheetDB returns plain JSON, migrating later is a matter of exporting the sheet and swapping the endpoint.

FAQ

Is Google Sheets a relational database?

No. Google Sheets stores flat tables without foreign keys, constraints or joins. You can keep related data in separate tabs and link rows by an id column, but the relationship is enforced by your code, not by the sheet. For simple one-to-many data this is enough; for complex relational models use a real database.

How many rows can Google Sheets handle as a database?

A Google spreadsheet can hold up to 10 million cells, so a 10-column sheet fits about one million rows. In practice the sheet becomes slow to open long before that, and every API read fetches the whole tab. Keep a sheet used as a database under a few tens of thousands of rows. Read responses are cached for 15 seconds by default; for read-heavy traffic, increase the cache duration in the API settings so fewer requests reach Google.

Is it free to use Google Sheets as a database?

Google Sheets itself is free, and SheetDB has a free plan with a monthly request quota, no credit card required. You only pay when your app makes more requests than the free plan includes.

Do I need OAuth or a Google Cloud project?

Not with SheetDB. You sign in once with your Google account, paste the spreadsheet URL and get a REST endpoint. There is no Google Cloud project, no service account, no OAuth consent screen and no token refresh logic in your code.

Can I use Google Sheets as a database for a website?

Yes. A static site or a single-page app can read rows with a plain fetch() call and write rows with a POST request, so no backend is needed. Restrict the API permissions to read-only and protect writes with HTTP Basic Auth. Read responses are cached for 15 seconds by default, so visitors do not hit Google's rate limits; on a busy site, increase the cache duration in the API settings.

Turn your sheet into a database now

Sign in with Google, paste a spreadsheet URL and get a REST API in under a minute. Free plan, no credit card.

Create free API

Have question?

If you have any questions feel free to ask us via chat or .