Batch Exports

When you need to export results for multiple regions, time periods, or variables, batch exports let you queue many tasks at once without manual repetition.

Learning objectives

  • Export images for multiple regions using loops.
  • Create time series exports (monthly, yearly).
  • Export each image in a collection separately.
  • Manage large export queues effectively.

Why it matters

Real projects require exporting dozens or hundreds of files. Manual exports are tedious and error-prone. Batch exports automate the process and ensure consistency.

Quick win: Export by region

Export NDVI for multiple parks:

// Define multiple regions
var parks = ee.FeatureCollection([
  ee.Feature(ee.Geometry.Point([-81.0, 28.4]).buffer(10000), {name: 'Park_A'}),
  ee.Feature(ee.Geometry.Point([-82.0, 29.1]).buffer(10000), {name: 'Park_B'}),
  ee.Feature(ee.Geometry.Point([-80.5, 27.8]).buffer(10000), {name: 'Park_C'})
]);

// Create NDVI image
var image = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')
  .filterDate('2023-06-01', '2023-08-31')
  .median()
  .multiply(0.0000275).add(-0.2);
var ndvi = image.normalizedDifference(['SR_B5', 'SR_B4']).rename('NDVI');

// Get list of features to loop over
var parkList = parks.toList(parks.size());

// Export each region
for (var i = 0; i < 3; i++) {
  var park = ee.Feature(parkList.get(i));
  var name = park.get('name').getInfo();  // Get name client-side
  
  Export.image.toDrive({
    image: ndvi,
    description: 'NDVI_' + name + '_2023',
    folder: 'EarthEngine/Parks',
    region: park.geometry(),
    scale: 30,
    maxPixels: 1e9
  });
}

print('3 export tasks created - check Tasks panel!');

What you should see

Three export tasks appear in the Tasks panel. Click "Run" on each to start the exports.

Export by time period

Create monthly composites and export each:

var roi = ee.Geometry.Rectangle([-82.5, 29.5, -82.0, 30.0]);
var year = 2023;

// Loop through months
for (var month = 1; month <= 12; month++) {
  var startDate = ee.Date.fromYMD(year, month, 1);
  var endDate = startDate.advance(1, 'month');
  
  // Get monthly composite
  var composite = ee.ImageCollection('MODIS/061/MOD13A2')
    .filterDate(startDate, endDate)
    .select('NDVI')
    .median();
  
  // Format month with leading zero
  var monthStr = (month < 10) ? '0' + month : '' + month;
  
  Export.image.toDrive({
    image: composite,
    description: 'NDVI_' + year + '_' + monthStr,
    folder: 'EarthEngine/Monthly',
    region: roi,
    scale: 250,
    maxPixels: 1e9
  });
}

print('12 monthly export tasks created!');

Export each image in a collection

Export individual images (not composites):

var roi = ee.Geometry.Point([-82.3, 29.6]).buffer(5000);

// Get collection
var collection = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')
  .filterDate('2023-06-01', '2023-06-30')
  .filterBounds(roi);

// Get list of image IDs
var imageList = collection.toList(collection.size());
var count = collection.size().getInfo();

// Export each image
for (var i = 0; i < count; i++) {
  var img = ee.Image(imageList.get(i));
  var id = img.id().getInfo();
  var date = img.date().format('YYYY-MM-dd').getInfo();
  
  Export.image.toDrive({
    image: img.select(['SR_B4', 'SR_B3', 'SR_B2']).multiply(0.0000275).add(-0.2),
    description: 'L8_' + date,
    folder: 'EarthEngine/L8_Images',
    region: roi,
    scale: 30,
    maxPixels: 1e9
  });
}

print(count + ' image export tasks created!');

Export zonal statistics for many features

Calculate and export statistics for each polygon:

// Load a FeatureCollection (counties, watersheds, etc.)
var counties = ee.FeatureCollection('TIGER/2018/Counties')
  .filter(ee.Filter.eq('STATEFP', '12'))  // Florida
  .limit(10);  // Limit for demo

// Calculate NDVI
var ndvi = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')
  .filterDate('2023-06-01', '2023-08-31')
  .filterBounds(counties)
  .median()
  .multiply(0.0000275).add(-0.2)
  .normalizedDifference(['SR_B5', 'SR_B4'])
  .rename('NDVI');

// Add mean NDVI to each county
var withStats = ndvi.reduceRegions({
  collection: counties,
  reducer: ee.Reducer.mean(),
  scale: 30
});

// Export as table
Export.table.toDrive({
  collection: withStats,
  description: 'County_NDVI_Stats',
  folder: 'EarthEngine',
  fileFormat: 'CSV'
});

print('Zonal stats export task created!');

Multi-year time series

Export annual composites for multiple years:

var roi = ee.Geometry.Rectangle([-82.5, 29.5, -82.0, 30.0]);

// Loop through years
for (var year = 2018; year <= 2023; year++) {
  var composite = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')
    .filterDate(year + '-06-01', year + '-08-31')
    .filterBounds(roi)
    .median()
    .multiply(0.0000275).add(-0.2)
    .normalizedDifference(['SR_B5', 'SR_B4'])
    .rename('NDVI');
  
  Export.image.toDrive({
    image: composite,
    description: 'NDVI_Summer_' + year,
    folder: 'EarthEngine/TimeSeries',
    region: roi,
    scale: 30,
    maxPixels: 1e9
  });
}

print('6 annual export tasks created!');

Pro tips

  • Start small: Test with 2-3 exports before running 100.
  • Use .getInfo() sparingly: It's slow—only use for loop variables.
  • Organize folders: Use subfolders in Drive to keep exports organized.
  • Consistent naming: Use the same pattern for all exports.
  • Monitor progress: Check the Tasks panel for errors.
  • Parallel limit: EE runs ~10 tasks in parallel; queue more if needed.

Running all tasks

After running your script, you still need to click "Run" for each task in the Tasks panel. For many tasks, you can:

  1. Use the browser console to auto-start tasks (advanced)
  2. Use the Python API with task.start()
  3. Click quickly through the list (practical for <20 tasks)

Try it: Custom batch export

Modify the yearly time series example to:

  1. Export winter (Dec-Feb) composites instead of summer.
  2. Add years 2015-2017 to cover a longer period.
  3. Export both NDVI and NDWI as separate tasks.

Common mistakes

  • Using too many .getInfo() calls (slows script dramatically).
  • Creating exports inside a .map() function (won't work).
  • Forgetting to click "Run" in the Tasks panel.
  • Not testing a single export first.
  • Running hundreds of exports without monitoring for failures.

Quick self-check

  1. Why do we use a client-side for loop instead of .map() for exports?
  2. What does .getInfo() do and why is it slow?
  3. How many tasks does Earth Engine run in parallel?
  4. After running the script, what additional step is required?

Next steps