If you are already tracking operations data in Google Sheets and want to stop doing the manual work around it, this tutorial shows you how to connect n8n to your spreadsheet and automate the most common tasks: reading rows on a schedule, updating cells based on conditions, and triggering actions when data changes.

No code. No ERP API. No external database. Just n8n reading and writing to a spreadsheet you already maintain.

What You Are Building

Three connected patterns that cover 90% of what ops teams actually need from spreadsheet automation:

  1. Read and act: n8n reads rows on a schedule and triggers an action for each one that meets a condition
  2. Write back: n8n updates a cell in the sheet after an action completes (status flag, timestamp, confirmation)
  3. Watch for changes: n8n polls the sheet and fires a notification when a new row appears or a specific value changes

By the end of this tutorial, you will have built and tested all three patterns. Each one is a building block. Most workflows you will ever need are a combination of these three.

Prerequisites

A Google Sheet with at least one data tab. For this tutorial, a simple operations log works: columns for Item, Status, Owner, and Last Updated. Column names can be anything; you will map them inside n8n.

An n8n instance. n8n Cloud or self-hosted, version 1.0 or later. If you are setting up n8n for the first time, the n8n Cloud free trial is the fastest way to follow along.

Google Sheets credentials in n8n. In n8n, go to Credentials, add a new Google Sheets OAuth2 credential, and authorize it against the Google account that owns your sheet. n8n walks you through the OAuth consent screen. Once authorized, the credential appears in every Google Sheets node you add.

A notification destination. Gmail or Slack. For Slack, create an incoming webhook URL in your workspace settings. For Gmail, add a Gmail OAuth2 credential the same way you added the Sheets credential.

Pattern 1: Read and Act

This is the foundation. n8n reads every row in a sheet on a schedule, filters for rows that meet a condition, and takes an action for each one.

Step 1: Use n8n AI to Scaffold the Workflow

Before adding any nodes manually, use n8n's built-in AI to generate the starting structure. Open a new workflow, click the AI button in the editor, and describe what you want to build:

"Create a workflow that runs on a schedule, reads all rows from a Google Sheet, filters rows where Status equals Pending, and sends a Gmail notification for each match."

n8n AI will generate the core nodes and wire them together. Review what it produces before moving on. You will still configure credentials, field mappings, and conditions in the steps below, but starting with an AI-generated scaffold means you are adjusting an existing structure rather than building from scratch.

Once the AI has laid out the workflow, locate the Schedule Trigger node it created. For most ops use cases, once daily at 7am or 8am is sufficient. If you need hourly checks, set the interval to 60 minutes.

Step 2: Add a Google Sheets Node (Read Rows)

Add a Google Sheets node after the trigger.

  • Operation: Get Many Rows
  • Credential: Select your Google Sheets credential
  • Spreadsheet: Paste the URL of your sheet or select it from the picker
  • Sheet: Select the tab name
  • Return All Rows: Enable

Run the node manually to confirm it returns your data. Each row will appear as a separate item in the output panel, with column headers as JSON keys.

Step 3: Add an IF Node to Filter Rows

Add an IF node after the Google Sheets node. Set the condition to match whatever you want to act on. For example, to find rows where Status equals "Pending":

  • Value 1: {{ $json.Status }}
  • Condition: Equals
  • Value 2: Pending

The True branch contains rows matching the condition. The False branch contains everything else; leave it unconnected or route it to a No Operation node.

Step 4: Add Your Action Node

On the True branch, add whatever action you need. Common choices:

  • Gmail: Send Email (notifies a team member about each pending item)
  • Slack: Send Message (posts to an ops channel)
  • HTTP Request: Calls an external API or webhook

Configure the action to reference fields from the row. For a Gmail node sending a task notification:

  • Subject: Action needed: {{ $json.Item }}
  • Message: Status: {{ $json.Status }}\nOwner: {{ $json.Owner }}

Run the full workflow with test data to confirm the action fires for the right rows.

Pattern 2: Write Back to the Sheet

After an action completes, you want a record of it. This pattern updates a cell in the sheet so you can track what n8n has already processed.

Step 1: Add a Google Sheets Node (Update Row)

After your action node, add a second Google Sheets node.

  • Operation: Update Row
  • Credential: Same credential as before
  • Spreadsheet and Sheet: Same as the read node
  • Column to Match On: A unique identifier column (row number, item ID, or any value that is unique per row). In n8n, use the Row Number field from the read output: {{ $json._rowNumber }}
  • Fields to Update: Set the Status column to "Processed" and the Last Updated column to {{ $now.toISODate() }}

This closes the loop: the next time the workflow runs, the IF node filters out rows already marked "Processed" and the same rows are not actioned twice.

Run the workflow manually. Open the sheet and confirm the cells updated as expected.

The Pattern in Action

For most ops workflows, Patterns 1 and 2 together handle the full cycle:

Schedule Trigger
    → Google Sheets (read all rows)
    → IF node (filter by condition)
    → Action node (email, Slack, HTTP)
    → Google Sheets (update row, mark processed)

This four-node sequence handles daily task reminders, overdue item alerts, status-driven notifications, and most approval workflows without anything more complex.

Pattern 3: Watch for Changes

Instead of acting on existing rows, this pattern detects when something new appears or changes and fires immediately.

n8n does not support native Google Sheets triggers on its own. Google Sheets does not push events to n8n by default. The standard approach is polling: n8n checks the sheet on a short interval and compares the current state to what it last saw.

Step 1: Schedule a Short Interval

Create a new workflow. Add a Schedule Trigger set to run every 5 or 10 minutes.

Step 2: Read the Sheet and Store Last Row Count

Add a Google Sheets node to read all rows. Add a Code node after it to count the total rows and compare to the last known count using n8n's workflow static data:

const items = $input.all();
const currentCount = items.length;

// Retrieve last known row count from static data
const workflowStaticData = $getWorkflowStaticData('global');
const lastCount = workflowStaticData.lastRowCount || 0;

// Detect new rows
const newRows = items.slice(lastCount);

// Update stored count
workflowStaticData.lastRowCount = currentCount;

// Return new rows only
return newRows.map(item => ({ json: item.json }));

This code returns only the rows that appeared since the last run. If no new rows exist, it returns an empty array and the workflow ends without triggering any action.

Step 3: Add an IF Node to Handle Empty Output

Add an IF node to check whether any new rows were returned:

  • Value 1: {{ $items().length }}
  • Condition: Greater than
  • Value 2: 0

Connect the True branch to your notification node. The False branch ends silently.

Step 4: Add Your Notification Node

On the True branch, add a Gmail or Slack node. Reference fields from the new row:

  • For Slack: New entry in operations log: {{ $json.Item }}, Owner: {{ $json.Owner }}
  • For Gmail: Subject New log entry, body with the full row details

This pattern is useful for monitoring form submissions that write to a sheet, watching for new purchase orders or quotes logged by a team, or any situation where "something new appeared" is the trigger you need.

What to Watch Out For

Column name mismatches. The Google Sheets node maps column headers as JSON keys. If your header is Last Updated but you reference LastUpdated in a Code or Set node, the value will be empty. Use the output panel from the Google Sheets node to confirm exact key names before writing any expressions.

Row numbering. When you use _rowNumber to match rows for updates, the row number is 1-indexed and includes the header row. Row 1 in the sheet is the header, and your first data row is _rowNumber: 2. n8n handles this correctly if you use the _rowNumber field directly from the read output. Problems appear if you try to calculate row numbers manually.

Polling frequency on the Change Detection pattern. Every 5 minutes means n8n runs 288 times per day against your sheet. This is well within Google Sheets API limits for normal use, but if you have multiple workflows polling the same sheet, monitor your Google API quota in the Google Cloud Console. Increasing the interval to 10–15 minutes reduces the call count without meaningfully slowing detection for most use cases.

Static data in n8n Cloud vs self-hosted. The $getWorkflowStaticData approach in Pattern 3 persists data between executions. On n8n Cloud, this works as expected. On self-hosted n8n, confirm that your instance is not running in stateless mode, which would reset the static data on every execution.

How to Extend These Patterns

Add a Slack approval step. Between the action node and the write-back node, add a Wait node that pauses until a Slack message is replied to with an approval or rejection. The write-back then records the decision. This turns the read-and-act pattern into a human-in-the-loop workflow.

Connect to a second sheet. The write-back node does not have to update the same sheet it read from. You can log completed actions to a separate audit sheet, which is useful for keeping your operational data clean while maintaining a full history of what n8n acted on.

Trigger on a webhook instead of a schedule. If you are using Google Forms that write to a sheet, skip the polling pattern entirely. Configure the form to POST to an n8n webhook URL via Google Apps Script. n8n receives the form submission instantly and processes the new row without polling.

Why Spreadsheets First

Google Sheets is the right starting point for most automation projects for one reason: your data is already there. Before any ERP connection, before any database, your team has inventory counts, order logs, and task lists in a spreadsheet. Building automation around that data requires no migration, no new tool, and no API contract with an ERP vendor.

The three patterns in this tutorial cover the read, write, and watch operations that every spreadsheet-based workflow uses. Once these are working, adding an ERP connection means replacing the Sheets read node with an HTTP Request node that calls your ERP API; the rest of the workflow stays identical.

The Flow Kaizen guide covers how to sequence your first five automation builds, starting with spreadsheet-based workflows and building toward ERP-connected systems.