The need comes up constantly: expenses tracked in separate monthly tabs, sales data spread across regional files, team logs in individual sheets. At some point, you need to pull it all into one place.

There are three main approaches, each with different tradeoffs.

---

Option 1: VSTACK (Same Spreadsheet, Multiple Tabs)

If your data lives on separate tabs within the same spreadsheet, VSTACK stacks them vertically into a single range.

Code
=VSTACK(January!A2:D, February!A2:D, March!A2:D)

This returns all rows from all three tabs, combined, starting at the cell where you enter the formula.

What VSTACK does well:

  • Simple syntax
  • Updates automatically when source tabs change
  • No permissions needed (it's all in the same file)

Limitations:

  • Only works within the same spreadsheet file
  • Doesn't skip empty rows between datasets — if January has 50 rows and February has 30, the output has 50 + 30 rows stacked (any blanks at the bottom of a tab create blank rows in the output)

To skip blanks:

Code
=FILTER(VSTACK(January!A2:D, February!A2:D), VSTACK(January!A2:A, February!A2:A)<>"")

This stacks the data and then filters out rows where column A is empty.

---

Option 2: IMPORTRANGE (Different Spreadsheet Files)

To pull data from a completely separate Google Sheets file, use IMPORTRANGE.

Code
=IMPORTRANGE("spreadsheet_url", "Sheet1!A2:D")

The first argument is the URL of the source spreadsheet. The second is the range, including the tab name.

To combine data from two separate files:

Code
=VSTACK(
  IMPORTRANGE("url_of_file_1", "Data!A2:D"),
  IMPORTRANGE("url_of_file_2", "Data!A2:D")
)

First-time setup: The first time you use IMPORTRANGE with a new source file, Google asks for permission. Click the cell with the formula and click Allow access when prompted.

What IMPORTRANGE does well:

  • Works across files, even files owned by different people
  • Source data can be protected — you only need view access

Limitations:

  • Requires an active connection; can show a loading delay
  • If the source file's range changes (columns added), you have to update the formula
  • Large ranges can be slow to load

Full guide: How to Use IMPORTRANGE in Google Sheets

---

Option 3: Apps Script (Most Control)

For combining many sheets, handling complex merges, or automating the combination on a schedule, Apps Script is the right tool.

This script reads from multiple tabs and writes all rows into a single "Combined" tab:

Code
function combineSheets() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sourceTabs = ["January", "February", "March"];  // Tab names to combine
  var outputTab  = "Combined";

  // Clear the output tab (keep the header)
  var outputSheet = ss.getSheetByName(outputTab);
  if (!outputSheet) outputSheet = ss.insertSheet(outputTab);
  var lastRow = outputSheet.getLastRow();
  if (lastRow > 1) outputSheet.getRange(2, 1, lastRow - 1, outputSheet.getLastColumn()).clearContent();

  var allRows = [];

  for (var i = 0; i < sourceTabs.length; i++) {
var sheet = ss.getSheetByName(sourceTabs[i]);
if (!sheet) continue;

var data = sheet.getDataRange().getValues();
// Skip header row (row 0) of each source tab
for (var j = 1; j < data.length; j++) {
  if (data[j].join("").trim() === "") continue;  // skip blank rows
  allRows.push(data[j]);
}
  }

  if (allRows.length > 0) {
outputSheet.getRange(2, 1, allRows.length, allRows[0].length).setValues(allRows);
Logger.log("Combined " + allRows.length + " rows from " + sourceTabs.length + " tabs.");
  }
}

To run automatically (e.g., refresh every morning):

  1. Add a time-driven trigger in the Apps Script triggers panel
  2. Set it to run combineSheets on a daily schedule

What Apps Script does well:

  • Handles any number of tabs or files
  • Can add metadata (a "Source" column, a timestamp)
  • Can deduplicate rows or apply transformations before writing

---

Which Approach to Use

| Situation | Best option | |-----------|------------| | 2–5 tabs in the same file | VSTACK | | Data spread across separate files | IMPORTRANGE + VSTACK | | Many files / files owned by others | Apps Script | | Data needs transformation before combining | Apps Script | | You want a live view (not a copy) | VSTACK or IMPORTRANGE | | You want a static snapshot that can be edited | Apps Script (writes values, not formulas) |

---

Common Problems

IMPORTRANGE shows "Loading..."

The source file is large or the connection is initializing. Wait a few seconds. If it persists, check that you still have access to the source file.

VSTACK returns rows from a fixed range and misses new entries

Your range ends at a specific row (e.g., A2:D50). Use an open-ended range: A2:D to capture all rows with data.

Combined data has duplicate headers

You're including the header row from source tabs. Make sure your ranges start from row 2 (the first data row), not row 1.

---

What to Build on Top of This

Don't want to set this up yourself? Describe your sheet structure and it'll be configured for you. Get it installed