# Publish and edit blog posts from a Google Sheet

A blog is a table pretending to be a CMS: each post is a row with a title, slug, date, tags, and body. Keep that table in Google Sheets and PasteSheet serves it as a live JSON API — filter to published posts, sort newest-first, and render the feed without standing up WordPress or a database.

*Last updated: 2026-07-11 · Source: <https://pastesheet.com/use-cases/google-sheets-blog-cms>*

## Key facts

- A Google Sheet is capped at **10 million cells** (or 18,278 columns), which is the real ceiling on using one as a database. ([source](https://support.google.com/drive/answer/37603))
- One row is one post, and the row cap is your archive size: **500 posts on Free**, **5,000 on Starter ($9/mo)**, uncapped on **Pro ($19/mo)**.
- A Free endpoint exposes **one tab**, so a Posts-plus-Authors layout needs **Starter ($9/mo)** (5 tabs) or **Pro** (unlimited).
- Webhooks that rebuild a static blog the moment a post flips to `published` are a **Pro ($19/mo)** feature.

## A blog is just a spreadsheet

Strip a blog down and every post is a handful of fields: a title, a URL slug, a publish date, some tags, and the body. That is a spreadsheet row. Yet most blogs drag in a full CMS, a database, and an admin login to manage what is fundamentally a table your writers could edit in their sleep.

PasteSheet turns a *Posts* tab into a content API. Writers draft in Google Sheets — a tool they already know — flip a `status` cell to `published`, and your front end picks it up on the next cache refresh. Slugs map to routes, the body renders as Markdown or HTML, and there is no migration to run when you add a column.

## Columns that map to a post

One row per post, one column per field. A typical layout:

- `title`, `slug`, and `excerpt` for the listing and the route.
- `published_at` to sort newest-first and `status` to gate drafts.
- `tags` for filtering and `author` for bylines.
- `body` holding Markdown or HTML your renderer turns into the article.

## Fetch the published feed

Filter to published rows and sort by date with URL parameters — drafts stay hidden simply by not being marked published:

```bash
curl "https://pastesheet.com/your-endpoint/Posts?status=published&sort=-published_at&per_page=10"

{
  "data": [
    {
      "title": "Why we moved our blog to a spreadsheet",
      "slug": "blog-in-a-sheet",
      "excerpt": "No database, no admin panel — just rows.",
      "tags": "engineering, meta",
      "author": "Dana Lee",
      "published_at": "2026-07-09",
      "status": "published"
    }
  ]
}
```

## Read-only, so it is safe to publish

Because the endpoint is **read-only by design**, it is safe to expose publicly or hand to a teammate: consumers can read and query the data but can never change the sheet. And there is **no Google Cloud project, OAuth screen, or service account** to set up — you paste a share URL and get a live API.

## What it costs

**Free — $0/month.** For side projects and trying things out.

- Endpoints: 3
- Requests: 2,000 / month
- Rows per endpoint: 500
- Tabs per endpoint: 1
- Rate limit: 60 / minute

**Start free.** The Free plan runs 3 live endpoints with a 5-minute cache — enough for a working blog. Paid plans add private endpoints for staging, type-mapped columns, and [webhooks](https://pastesheet.com/features) to rebuild a static site when a post ships.

## Frequently asked questions

### How do I keep drafts out of the feed?

Add a status column and filter the endpoint to status=published. Unpublished rows simply never match the query, so drafts stay invisible to your site until a writer flips the cell.

### Can I paginate a long archive?

Yes. Use page and per_page to page through posts, and sort=-published_at to keep the newest first — so a growing archive stays fast and you fetch only the rows a page needs.

### Where does the post body live?

In a cell. Store Markdown or HTML in a body column and return it like any other field; your front end renders it. Longer posts work fine — the body is just a string in the JSON.

### Do I need a database or WordPress?

No. There is no database, admin panel, or server to run. You paste a Google Sheet URL and PasteSheet hosts the read-only API your blog reads from.

## Sources

- [Files you can store in Google Drive (size limits)](https://support.google.com/drive/answer/37603) — Google

## Related use cases

- [Use Google Sheets as a Free Headless CMS](https://pastesheet.com/use-cases/google-sheets-cms) — Run your website's content from a Google Sheet. PasteSheet publishes it as a live, read-only JSON API — no database, no backend, no Google Cloud setup.
- [Drive a Marketing Site from Google Sheets](https://pastesheet.com/use-cases/google-sheets-content-website) — Run your marketing site's content blocks from a Google Sheet — hero copy, feature lists, section text. PasteSheet publishes it as a live, read-only JSON API.
- [Power an FAQ Page from a Google Sheet](https://pastesheet.com/use-cases/google-sheets-faq-page) — Build a searchable FAQ or help page from a Google Sheet — one row per question and answer. Full-text search over questions via a live, read-only JSON API.
- [Use a Google Sheet as a Next.js Data Source](https://pastesheet.com/use-cases/google-sheets-nextjs-data) — Fetch a Google Sheet as typed JSON in Next.js or React — from a Server Component, getStaticProps, or ISR. Cached, read-only, set up by pasting a share URL.

---

[PasteSheet](https://pastesheet.com) turns any Google Sheet into a live REST API and MCP server for AI agents — no backend, no code. Canonical HTML version of this page: <https://pastesheet.com/use-cases/google-sheets-blog-cms>
