Split a master sheet into per-owner sheets
Generate a filtered copy for each team member from the master Tasks sheet.
Published Oct 15, 2025
Northwind runs every project off one master Tasks sheet — hundreds of rows,
one owner column, everyone in it. That works for the project lead, but for
each teammate it is noise: they have to filter the sheet down to their own name
every time they open it, and a stray sort by someone else wrecks the view.
This script splits the master sheet into one spreadsheet per owner, each holding
only that person’s rows plus the header. It runs on a schedule, so every Monday
morning María opens Tasks — María and sees exactly her work, nothing else.
The master stays the single source of truth; the per-owner sheets are
read-friendly copies regenerated from it.
What you’ll need
- A master Google Sheet whose first tab has a header row, including a column
titled exactly
owner. - A Drive folder to hold the generated per-owner spreadsheets — copy its ID from the folder URL.
- Edit access to that folder, so the script can create files inside it.
The script
// The master Tasks spreadsheet that everything is split from.
const MASTER_ID = '1abcMasterTasksId';
// The Drive folder the per-owner spreadsheets are written into.
const OUTPUT_FOLDER_ID = '1abcPerOwnerFolderId';
// The header that identifies the owner column.
const OWNER_HEADER = 'owner';
// What to call rows that have no owner set.
const UNASSIGNED_LABEL = 'unassigned';
/**
* Reads the master Tasks sheet, groups its rows by owner, and writes one
* fresh spreadsheet per owner into the output folder.
*/
function splitByOwner() {
// 1. Read every row of the master sheet, header included.
const [header, ...rows] = SpreadsheetApp.openById(MASTER_ID)
.getSheets()[0]
.getDataRange()
.getValues();
// 2. Bail out if there is nothing below the header.
if (!rows.length) {
Logger.log('Master sheet has no task rows — nothing to split.');
return;
}
// 3. Find the owner column by its header name.
const ownerCol = header.indexOf(OWNER_HEADER);
if (ownerCol === -1) {
throw new Error('No "' + OWNER_HEADER + '" column in the master sheet.');
}
// 4. Group the rows into one bucket per owner.
const buckets = new Map();
for (const row of rows) {
const owner = row[ownerCol] || UNASSIGNED_LABEL;
if (!buckets.has(owner)) buckets.set(owner, []);
buckets.get(owner).push(row);
}
// 5. Clear out last run's files so old data never lingers.
const folder = DriveApp.getFolderById(OUTPUT_FOLDER_ID);
removeOldSplitFiles(folder);
// 6. Create one spreadsheet per owner with the header and their rows.
for (const [owner, ownerRows] of buckets) {
const ss = SpreadsheetApp.create('Tasks — ' + owner);
DriveApp.getFileById(ss.getId()).moveTo(folder);
const sheet = ss.getSheets()[0];
sheet.getRange(1, 1, 1, header.length).setValues([header]);
sheet.getRange(2, 1, ownerRows.length, header.length).setValues(ownerRows);
}
Logger.log('Split ' + rows.length + ' rows into ' + buckets.size + ' sheets.');
}
/**
* Deletes the per-owner spreadsheets from a previous run so the folder
* never accumulates stale duplicates. Files are matched by the "Tasks — "
* name prefix.
*
* @param {Folder} folder The output folder to clean.
*/
function removeOldSplitFiles(folder) {
// Iterate every file in the folder and trash the ones from a previous run.
const all = folder.getFiles();
while (all.hasNext()) {
const file = all.next();
if (file.getName().startsWith('Tasks — ')) {
file.setTrashed(true);
}
}
}
How it works
splitByOwneropens the master spreadsheet and reads its first tab in one call, peeling off the header with array destructuring.- If there are no rows below the header, it logs a message and stops — no empty files get created.
- It locates the
ownercolumn by name rather than by position, so reordering columns in the master never breaks the split. A missing column throws a clear error. - It walks the rows once, dropping each into a
Mapkeyed by owner. Rows with a blank owner go into anunassignedbucket. removeOldSplitFilestrashes last run’sTasks — …files so the folder does not fill up with duplicates and a removed owner’s file disappears.- For each owner it creates a new spreadsheet, moves it into the output folder, writes the header, and writes that owner’s rows beneath it.
Example run
The master Tasks sheet:
| task | owner | due |
|---|---|---|
| Draft Q3 report | María | 2025-10-20 |
| Update price list | Hans | 2025-10-18 |
| Review supplier list | María | 2025-10-25 |
| Archive old files | 2025-10-30 |
After a run the output folder contains three spreadsheets. Tasks — María
holds:
| task | owner | due |
|---|---|---|
| Draft Q3 report | María | 2025-10-20 |
| Review supplier list | María | 2025-10-25 |
Tasks — Hans holds the price-list row, and Tasks — unassigned holds the
archive row.
Trigger it
This is a regenerate-from-scratch job, so run it on a schedule that suits the team’s rhythm — Monday morning works well:
- In the Apps Script editor open Triggers (the clock icon).
- Click Add Trigger.
- Choose
splitByOwner, event source Time-driven, type Week timer, and pick the day and hour. - Save and approve the authorisation prompt.
Watch out for
- The script regenerates the per-owner files every run. Anything a teammate types directly into their copy is overwritten — these are read-only views, and edits must go back into the master.
- Owners are grouped by the exact text in the
ownercolumn. “Maria” and “María” become two separate files, and so do “hans” and “Hans”. Keep the master’s owner values consistent. - A new spreadsheet is created on every run. Without
removeOldSplitFilesthe folder would fill with duplicates; keep that cleanup step in place. setValueswrites the whole grid at once, which is fast, but a master sheet with tens of thousands of rows can still approach the script time limit. If it does, split the run across owners in batches.- The per-owner files inherit only the values, not the formatting, formulas, or data validation of the master sheet.
Related
Build an OKR tracker with progress rollups
Aggregate Northwind's key-result progress into objective-level scores automatically.
Updated Jan 14, 2026
Build a recurring-task generator
Spawn new Northwind task rows on a daily or weekly cadence from a Recurring sheet.
Updated Jan 10, 2026
Build a multi-sheet search-and-jump tool
Find a value across every tab of a workbook and click through to the cell that contains it.
Updated Jan 7, 2026
Auto-rebuild grouped summaries on edit
Refresh pivot-style rollups the instant data changes — no manual recompute.
Updated Jan 4, 2026
Build a data-quality scorecard
Grade any sheet on completeness, validity, and freshness — surface gaps as a single score.
Updated Dec 31, 2025