All posts
Blog

How Non-Technical Content Editors Can Update a Website with Google Sheets

A practical guide to setting up a workflow where content editors update a Google Sheet and the website reflects changes automatically.

2 min read

The two-minute version of the workflow

A developer sets up a Google Sheet with the right column headers. They point SheetsAPI at it and get a REST endpoint back. The Next.js app fetches from that endpoint with a 60-second revalidation window. From that point on, when a content editor adds a row, changes a value, or removes an entry in the Sheet, the website reflects it within a minute — no deployment, no CMS login, no developer involved.

That is the whole workflow. The rest of this post is the practical detail of making it work well.

What the editor sees

The editor opens a Google Sheet that looks like a table. For a team directory it might have columns: name, role, bio, photo_url. For a FAQ page: question, answer, category. For a product listing: title, price, description, available.

Adding content means typing into a new row. Editing means clicking a cell. Removing something means deleting the row or clearing a value. The editor never needs to log in anywhere else, never waits for a developer to push a change, and has full undo history if they make a mistake.

The one thing to communicate up front: column names are the API field names, so they should not be renamed without telling the developer. That is a fair constraint for an otherwise frictionless workflow.

What the developer sets up

On the developer side, the setup is small:

  1. Create the Sheet, define the column headers in row 1.
  2. Sign in to GKit, connect the Sheet, and copy the SheetsAPI endpoint URL.
  3. In Next.js, fetch from that endpoint with revalidation:
// app/team/page.tsx
export default async function TeamPage() {
  const res = await fetch(
    "https://sheetsapi.gkit.mreshank.com/api/spreadsheets/USER_KEY/Team",
    { next: { revalidate: 60 } }
  );
  const { data } = await res.json();
  return <TeamGrid members={data} />;
}

The page rebuilds in the background at most every 60 seconds. No webhook needed. No deployment step when content changes.

If the Sheet is private, add the API key to your environment variables and pass it in the Authorization header. Public Sheets need no token at all.

Advantages over a traditional CMS

A CMS login is another account to manage, another interface to train someone on, and often another subscription to pay for. When the editor is already in Google Workspace all day — email, docs, calendar — a Sheet is zero learning curve.

For small teams managing a handful of content types (a team page, a pricing table, a list of blog categories), the operational simplicity of a Sheet beats the feature set of a CMS that goes mostly unused.

Real limitations to be honest about

No rich text natively. A cell holds plain text. If a field needs formatted content — bold, links, lists — you have two options: store Markdown in the cell and render it client-side, or keep that field in a real CMS and use the Sheet for structured fields only.

No media uploads. Editors can paste a URL into a photo_url column, but they cannot upload an image directly to the Sheet. The image has to live somewhere else first (Google Drive, Cloudinary, wherever). For many content types this is fine; for image-heavy publishing workflows it is a friction point worth acknowledging before you build.

No validation. A cell accepts anything — a typo in a date, a broken URL, a value that doesn't match what the component expects. If field integrity matters, add a VLOOKUP or data validation rule in the Sheet itself. It is not a substitute for proper schema validation, but it catches the obvious mistakes at the source.

For content that is mostly text-based and small in scope, this workflow removes a real category of developer involvement from day-to-day operations. That is worth the honest tradeoffs.

Share