TL;DR
AWS EMR (Elastic MapReduce) APIs manage big data clusters running Hadoop, Spark, Hive, and Presto. You create clusters, submit jobs as steps, auto-scale based on workload, and terminate when done. Authentication uses AWS IAM. Use Apidog to validate cluster configurations, test job submissions against the API structure, and document your data pipelines.
Introduction
AWS EMR is AWS's managed Hadoop and Spark service for analytics, machine learning, and ETL workloads. It processes data on EC2 instances without requiring you to operate the underlying Hadoop infrastructure yourself.
An EMR cluster is made up of EC2 instances. When creating one, define:
- Instance types for primary, core, and task nodes
- Applications such as Spark, Hadoop, Hive, Presto, or HBase
- Bootstrap actions for setup scripts
- Steps that run your jobs
The EMR API lets you automate the full cluster lifecycle: create clusters, submit jobs, monitor execution, configure scaling, and terminate resources when processing is complete.
💡 If you’re building data pipelines, Apidog can help you test cluster configurations, validate job definitions, and document EMR workflows before running expensive data processing jobs.
Test AWS APIs with Apidog - free
By the end of this guide, you’ll be able to:
- Create and configure EMR clusters through the API and AWS CLI
- Submit Spark and Hive jobs as EMR steps
- Configure auto-scaling policies
- Monitor cluster and step status
- Reduce costs with transient clusters, instance fleets, and Spot instances
Authenticate with AWS
EMR uses standard AWS IAM authentication. For application code, prefer an AWS SDK. For command-line workflows, use the AWS CLI. Both handle AWS Signature Version 4 (SigV4) signing for you.
Use the AWS SDK
Install the EMR SDK package:
npm install @aws-sdk/client-emr
Create an EMR client using environment variables for credentials:
import { EMRClient, RunJobFlowCommand } from '@aws-sdk/client-emr'
const client = new EMRClient({
region: 'us-east-1',
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
}
})
Avoid hard-coding credentials in source code. In production, use IAM roles where possible.
Use the AWS CLI
The AWS CLI signs requests automatically when your credentials are configured:
aws emr list-clusters --region us-east-1
Direct API requests and SigV4
The EMR API requires AWS Signature Version 4. If you call the API directly, you must sign every request. In practice, use an AWS SDK, boto3, or the AWS CLI unless you specifically need to implement SigV4 yourself.
IAM permissions
A basic policy for EMR management can include the following permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"elasticmapreduce:*",
"ec2:Describe*",
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject",
"s3:ListBucket"
],
"Resource": "*"
}
]
}
Use this as a starting point, then scope actions and resources down for production workloads.
Create an EMR cluster
Create a basic Spark cluster with the AWS CLI
The following command creates a three-node cluster with Spark and Hadoop installed:
aws emr create-cluster \
--name "My Spark Cluster" \
--release-label emr-7.0.0 \
--applications Name=Spark Name=Hadoop \
--instance-type m5.xlarge \
--instance-count 3 \
--service-role EMR_DefaultRole \
--job-flow-role EMR_EC2_DefaultRole
Before running it, make sure that:
- The EMR service role exists.
- The EC2 instance profile role exists.
- Your account has enough EC2 capacity and service quota for the selected instance type.
- Your region supports the EMR release label and instance type.
Create a cluster with RunJobFlow
Use the RunJobFlow API when you need programmatic cluster provisioning:
{
"Name": "Data Processing Cluster",
"ReleaseLabel": "emr-7.0.0",
"Applications": [
{ "Name": "Spark" },
{ "Name": "Hadoop" },
{ "Name": "Hive" }
],
"Instances": {
"MasterInstanceType": "m5.xlarge",
"SlaveInstanceType": "m5.xlarge",
"InstanceCount": 3,
"KeepJobFlowAliveWhenNoSteps": true,
"TerminationProtected": false
},
"Steps": [],
"ServiceRole": "EMR_DefaultRole",
"JobFlowRole": "EMR_EC2_DefaultRole",
"LogUri": "s3://my-bucket/emr-logs/",
"Tags": [
{ "Key": "Environment", "Value": "Production" }
]
}
A successful request returns a cluster ID:
{
"JobFlowId": "j-ABC123DEF456"
}
Store this ID. You need it to add steps, inspect status, configure scaling, and terminate the cluster.
Choose instance groups or instance fleets
EMR supports two provisioning approaches:
- Instance groups: Use a fixed instance type for each group: primary, core, and task.
- Instance fleets: Provide multiple instance types and capacity targets. EMR selects available capacity based on your configuration.
Use instance fleets when capacity availability or Spot pricing is a concern.
{
"Instances": {
"InstanceFleets": [
{
"Name": "MasterFleet",
"InstanceFleetType": "MASTER",
"TargetOnDemandCapacity": 1,
"InstanceTypeConfigs": [
{
"InstanceType": "m5.xlarge"
},
{
"InstanceType": "m4.xlarge"
}
]
},
{
"Name": "CoreFleet",
"InstanceFleetType": "CORE",
"TargetOnDemandCapacity": 2,
"TargetSpotCapacity": 4,
"InstanceTypeConfigs": [
{
"InstanceType": "m5.2xlarge"
},
{
"InstanceType": "m4.2xlarge"
}
],
"LaunchSpecifications": {
"SpotSpecification": {
"TimeoutDurationMinutes": 60,
"TimeoutAction": "SWITCH_TO_ON_DEMAND"
}
}
}
]
}
}
Submit jobs as EMR steps
EMR runs jobs as steps. Steps execute sequentially by default, so define their failure behavior carefully.
Add a Spark step with the AWS CLI
Use command-runner.jar to invoke spark-submit:
aws emr add-steps \
--cluster-id j-ABC123DEF456 \
--steps '[
{
"Name": "Process Data",
"ActionOnFailure": "CONTINUE",
"HadoopJarStep": {
"Jar": "command-runner.jar",
"Args": [
"spark-submit",
"--deploy-mode",
"cluster",
"--class",
"com.example.DataProcessor",
"s3://my-bucket/jars/processor.jar",
"s3://my-bucket/input/",
"s3://my-bucket/output/"
]
}
}
]'
Use --deploy-mode cluster when the Spark driver should run on the EMR cluster rather than on the machine submitting the command.
Add steps with AddJobFlowSteps
The equivalent API request looks like this:
{
"JobFlowId": "j-ABC123DEF456",
"Steps": [
{
"Name": "Spark ETL Job",
"ActionOnFailure": "CONTINUE",
"HadoopJarStep": {
"Jar": "command-runner.jar",
"Args": [
"spark-submit",
"--executor-memory",
"4g",
"--executor-cores",
"2",
"s3://my-bucket/scripts/process.py",
"--input",
"s3://my-bucket/input/",
"--output",
"s3://my-bucket/output/"
]
}
}
]
}
Set ActionOnFailure
Choose the failure behavior that matches your pipeline:
| Value | Behavior |
|---|---|
TERMINATE_CLUSTER |
Stops the cluster when the step fails. |
CANCEL_AND_WAIT |
Cancels remaining steps and keeps the cluster running. |
CONTINUE |
Continues to the next step after a failure. |
For transient ETL clusters, TERMINATE_CLUSTER can prevent idle compute costs after a critical failure. For debugging workflows, CANCEL_AND_WAIT can be useful because the cluster remains available for inspection.
Add a Hive step
Use hive-script through command-runner.jar:
{
"Name": "Hive Query",
"HadoopJarStep": {
"Jar": "command-runner.jar",
"Args": [
"hive-script",
"--run-hive-script",
"--args",
"-f",
"s3://my-bucket/scripts/transform.q"
]
}
}
Configure auto-scaling
EMR can add or remove nodes based on CloudWatch metrics. Auto-scaling is useful when workload volume changes over time.
Create an auto-scaling policy
This policy adds two nodes when available memory is low:
aws emr put-auto-scaling-policy \
--cluster-id j-ABC123DEF456 \
--instance-group-id ig-ABC123 \
--auto-scaling-policy '{
"Constraints": {
"MinCapacity": 2,
"MaxCapacity": 10
},
"Rules": [
{
"Name": "ScaleOut",
"Description": "Add nodes when memory is high",
"Action": {
"SimpleScalingPolicyConfiguration": {
"AdjustmentType": "CHANGE_IN_CAPACITY",
"ScalingAdjustment": 2,
"CoolDown": 300
}
},
"Trigger": {
"CloudWatchAlarmDefinition": {
"ComparisonOperator": "GREATER_THAN",
"EvaluationPeriods": 3,
"MetricName": "MemoryAvailableMB",
"Namespace": "AWS/ElasticMapReduce",
"Period": 300,
"Threshold": 2000,
"Statistic": "AVERAGE"
}
}
}
]
}'
Validate the metric logic before applying it. For example, MemoryAvailableMB represents free memory, so scale-out thresholds should be selected carefully for the behavior you intend.
Metrics to use for scaling
Common EMR metrics include:
| Metric | Use |
|---|---|
MemoryAvailableMB |
Available memory across the cluster. |
MemoryTotalMB |
Total cluster memory. |
HDFSUtilization |
Percentage of HDFS storage in use. |
AppsRunning |
Number of running YARN applications. |
AppsPending |
Number of YARN applications waiting to run. |
Monitor clusters and jobs
List running clusters
aws emr list-clusters --states RUNNING
Describe a cluster
aws emr describe-cluster --cluster-id j-ABC123DEF456
The response includes cluster state, installed applications, logging location, and the primary node DNS name:
{
"Cluster": {
"Id": "j-ABC123DEF456",
"Name": "My Cluster",
"Status": {
"State": "RUNNING",
"StateChangeReason": {},
"Timeline": {
"CreationDateTime": "2026-03-24T10:00:00.000Z"
}
},
"Applications": [
{ "Name": "Spark", "Version": "3.5.0" }
],
"InstanceCollectionType": "INSTANCE_GROUP",
"LogUri": "s3://my-bucket/emr-logs/",
"MasterPublicDnsName": "ec2-12-34-56-78.compute-1.amazonaws.com"
}
}
List cluster steps
aws emr list-steps --cluster-id j-ABC123DEF456
A completed step has a status similar to this:
{
"Id": "s-ABC123",
"Name": "Process Data",
"Status": {
"State": "COMPLETED",
"Timeline": {
"StartDateTime": "2026-03-24T10:05:00.000Z",
"EndDateTime": "2026-03-24T11:30:00.000Z"
}
}
}
Monitor through CloudWatch
EMR publishes CloudWatch metrics including:
JobsFailedJobsRunningMemoryAvailableMBMemoryTotalMBHDFSUtilization
Use these metrics for dashboards, alarms, and auto-scaling triggers.
Optimize EMR costs
Use Spot instances for task capacity
Task nodes are a good candidate for Spot instances because they process data but do not store HDFS data.
{
"Name": "TaskGroup",
"InstanceRole": "TASK",
"InstanceType": "m5.2xlarge",
"InstanceCount": 4,
"Market": "SPOT",
"BidPrice": "0.10"
}
If a Spot task node is interrupted, work can continue on the remaining nodes.
Use transient clusters
For scheduled batch jobs, create a cluster, run the required steps, and terminate it after completion:
{
"KeepJobFlowAliveWhenNoSteps": false,
"Steps": [
{ "...": "step 1" },
{ "...": "step 2" }
]
}
With KeepJobFlowAliveWhenNoSteps set to false, the cluster terminates after all steps finish.
Provide multiple instance options
Instance fleets let EMR select from several instance types:
{
"InstanceTypeConfigs": [
{
"InstanceType": "m5.2xlarge",
"BidPrice": "0.15"
},
{
"InstanceType": "m4.2xlarge",
"BidPrice": "0.12"
},
{
"InstanceType": "c5.2xlarge",
"BidPrice": "0.10"
}
]
}
Providing alternatives can improve capacity availability and reduce cost compared with relying on a single instance type.
Test EMR requests with Apidog
EMR clusters can be expensive to run, so validate your request payloads before using them in a production workflow.
1. Validate cluster configurations
Save cluster templates in Apidog and add tests that check required fields before sending a request:
pm.test('Cluster has required applications', () => {
const config = pm.request.body.toJSON()
const apps = config.Applications.map(a => a.Name)
pm.expect(apps).to.include('Spark')
})
pm.test('Instance types are valid', () => {
const config = pm.request.body.toJSON()
const types = ['m5.xlarge', 'm5.2xlarge', 'm4.xlarge']
pm.expect(types).to.include(config.Instances.MasterInstanceType)
})
2. Validate step definitions
Test that a Spark step uses the expected command and arguments:
pm.test('Spark step has valid args', () => {
const step = pm.request.body.toJSON().Steps[0]
const args = step.HadoopJarStep.Args
pm.expect(args[0]).to.eql('spark-submit')
pm.expect(args).to.include('--deploy-mode')
})
3. Store environment variables
Keep environment-specific values out of request bodies:
AWS_REGION: us-east-1
EMR_SERVICE_ROLE: EMR_DefaultRole
EMR_EC2_ROLE: EMR_EC2_DefaultRole
S3_LOG_BUCKET: my-emr-logs
S3_SCRIPTS_BUCKET: my-emr-scripts
Test AWS APIs with Apidog - free
Common errors and fixes
ValidationError: ServiceRole is not valid
Cause: The IAM service role does not exist or is not configured for EMR.
Fix: Create the service role in IAM or use the AWS default role:
EMR_DefaultRole_V2
Failed to provision EC2 instances
Cause: The selected instance type is unavailable in the Availability Zone, or your account has reached a service limit.
Fix:
- Use instance fleets with multiple instance types.
- Request a service limit increase.
- Select different instance types.
Step failed with application exit code 1
Cause: The Spark or Hadoop application failed.
Fix:
- Check the EMR step status.
- Open the S3 location configured by
LogUri. - Review
stderrandstdoutfor the failed step. - Reproduce the job with the same input paths and arguments if needed.
Cluster stuck in STARTING
Cause: Bootstrap actions failed or the cluster does not have required permissions.
Fix:
- Check the EC2 instance console output.
- Verify that bootstrap scripts are accessible in S3.
- Verify that the EC2 instance profile has S3 access.
Alternatives and comparisons
| Feature | AWS EMR | Google Dataproc | Azure HDInsight | Databricks |
|---|---|---|---|---|
| Managed Hadoop/Spark | ✓ | ✓ | ✓ | Spark only |
| AWS integration | Excellent | Limited | Limited | Good |
| Serverless option | EMR Serverless | Dataproc Serverless | Limited | ✓ |
| Cost | Spot support | Preemptible VMs | Spot instances | Good |
| ML support | EMR Studio | Vertex AI | Synapse | MLflow built-in |
EMR provides deep AWS integration. Databricks offers stronger Spark tooling. Dataproc can be a better fit for GCP users.
Real-world use cases
Data lake ETL
A retail company processes daily sales data. An EMR cluster reads CSV files from S3, transforms them with Spark, and writes Parquet files to a data lake. The cluster runs for two hours each day and then terminates.
Log analytics
A SaaS company processes application logs from S3. Spark aggregates metrics and writes results to a data warehouse. Auto-scaling adds task nodes when log volume increases.
Machine learning pipelines
A data science team trains models on EMR. Spark reads feature data from S3, trains models with MLlib, and exports results to SageMaker for serving.
Wrap up
You can use the EMR API and AWS CLI to:
- Create clusters with the
RunJobFlowAPI - Submit Spark or Hive work as steps
- Configure auto-scaling policies
- Monitor execution with EMR APIs and CloudWatch
- Control costs with Spot instances and transient clusters
A practical next-step checklist:
- Set up IAM roles for EMR.
- Create a small test cluster.
- Submit a simple Spark job.
- Review logs in S3.
- Add scaling and cost controls after validating the workload.
Test AWS APIs with Apidog - free
FAQ
What’s the difference between primary, core, and task nodes?
- Primary: Runs cluster management services such as YARN ResourceManager and HDFS NameNode.
- Core: Runs data processing and stores HDFS data.
- Task: Runs data processing only and does not store HDFS data. This makes task nodes suitable for Spot instances.
How do I SSH into the primary node?
aws emr ssh --cluster-id j-ABC123DEF456 --key-pair-file my-key.pem
Can I run Jupyter notebooks on EMR?
Yes. Use EMR Studio, enable the JupyterHub application, or use EMR Notebooks.
What is EMR Serverless?
EMR Serverless is a serverless option for submitting Spark and Hive jobs without managing clusters. You pay per job run, which can be useful for sporadic workloads.
How do I read from DynamoDB?
Use the DynamoDB connector:
spark-submit --conf spark.hadoop.dynamodb.servicename=dynamodb \
--conf spark.hadoop.dynamodb.input.tableName=MyTable \
--conf spark.hadoop.dynamodb.output.tableName=MyTable \
--conf spark.hadoop.dynamodb.region=us-east-1 \
my-job.jar
What release label should I use?
Use the latest stable release label that is compatible with your applications, such as emr-7.x for Spark 3.x. Keep versions consistent across environments and check application compatibility in the release notes.
How do I troubleshoot failed steps?
- Check the step status:
aws emr describe-step
- Review S3 logs:
s3://your-log-bucket/logs/j-ABC123/steps/s-DEF123/
- SSH to the primary node and inspect logs:
/mnt/var/log/

Top comments (0)