Configure AWS DataSync Tasks

The aws:datasync/task:Task resource, part of the Pulumi AWS provider, defines a DataSync task configuration that specifies how files should be synchronized between two locations. This guide focuses on four capabilities: basic task creation, scheduled execution, file filtering, and enhanced mode for S3 transfers.

DataSync tasks connect pre-existing locations (S3, EFS, FSx, NFS, SMB). The task resource defines the sync configuration; actual file transfers happen when you execute the task outside of Pulumi. The examples are intentionally small. Combine them with your own DataSync locations and execution logic.

Create a basic task between two locations

Most deployments start by defining a task that connects a source to a destination. The task is a reusable configuration; you trigger actual transfers separately.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.datasync.Task("example", {
    destinationLocationArn: destination.arn,
    name: "example",
    sourceLocationArn: source.arn,
    options: {
        bytesPerSecond: -1,
    },
});
import pulumi
import pulumi_aws as aws

example = aws.datasync.Task("example",
    destination_location_arn=destination["arn"],
    name="example",
    source_location_arn=source["arn"],
    options={
        "bytes_per_second": -1,
    })
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/datasync"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := datasync.NewTask(ctx, "example", &datasync.TaskArgs{
			DestinationLocationArn: pulumi.Any(destination.Arn),
			Name:                   pulumi.String("example"),
			SourceLocationArn:      pulumi.Any(source.Arn),
			Options: &datasync.TaskOptionsArgs{
				BytesPerSecond: pulumi.Int(-1),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.DataSync.Task("example", new()
    {
        DestinationLocationArn = destination.Arn,
        Name = "example",
        SourceLocationArn = source.Arn,
        Options = new Aws.DataSync.Inputs.TaskOptionsArgs
        {
            BytesPerSecond = -1,
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.datasync.Task;
import com.pulumi.aws.datasync.TaskArgs;
import com.pulumi.aws.datasync.inputs.TaskOptionsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new Task("example", TaskArgs.builder()
            .destinationLocationArn(destination.arn())
            .name("example")
            .sourceLocationArn(source.arn())
            .options(TaskOptionsArgs.builder()
                .bytesPerSecond(-1)
                .build())
            .build());

    }
}
resources:
  example:
    type: aws:datasync:Task
    properties:
      destinationLocationArn: ${destination.arn}
      name: example
      sourceLocationArn: ${source.arn}
      options:
        bytesPerSecond: -1

The sourceLocationArn and destinationLocationArn link the task to existing DataSync locations. The options block controls transfer behavior; setting bytesPerSecond to -1 removes bandwidth limits. The task doesn’t transfer files until you execute it through the AWS console, CLI, or SDK.

Schedule automatic transfers with cron expressions

Teams running regular migrations or backups configure tasks to run automatically rather than triggering each execution manually.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.datasync.Task("example", {
    destinationLocationArn: destination.arn,
    name: "example",
    sourceLocationArn: source.arn,
    schedule: {
        scheduleExpression: "cron(0 12 ? * SUN,WED *)",
    },
});
import pulumi
import pulumi_aws as aws

example = aws.datasync.Task("example",
    destination_location_arn=destination["arn"],
    name="example",
    source_location_arn=source["arn"],
    schedule={
        "schedule_expression": "cron(0 12 ? * SUN,WED *)",
    })
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/datasync"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := datasync.NewTask(ctx, "example", &datasync.TaskArgs{
			DestinationLocationArn: pulumi.Any(destination.Arn),
			Name:                   pulumi.String("example"),
			SourceLocationArn:      pulumi.Any(source.Arn),
			Schedule: &datasync.TaskScheduleArgs{
				ScheduleExpression: pulumi.String("cron(0 12 ? * SUN,WED *)"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.DataSync.Task("example", new()
    {
        DestinationLocationArn = destination.Arn,
        Name = "example",
        SourceLocationArn = source.Arn,
        Schedule = new Aws.DataSync.Inputs.TaskScheduleArgs
        {
            ScheduleExpression = "cron(0 12 ? * SUN,WED *)",
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.datasync.Task;
import com.pulumi.aws.datasync.TaskArgs;
import com.pulumi.aws.datasync.inputs.TaskScheduleArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new Task("example", TaskArgs.builder()
            .destinationLocationArn(destination.arn())
            .name("example")
            .sourceLocationArn(source.arn())
            .schedule(TaskScheduleArgs.builder()
                .scheduleExpression("cron(0 12 ? * SUN,WED *)")
                .build())
            .build());

    }
}
resources:
  example:
    type: aws:datasync:Task
    properties:
      destinationLocationArn: ${destination.arn}
      name: example
      sourceLocationArn: ${source.arn}
      schedule:
        scheduleExpression: cron(0 12 ? * SUN,WED *)

The schedule block defines when DataSync executes the task. The scheduleExpression uses cron syntax; this example runs every Sunday and Wednesday at noon UTC. DataSync handles execution automatically once the schedule is active.

Filter files with include and exclude patterns

Large datasets often contain files that shouldn’t be transferred. Pattern-based filtering controls which files participate in the sync.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.datasync.Task("example", {
    destinationLocationArn: destination.arn,
    name: "example",
    sourceLocationArn: source.arn,
    excludes: {
        filterType: "SIMPLE_PATTERN",
        value: "/folder1|/folder2",
    },
    includes: {
        filterType: "SIMPLE_PATTERN",
        value: "/folder1|/folder2",
    },
});
import pulumi
import pulumi_aws as aws

example = aws.datasync.Task("example",
    destination_location_arn=destination["arn"],
    name="example",
    source_location_arn=source["arn"],
    excludes={
        "filter_type": "SIMPLE_PATTERN",
        "value": "/folder1|/folder2",
    },
    includes={
        "filter_type": "SIMPLE_PATTERN",
        "value": "/folder1|/folder2",
    })
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/datasync"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := datasync.NewTask(ctx, "example", &datasync.TaskArgs{
			DestinationLocationArn: pulumi.Any(destination.Arn),
			Name:                   pulumi.String("example"),
			SourceLocationArn:      pulumi.Any(source.Arn),
			Excludes: &datasync.TaskExcludesArgs{
				FilterType: pulumi.String("SIMPLE_PATTERN"),
				Value:      pulumi.String("/folder1|/folder2"),
			},
			Includes: &datasync.TaskIncludesArgs{
				FilterType: pulumi.String("SIMPLE_PATTERN"),
				Value:      pulumi.String("/folder1|/folder2"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.DataSync.Task("example", new()
    {
        DestinationLocationArn = destination.Arn,
        Name = "example",
        SourceLocationArn = source.Arn,
        Excludes = new Aws.DataSync.Inputs.TaskExcludesArgs
        {
            FilterType = "SIMPLE_PATTERN",
            Value = "/folder1|/folder2",
        },
        Includes = new Aws.DataSync.Inputs.TaskIncludesArgs
        {
            FilterType = "SIMPLE_PATTERN",
            Value = "/folder1|/folder2",
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.datasync.Task;
import com.pulumi.aws.datasync.TaskArgs;
import com.pulumi.aws.datasync.inputs.TaskExcludesArgs;
import com.pulumi.aws.datasync.inputs.TaskIncludesArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new Task("example", TaskArgs.builder()
            .destinationLocationArn(destination.arn())
            .name("example")
            .sourceLocationArn(source.arn())
            .excludes(TaskExcludesArgs.builder()
                .filterType("SIMPLE_PATTERN")
                .value("/folder1|/folder2")
                .build())
            .includes(TaskIncludesArgs.builder()
                .filterType("SIMPLE_PATTERN")
                .value("/folder1|/folder2")
                .build())
            .build());

    }
}
resources:
  example:
    type: aws:datasync:Task
    properties:
      destinationLocationArn: ${destination.arn}
      name: example
      sourceLocationArn: ${source.arn}
      excludes:
        filterType: SIMPLE_PATTERN
        value: /folder1|/folder2
      includes:
        filterType: SIMPLE_PATTERN
        value: /folder1|/folder2

The excludes and includes blocks use SIMPLE_PATTERN filtering. The value property accepts pipe-separated patterns; this example includes or excludes specific folders. Filters apply during task execution, reducing transfer time and costs.

Use enhanced mode for S3-to-S3 transfers

S3-to-S3 transfers can use enhanced mode for higher performance and more detailed metrics.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.datasync.Task("example", {
    destinationLocationArn: destination.arn,
    name: "example",
    sourceLocationArn: source.arn,
    taskMode: "ENHANCED",
    options: {
        gid: "NONE",
        posixPermissions: "NONE",
        uid: "NONE",
        verifyMode: "ONLY_FILES_TRANSFERRED",
    },
});
import pulumi
import pulumi_aws as aws

example = aws.datasync.Task("example",
    destination_location_arn=destination["arn"],
    name="example",
    source_location_arn=source["arn"],
    task_mode="ENHANCED",
    options={
        "gid": "NONE",
        "posix_permissions": "NONE",
        "uid": "NONE",
        "verify_mode": "ONLY_FILES_TRANSFERRED",
    })
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/datasync"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := datasync.NewTask(ctx, "example", &datasync.TaskArgs{
			DestinationLocationArn: pulumi.Any(destination.Arn),
			Name:                   pulumi.String("example"),
			SourceLocationArn:      pulumi.Any(source.Arn),
			TaskMode:               pulumi.String("ENHANCED"),
			Options: &datasync.TaskOptionsArgs{
				Gid:              pulumi.String("NONE"),
				PosixPermissions: pulumi.String("NONE"),
				Uid:              pulumi.String("NONE"),
				VerifyMode:       pulumi.String("ONLY_FILES_TRANSFERRED"),
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.DataSync.Task("example", new()
    {
        DestinationLocationArn = destination.Arn,
        Name = "example",
        SourceLocationArn = source.Arn,
        TaskMode = "ENHANCED",
        Options = new Aws.DataSync.Inputs.TaskOptionsArgs
        {
            Gid = "NONE",
            PosixPermissions = "NONE",
            Uid = "NONE",
            VerifyMode = "ONLY_FILES_TRANSFERRED",
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.datasync.Task;
import com.pulumi.aws.datasync.TaskArgs;
import com.pulumi.aws.datasync.inputs.TaskOptionsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new Task("example", TaskArgs.builder()
            .destinationLocationArn(destination.arn())
            .name("example")
            .sourceLocationArn(source.arn())
            .taskMode("ENHANCED")
            .options(TaskOptionsArgs.builder()
                .gid("NONE")
                .posixPermissions("NONE")
                .uid("NONE")
                .verifyMode("ONLY_FILES_TRANSFERRED")
                .build())
            .build());

    }
}
resources:
  example:
    type: aws:datasync:Task
    properties:
      destinationLocationArn: ${destination.arn}
      name: example
      sourceLocationArn: ${source.arn}
      taskMode: ENHANCED
      options:
        gid: NONE
        posixPermissions: NONE
        uid: NONE
        verifyMode: ONLY_FILES_TRANSFERRED

The taskMode property switches to ENHANCED, which is only available for S3-to-S3 transfers. Enhanced mode requires specific options: setting gid, uid, and posixPermissions to NONE tells DataSync not to preserve Unix metadata. The verifyMode property controls data integrity checks; ONLY_FILES_TRANSFERRED verifies only newly transferred files.

Beyond these examples

These snippets focus on specific task-level features: task creation and location linking, scheduling and filtering, and enhanced mode for S3 transfers. They’re intentionally minimal rather than full data migration solutions.

The examples reference pre-existing infrastructure such as DataSync source and destination locations (S3, EFS, FSx, NFS, SMB). They focus on configuring the task rather than provisioning the locations it connects.

To keep things focused, common task patterns are omitted, including:

  • CloudWatch Logs integration (cloudwatchLogGroupArn)
  • Task execution reports (taskReportConfig)
  • Bandwidth throttling beyond bytesPerSecond
  • Advanced options (preserveDeletedFiles, overwriteMode, transferMode)

These omissions are intentional: the goal is to illustrate how each task feature is wired, not provide drop-in migration modules. See the DataSync Task resource reference for all available configuration options.

Let's configure AWS DataSync Tasks

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Task Execution & Lifecycle
Does creating a DataSync Task resource start syncing my files?
No, creating the task only sets up the configuration. You must start task executions separately to actually synchronize files.
What properties can't I change after creating a task?
The destinationLocationArn, sourceLocationArn, and taskMode properties are immutable. You’ll need to recreate the task to change these values.
Task Modes & Performance
What's the difference between BASIC and ENHANCED mode?
BASIC mode (default) transfers files between AWS storage and on-premises, edge, or other cloud storage. ENHANCED mode transfers virtually unlimited numbers of objects with enhanced metrics, more detailed logs, and higher performance.
When can I use ENHANCED mode?
ENHANCED mode is currently only available for transfers between Amazon S3 locations. Use BASIC mode for other storage types.
How do I set unlimited bandwidth for transfers?
Set bytesPerSecond to -1 in the options block to allow unlimited bandwidth.
Scheduling & Filtering
How do I schedule periodic file transfers?
Configure the schedule block with a scheduleExpression using cron syntax, such as cron(0 12 ? * SUN,WED *) for transfers at noon on Sundays and Wednesdays.
How do I filter which files get transferred?
Use includes and excludes blocks with filterType: "SIMPLE_PATTERN" and pipe-separated paths in the value field (e.g., "/folder1|/folder2").
Configuration & Options
Can I override task options for individual executions?
Yes, the options block sets default behavior, but you can override these options when starting individual task executions.
What options should I use with ENHANCED mode?
The Enhanced mode example shows gid: "NONE", posixPermissions: "NONE", uid: "NONE", and verifyMode: "ONLY_FILES_TRANSFERRED" as recommended settings.

Using a different cloud?

Explore storage guides for other cloud providers: