Skip to main content

Turn Google Sheets rows into Google Slides decks with n8n

Mark a row Ready and the workflow builds a Google Slides deck for it from your template, saves it to Google Drive and writes the link back into the sheet.

Source
Google Sheets
Output
Google Slides
Delivered to
Google Drive

n8n workflow

The importable workflow file for this recipe is being tested and will be added here. The steps below show exactly what it does, so you can build it now in a few minutes with the SourceToDocs n8n node.

How the workflow runs

  1. 01

    Google Sheets Trigger: Row Added or Updated

    Outputs the rows of your sheet that were added or edited since the last check.

  2. 02

    If: Status is equal to Ready

    Only rows you have marked Ready continue, so a half-filled row never becomes a deck.

  3. 03

    Loop Over Items: Batch Size 1

    The SourceToDocs node starts one run for all the items it receives. The loop hands it one row at a time, so three rows marked Ready together still become three separate decks.

  4. 04

    SourceToDocs: Document, Generate

    Rows Come From is set to the Map Columns mode. Client, Project, Headline, Summary, Next step and Presenter come from the row; Date is the day the workflow runs. The node fills your Google Slides template and delivers the deck to your Google Drive folder.

  5. 05

    Google Sheets: Update Row

    Writes file_url into the Deck link column and changes Status, which also stops the same row from being generated twice.

Google Sheets fields and the template placeholders they fill
Google Sheets field Template placeholder
Client {{ client }}
Project {{ project }}
Headline {{ headline }}
Summary {{ summary }}
Next step {{ next_step }}
Presenter {{ presenter }}
(run date) {{ date }}

Or have Claude set it up

The Report decks from a spreadsheet skill works through the SourceToDocs connector at https://app.sourcetodocs.com/api/mcp. Install the skill, connect, then paste:

Use the report-decks skill. My data is in the Google Sheets spreadsheet "Client decks", tab "Decks", one row per deck, with the columns Deck ID, Client, Project, Headline, Summary, Next step and Presenter. Deck ID is unique per row. I will pick the spreadsheet, the Google Slides template and the Drive folder "Client decks 2026" when you send me the links. Set up one deck per row, show me the placeholder mapping before you run anything, then generate the deck for the first row only so I can check it.

Get the skill file

To turn Google Sheets rows into Google Slides decks in n8n, trigger on added or updated rows, let only rows marked Ready through, hand them one at a time to the SourceToDocs node, which fills your Google Slides template from the row’s columns, and write the returned link back to the sheet. One row is one run and one deck. The build is five nodes, described below, followed by the other shape: one deck per distinct value of a column, all in a single run.

What you need

  • A Google Sheet with one row per deck and the columns Deck ID, Client, Project, Headline, Summary, Next step, Presenter, Status and Deck link. Deck ID must be unique per row.
  • A Google Slides template with the placeholders {{ client }}, {{ project }}, {{ headline }}, {{ summary }}, {{ next_step }}, {{ presenter }} and {{ date }}, spread over as many slides as you like.
  • A SourceToDocs workspace and an API token for it. A workspace owner or admin creates the token on the API Tokens page.
  • On the Accounts page, a Google Slides connection for the template and a Google Drive connection for delivery. Every tile is a separate connection: Google Drive does not cover Google Slides.
  • n8n, Cloud or self-hosted, with the SourceToDocs node installed. On a self-hosted instance that is Settings, then Community nodes, then Install, with the package name @twovmodules/n8n-nodes-sourcetodocs; on n8n Cloud, add it from the nodes panel, where it has a verified listing.
  • A Google Sheets credential in n8n.

Set up the document in SourceToDocs

The template and its settings live in SourceToDocs. n8n only sends the row.

  1. Create a Google Slides document.
  2. Upload a small CSV with the header row Client, Project, Headline, Summary, Next step, Presenter, Date and one sample line as the data source; it becomes a data set. The sample is enough, because the workflow sends the real rows in place of reading the source.
  3. Each column gets an alias, a snake-case identifier derived from its name. The template uses the alias: column Next step is {{ next_step }}.
  4. Bind the slides to the data: Add Subset on the data set, then in Template Config add a dynamic_slide entry on that subset for every template slide that shows row data. Pick your template in Presentation Access, map each entry to its slide in the Slide Editor and press Save Mappings. A Slides document will not generate until the entries exist and are mapped. The Slide Editor lists each slide’s placeholders as Matched, Available or Unresolved.
  5. Add a Google Drive distribution and choose the folder.
  6. Leave split off. This shape gets its one deck per row from one run per row.

A slide with no row data, such as a fixed closing slide, takes a static_slide entry. Row placeholders on a static slide print blank, so keep them on the bound slides.

Build it in n8n

Add the nodes in this order. Connect the true output of If to Loop Over Items, the loop output to SourceToDocs, SourceToDocs to the Google Sheets node, and that node back into Loop Over Items.

NodeOperationKey settings
Google Sheets TriggerTrigger On: Row Added or UpdatedDocument and Sheet: your decks sheet. Optional: under Options, set Columns to Watch to Status so edits to other cells do not start the workflow.
IfOne condition{{ $json.Status }} is equal to Ready.
Loop Over ItemsBatch Size: 1No other settings.
SourceToDocsResource: Document. Operation: GenerateDocument: your deck document. Rows Come From: This Workflow — Map Columns. Data Set: the one with the seven columns. Columns: see below. Wait for Completion stays on, which is the default.
Google SheetsOperation: Update RowDocument and Sheet: the same decks sheet. Column to match on: Deck ID. Values: see below.

The seven column values in the SourceToDocs node:

ColumnValue
Client{{ $json.Client }}
Project{{ $json.Project }}
Headline{{ $json.Headline }}
Summary{{ $json.Summary }}
Next step{{ $json['Next step'] }}
Presenter{{ $json.Presenter }}
Date{{ $now.toFormat('d LLLL yyyy') }}

The values the Google Sheets node writes:

ColumnValue
Deck ID{{ $('Loop Over Items').item.json['Deck ID'] }}
Deck link{{ $json.file_url }}
StatusGenerated

The Column names are the data set’s column names, case included, not the template placeholders, which use the aliases.

Mapped values are sent as they resolve, so write numbers and dates in the sheet, or in the expression, the way they should read on the slide.

The SourceToDocs node returns file_url and file_name at the top level of its output, and file_url is what the last node writes. The deliveries list in the same output holds one entry per destination, and a Google Drive entry’s result carries drive_url for the deck in your folder.

The other shape: one deck per value of a column

The build above is one deck per row. If the sheet holds many rows per client, region or team and you want one deck for each of them, do it in a single run with a split document.

  1. Create a second Google Slides document and connect the sheet itself as its data source: a Google Sheets connection on the Accounts page, then Choose a spreadsheet and the tab in the data set’s Sheet field.
  2. On the Split step, set the driver to your Google Sheets source and that tab, and write the Split by expression with the column’s alias, for example {{ client }}. You get one file per distinct value; rows with a blank value are skipped.
  3. The driver’s own rows are not content. Set the data set that holds the rows to Only matching rows and give it the match key {{ client }}, so each deck receives only its own rows.
  4. Bind the slides and add the Drive folder as in steps 4 and 5 of the first setup: a subset, a dynamic_slide entry for each slide that shows row data, the mappings and a Google Drive distribution. A slide that lists several of a client’s rows needs a capacity on its entry and numbered placeholders, counted from 1.
  5. In n8n, the workflow shrinks to a trigger of your choice and the SourceToDocs node with Rows Come From left on Connected Data Sources, the default. The document reads the sheet itself.

Because this document reads the sheet and not a row sent by the workflow, nothing fills {{ date }} for it. Add a Date column to the sheet if the deck shows one; a placeholder with no matching column prints blank.

The node then outputs one item per deck, each with file_url and split_key, the value that deck was generated for. The decks land in a folder for that run inside your Drive folder. A split run delivers decks and no PDFs. The Airtable to Google Slides walkthrough covers the same split setup in more depth.

Or have Claude set it up

The setup in SourceToDocs can be done by Claude instead of by hand. With the SourceToDocs connector added to Claude and the report-decks skill installed, paste the prompt from the block at the top of this page. Claude creates the document, attaches the data, reads the placeholders in your template, configures the slide entries, their mappings and the Drive destination, shows you the mapping, and starts a run when you ask.

Claude reads the sheet itself, so two things differ from the workflow above. It asks first whether you need PDFs: one deck per row from a single split run delivers Google Slides decks and no PDFs, and a PDF with every deck means one run per row, which suits a few rows. And nothing fills {{ date }} for it, so add a Date column to the sheet if the deck shows one.

Three things stay with you. Claude sends links for you to pick the spreadsheet, the template and the Drive folder in Google’s own picker, because it cannot browse your Drive. It cannot edit the template file, so a missing placeholder is yours to add in Google Slides. And Claude runs when you ask: the trigger that reacts to a row marked Ready is the n8n workflow above.

When n8n’s Google Slides node is enough

n8n’s own Google Slides node can create a presentation, read one and replace text in it. For a few words swapped into a copy of one file, the Google Drive node and that node will do it: copy the template, then replace each placeholder as its own step. The SourceToDocs node does the job as one Generate step, from a template whoever owns the design can keep editing without touching the workflow. The n8n node page has the comparison table.

Where this fits

This workflow covers the simple case: a row, a template and a folder. For the trade-offs between Apps Script, the Slides API and a template-driven tool, see the Google Slides automation guide. If the row should become a Google Doc and a PDF instead of a deck, the proposal from a Google Sheets row recipe is the same chain with a Docs template.

Related

Common questions, answered

Is there a workflow file to import? +
Not yet. The importable file is being tested and will be added to this page. Until then, the five nodes and their settings above are everything the workflow contains, so you can build it by hand.
Can each deck also come as a PDF? +
Yes, in this one-row-per-run shape. Switch on Also generate PDF in the document's Output card and every run delivers a PDF beside the Google Slides file; the PDF link is in the node's deliveries list as pdf_url. A split document, the other shape on this page, delivers decks and no PDFs.
Can one row fill several slides? +
Yes. Every slide that shows row data needs its own dynamic_slide entry in Template Config, bound to the data set's subset and mapped to that slide in the Slide Editor. A static_slide entry is bound to no rows, so row placeholders on its slide print blank.
Why does the workflow use Loop Over Items? +
The Generate operation starts one run for all the items it receives. Without the loop, three Ready rows would arrive as three rows of one run, not as three decks. With Batch Size 1 each row is its own run and its own file.
What stops a row from generating twice? +
The last node changes Status away from Ready, and the If node only lets Ready rows through. To regenerate a deck after editing the row, set Status back to Ready.