AWS DMS Terraform Module and Infrastructure Patterns for Database Migration

Database migration is one of the most challenging aspects of infrastructure management. Whether you are migrating from on-premises to AWS, between database engines, upgrading major versions, or restructuring your database architecture, Terraform can automate and standardize the process. This guide covers using Terraform for database migrations with AWS Database Migration Service, Blue-Green deployments, and schema migration strategies. Terraform excels at the infrastructure provisioning aspects of migration while complementary tools handle the data migration and schema changes.

Module Overview

The Terraform module which creates AWS DMS Database Migration Service resources provides a consolidated interface for provisioning the full DMS stack. See examples directory for working examples to reference.

The module is published as terraform-aws-modules/dms/aws with version constraint ~> 2.0. The module accepts subnet group configuration, replication instance configuration, and endpoint definitions in a single module block.

Module Resources

The module encapsulates the following resource types:

Type Resource
resource awsdmscertificate.this
resource awsdmsendpoint.this
resource awsdmsevent_subscription.this
resource awsdmsreplication_config.this
resource awsdmsreplication_instance.this
resource awsdmsreplicationsubnetgroup.this
resource awsdmsreplication_task.this
resource awsdmss3_endpoint.this
resource awsiampolicy.access
resource awsiamrole.access
resource awsiamrole.dmsaccessfor_endpoint
resource awsiamrole.dmscloudwatchlogs_role
resource awsiamrole.dmsvpcrole
resource awsiamrolepolicyattachment.access
resource awsiamrolepolicyattachment.access_additional
resource timesleep.waitfordependencyresources

Module Data Sources

Data Source Description
awscalleridentity.current
awsiampolicy_document.access
awsiampolicydocument.accessassume
awsiampolicydocument.dmsassume_role
awsiampolicydocument.dmsassumeroleredshift
aws_partition.current
aws_region.current

Module Inputs

Name Description Type Default Required
accessiamrole_description Description of the role string null no
accessiamrole_name Name to use on IAM role created string null no
accessiamrole_path IAM role string null no

The complete example configuration creates:

  • AWS IAM roles necessary for AWS DMS
  • AWS DMS subnet group
  • AWS DMS replication instance
  • Two AWS DMS replication endpoints - one source and one target to migrate data from an Aurora PostgreSQL cluster to Aurora MySQL cluster
  • AWS DMS replication task
  • Two AWS DMS event subscriptions - one for the replication instance, and one for the replication task
  • Necessary supporting resources to demonstrate the capabilities of the module

Replication Instance Configuration

A typical module invocation configures the replication instance and endpoints together:

```hcl
module "databasemigrationservice" {
source = "terraform-aws-modules/dms/aws"
version = "~> 2.0"

replsubnetgroupname = "example"
repl
subnetgroupdescription = "DMS Subnet group"
replsubnetgroupsubnetids = ["subnet-1fe3d837", "subnet-129d66ab", "subnet-1211eef5"]

replinstanceallocatedstorage = 64
repl
instanceautominorversionupgrade = true
replinstanceallowmajorversionupgrade = true
repl
instanceapplyimmediately = true
replinstanceengineversion = "3.5.2"
repl
instancemultiaz = true
replinstancepreferredmaintenancewindow = "sun:10:30-sun:14:30"
replinstancepubliclyaccessible = false
repl
instanceclass = "dms.t3.large"
repl
instanceid = "example"
repl
instancevpcsecuritygroupids = ["sg-12345678"]

endpoints = {
source = {
databasename = "example"
endpoint
id = "example-source"
endpointtype = "source"
engine
name = "aurora-postgresql"
extraconnectionattributes = "heartbeatFrequency=1;"
username = "postgresqlUser"
password = "youShouldPickABetterPassword123!"
port = 5432
servername = "dms-ex-src.cluster-abcdefghijkl.us-east-1.rds.amazonaws.com"
ssl
mode = "none"
tags = { EndpointType = "source" }
}
destination = {
databasename = "example"
endpoint
id = "example-destination"
endpointtype = "target"
engine
name = "aurora"
username = "mysqlUser"
password =
}
}
}
```

The replication instance parameters control capacity and maintenance behavior. repl_instance_allocated_storage is set to 64. repl_instance_auto_minor_version_upgrade is true. repl_instance_allow_major_version_upgrade is true. repl_instance_apply_immediately is true. repl_instance_engine_version is 3.5.2. repl_instance_multi_az is true. repl_instance_preferred_maintenance_window is sun:10:30-sun:14:30. repl_instance_publicly_accessible is false. repl_instance_class is dms.t3.large.

Native Terraform Resources for DMS

Terraform provides native resources for DMS infrastructure.

The AWS provider exposes 8 Terraform resources and 5 data sources available for DMS.

Resource list:

  • aws_dms_certificate - ResourceManages an Dms Certificate resource.
  • aws_dms_endpoint - ResourceManages an Dms Endpoint resource.
  • aws_dms_event_subscription - ResourceManages an Dms Event Subscription resource.
  • aws_dms_replication_config - ResourceManages an Dms Replication Config resource.
  • aws_dms_replication_instance - ResourceManages an Dms Replication Instance resource.
  • aws_dms_replication_subnet_group - ResourceManages an Dms Replication Subnet Group resource.
  • aws_dms_replication_task - ResourceManages an Dms Replication Task resource.
  • aws_dms_s3_endpoint - ResourceManages an Dms S3 Endpoint resource.

Migration Types and Prerequisites

Database migrations generally fall into several categories.

  • Engine migration involves moving from one database engine to another for example, Oracle to PostgreSQL.
  • Version upgrade means moving to a newer version of the same engine.
  • Cloud migration is moving from on-premises or another cloud to AWS.
  • Schema migration refers to making structural changes to your database tables and objects.
  • Architecture migration involves moving from single-instance to multi-AZ, or from RDS to Aurora.

Prerequisites for Terraform DMS work:

  • Terraform 1.0 or later
  • An AWS account
  • Source and target database configurations
  • Understanding of your data migration requirements

AWS Database Migration Service handles the actual data transfer. Terraform provisions the DMS infrastructure.

Network and Security Provisioning

A complete DMS networking setup provisions VPC, subnets, subnet group, and security group.

```hcl
provider "aws" {
region = "us-east-1"
}

resource "awsvpc" "migration" {
cidr
block = "10.0.0.0/16"
enablednssupport = true
enablednshostnames = true
tags = {
Name = "migration-vpc"
}
}

data "awsavailabilityzones" "available" {
state = "available"
}

resource "awssubnet" "private" {
count = 3
vpc
id = awsvpc.migration.id
cidr
block = cidrsubnet(awsvpc.migration.cidrblock, 8, count.index + 10)
availabilityzone = data.awsavailability_zones.available.names[count.index]
tags = {
Name = "migration-private-${count.index + 1}"
}
}

resource "awsdmsreplicationsubnetgroup" "main" {
replicationsubnetgroupdescription = "DMS replication subnet group"
replication
subnetgroupid = "dms-replication-subnet-group"
subnetids = awssubnet.private[*].id
tags = {
Name = "dms-subnet-group"
}
}

resource "awssecuritygroup" "dms" {
nameprefix = "dms-"
vpc
id = aws_vpc.migration.id
description = "Security group for DMS replication instance"

egress {
fromport = 3306
to
port = 3306
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "MySQL source"
}

egress {
fromport = 5432
to
port = 5432
protocol = "tcp"
cidrblocks = [awsvpc.migration.cidr_block]
description = "PostgreSQL target"
}

egress {
fromport = 443
to
port = 443
protocol =
}
}
```

Monitoring with CloudWatch Alarms

Operational visibility for DMS replication is provided via CloudWatch metric alarms.

```hcl
resource "awscloudwatchmetricalarm" "dmscdclatency" {
alarm
name = "dms-cdc-latency"
comparisonoperator = "GreaterThanThreshold"
evaluation
periods = 3
metricname = "CDCLatencySource"
namespace = "AWS/DMS"
period = 300
statistic = "Average"
threshold = 60
alarm
description = "DMS CDC latency from source is high"
dimensions = {
ReplicationInstanceIdentifier = awsdmsreplicationinstance.main.replicationinstanceid
ReplicationTaskIdentifier = aws
dmsreplicationtask.migration.replicationtaskid
}
}

resource "awscloudwatchmetricalarm" "dmsfullload" {
alarm
name = "dms-full-load-throughput"
comparisonoperator = "LessThanThreshold"
evaluation
periods = 3
metricname = "FullLoadThroughputRowsSource"
namespace = "AWS/DMS"
period = 300
statistic = "Average"
threshold = 100
alarm
description = "DMS full load throughput is low"
dimensions = {
ReplicationInstanceIdentifier = awsdmsreplicationinstance.main.replicationinstanceid
ReplicationTaskIdentifier = aws
dmsreplicationtask.migration.replicationtaskid
}
}
```

Schema Migration with Terraform Provisioners

While Terraform should not typically manage database schemas, you can use provisioners for initial setup.

hcl resource "null_resource" "schema_migration" { triggers = { db_instance_id = aws_db_instance.target.id migration_hash = filemd5("${path.module}/migrations/latest.sql") } provisioner "local-exec" { command = <<-EOT PGPASSWORD=${var.target_db_password} psql \ -h ${aws_db_instance.target.address} \ -U admin \ -d appdb \ -f ${path.module}/migrations/latest.sql EOT environment = { PGPASSWORD = } } }

Example Complete Requirements

To run this example you need to execute:

$ terraform init $ terraform plan $ terraform apply

Note that this example may create resources which will incur monetary charges on your AWS bill. Run terraform destroy when you no longer need these resources.

Version constraints for the example:

Name Version
terraform >= 1.0
aws >= 5.96
Name Version
aws >= 5.96
Name Source Version
dmsaurorapostgresqlauroramysql ../.. n/a
dms_default ../.. n/a
dms_disabled ../.

Conclusion

The Terraform approach to AWS DMS centers on separating infrastructure provisioning from data movement. The terraform-aws-modules/terraform-aws-dms module encapsulates IAM roles, subnet groups, replication instances, endpoints, replication tasks, and event subscriptions into a reusable construct with explicit parameters for instance class, storage, maintenance window, multi-AZ, and security group attachment. Native provider resources such as awsdmsreplicationinstance, awsdmsendpoint, awsdmsreplicationsubnetgroup, and awsdmsreplicationtask provide granular control when custom networking or monitoring is required.

Depth of configuration is visible in the complete example which creates an Aurora PostgreSQL to Aurora MySQL migration with VPC, private subnets, DMS subnet group, security group egress rules for source and target ports, and CloudWatch alarms for CDC latency and full load throughput. The module example demonstrates endpoint definitions with enginename, servername, port, sslmode, extraconnection_attributes, and tags.

Prerequisites remain minimal: Terraform 1.0 or later, an AWS account, source and target database configurations, and understanding of migration requirements. The module supports engine migration, version upgrade, cloud migration, schema migration, and architecture migration patterns through infrastructure as code. Monitoring and schema provisioning can be layered with CloudWatch metric alarms and null_resource provisioners without coupling schema state to Terraform.

The combination of module abstraction and native resources allows teams to standardize DMS deployments, enforce security group and subnet placement, and maintain consistent replication instance settings across environments while retaining the ability to customize endpoints and tasks per migration use case.

Sources

  1. terraform-aws-modules/terraform-aws-dms
  2. awsfundamentals.com/terraform/dms
  3. oneuptime.com/blog/post/2026-02-23-how-to-handle-database-migration-with-terraform/view
  4. github.com/terraform-aws-modules/terraform-aws-dms/blob/master/examples/complete/README.md

Related Posts