How to Generate a PDF or Google Doc for Each Row in Google Sheets (2026)
You have a sheet with one row per person, client or student, and you need one document per row. Google Sheets has no built-in "make a document per row" button, but there are three practical routes: a short Apps Script you own, the built-in mail merge in Google Docs (limited), or an add-on. Here is each one, free option first.
Watch the 2-minute walkthrough on YouTube. Short on time? Watch the 50-second version.
Option 1: a free Apps Script (works today)
- Create a Google Doc template. Wherever a value should go, type the column header in double braces, such as
{{Name}}or{{Course}}. The text must match the header in row 1 exactly. - Create a Drive folder for the output and copy its ID from the URL (the part after
/folders/). Copy the template's ID from its URL too (between/d/and/edit). - In your sheet, open Extensions › Apps Script, delete the sample code, paste the script below, and fill in the two IDs.
- Save, reload the sheet, then use the new Merge › Create docs for new rows menu. Approve the permission prompt the first time.
/**
* One Google Doc + PDF per row.
* Sheet: row 1 = headers (e.g. Name, Course, Date). Template Doc uses {{Name}}, {{Course}}, {{Date}}.
* Adds "Doc link" and "PDF link" columns; rows that already have a PDF link are skipped.
*/
const TEMPLATE_ID = 'PASTE_TEMPLATE_DOC_ID';
const FOLDER_ID = 'PASTE_OUTPUT_FOLDER_ID';
function mergeRows() {
const sh = SpreadsheetApp.getActiveSheet();
const data = sh.getDataRange().getDisplayValues(); // display values keep your date/currency formatting
const head = data[0];
let docCol = head.indexOf('Doc link'), pdfCol = head.indexOf('PDF link');
if (docCol < 0) { docCol = head.length; sh.getRange(1, docCol + 1).setValue('Doc link'); head.push('Doc link'); }
if (pdfCol < 0) { pdfCol = head.length; sh.getRange(1, pdfCol + 1).setValue('PDF link'); head.push('PDF link'); }
const folder = DriveApp.getFolderById(FOLDER_ID);
const template = DriveApp.getFileById(TEMPLATE_ID);
const start = Date.now();
for (let r = 1; r < data.length; r++) {
const row = data[r];
if (row[pdfCol]) continue; // already done
if (Date.now() - start > 5 * 60 * 1000) break; // stay under the 6-minute run limit; run again to continue
const name = (row[0] || 'Row ' + (r + 1)) + ' - ' + Utilities.formatDate(new Date(), Session.getScriptTimeZone(), 'yyyy-MM-dd');
const copy = template.makeCopy(name, folder);
const doc = DocumentApp.openById(copy.getId());
const body = doc.getBody();
head.forEach((h, i) => {
if (!h) return;
body.replaceText('\\{\\{' + h.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + '\\}\\}', row[i] || '');
});
doc.saveAndClose();
const pdf = folder.createFile(copy.getAs(MimeType.PDF)).setName(name + '.pdf');
sh.getRange(r + 1, docCol + 1).setValue(copy.getUrl());
sh.getRange(r + 1, pdfCol + 1).setValue(pdf.getUrl());
SpreadsheetApp.flush();
}
}
function onOpen() {
SpreadsheetApp.getUi().createMenu('Merge').addItem('Create docs for new rows', 'mergeRows').addToUi();
}
What it does: copies the template per row, replaces every {{Header}} with that row's displayed value, exports a PDF next to the Doc, and writes both links back so a second run only processes new rows. Delete the Doc copy afterwards if you only want PDFs.
Limits to know
- 6-minute run time. Apps Script stops a run after 6 minutes for consumer and Workspace accounts. The script stops itself at 5 minutes; run it again and it continues where it left off. Each row typically takes a few seconds.
- Daily quotas. Google publishes per-account daily limits for documents created and other services on its Apps Script quotas page. Large batches may need to be spread over days.
- Formatting.
replaceTextkeeps the template's formatting, but it can't fill tables with a variable number of lines or insert images without extra code. - Automation. To run on every new Google Form response, add an installable "On form submit" trigger (Apps Script › Triggers) pointing at
mergeRows.
Permissions caveat: because this script calls DriveApp and DocumentApp.openById, Google will ask you to allow it to "see, edit, create and delete all of your Google Drive files" and all your Docs. That is fine for a script you wrote and own, but it is the same broad access most mail-merge add-ons request. If that matters for your organisation, look for a tool that uses the drive.file scope, which only touches files you pick or the tool creates.
Option 2: mail merge built into Google Docs
Some Google Workspace editions include a mail merge feature in Google Docs that pulls fields from a Google Sheet, aimed mainly at sending personalised emails from a Doc. Availability depends on your Workspace edition, and it is not designed to save one separate Doc or PDF per row into a Drive folder. If your account has it and you just need personalised emails, try it first. If you need files, use Option 1 or an add-on.
Option 3: an add-on
Add-ons wrap the same idea in a sidebar, with triggers, file naming and error handling. Established options include Autocrat (free), Document Studio, Portant and Form Publisher; see our Autocrat alternatives guide for prices and permissions checked November 5, 2026. Most of them request access to all of your Drive files.
Tips that save a re-run
- Format dates and currency in the sheet first (Format › Number); the script uses what you see.
- Avoid duplicate header names and keep headers free of braces.
- Test on a copy of the sheet with three rows before running hundreds.
{{placeholder}} template from each row and saves Docs, PDFs or both into a Drive folder you choose, writing the output links back to the sheet. It uses narrow, non-restricted scopes only (spreadsheets.currentonly, drive.file, script.container.ui, and script.external_request for the license check), so it cannot browse your whole Drive or read Gmail, and your sheet and document content never leaves your Google account. 14-day free trial with no credit card, then $8/month or $59/year. It is live on the Google Workspace Marketplace.See SheetWeave
Related Google Sheets guides
- How to generate a PDF or Google Doc for each row in Google Sheets
- Best Autocrat alternatives for mail merge to PDF and Docs
- Make invoices or certificates from Google Sheets rows
- Create sales quotes or estimates from Google Sheets
- Generate receipts from Google Sheets rows
- Create purchase orders from Google Sheets
- Make packing slips from Google Sheets orders
- Generate a PDF certificate from a Google Form response
- Issue numbered training completion certificates with expiry dates
- Make a PDF progress report for each student
- Generate offer letters from a Google Sheets hiring tracker
- Email each row’s PDF as an attachment
- Automatic email reminders from a date column
- Contract renewal and expiration alerts from Google Sheets
- Track certificate of insurance (COI) expirations in Google Sheets
- Track employee license and certification expirations
- Track equipment and vehicle maintenance with reminders
- Track warranty expiration dates with reminders
- Birthday and work anniversary reminders from Google Sheets
- Rent due and lease renewal reminders from Google Sheets
- Send invoice payment reminders from Google Sheets
- Highlight overdue tasks and send email reminders
- Follow-up reminders for leads, clients and candidates
- Membership renewal reminders for clubs and associations
- SheetWeave vs Autocrat
- SheetWeave vs Document Studio
- SheetWeave vs RowDocs
Third-party details come from each vendor's own site and Google Workspace Marketplace listing, checked November 5, 2026. Not affiliated with Google, New Visions, Digital Inspiration, Tofu Labs or any other vendor named here. Google Sheets, Google Docs and Google Drive are trademarks of Google LLC. Features and prices change, so verify before you buy. Questions or corrections: hello@loomwise.app.