Create AWS FSx for NetApp ONTAP File Systems

The aws:fsx/ontapFileSystem:OntapFileSystem resource, part of the Pulumi AWS provider, provisions FSx for NetApp ONTAP file systems with configurable deployment topology, HA pairs, and throughput capacity. This guide focuses on three capabilities: multi-AZ high availability deployment, HA pair scaling for capacity and performance, and Gen2 architecture for higher throughput.

FSx ONTAP file systems run in VPC subnets and require appropriate subnet placement for the chosen deployment type. The examples are intentionally small. Combine them with your own VPC infrastructure, security groups, and backup configuration.

Deploy a multi-AZ file system for high availability

Enterprise workloads requiring continuous availability deploy FSx ONTAP across multiple availability zones, providing automatic failover during AZ outages.

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

const test = new aws.fsx.OntapFileSystem("test", {
    storageCapacity: 1024,
    subnetIds: [
        test1.id,
        test2.id,
    ],
    deploymentType: "MULTI_AZ_1",
    throughputCapacity: 512,
    preferredSubnetId: test1.id,
});
import pulumi
import pulumi_aws as aws

test = aws.fsx.OntapFileSystem("test",
    storage_capacity=1024,
    subnet_ids=[
        test1["id"],
        test2["id"],
    ],
    deployment_type="MULTI_AZ_1",
    throughput_capacity=512,
    preferred_subnet_id=test1["id"])
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := fsx.NewOntapFileSystem(ctx, "test", &fsx.OntapFileSystemArgs{
			StorageCapacity: pulumi.Int(1024),
			SubnetIds: pulumi.StringArray{
				test1.Id,
				test2.Id,
			},
			DeploymentType:     pulumi.String("MULTI_AZ_1"),
			ThroughputCapacity: pulumi.Int(512),
			PreferredSubnetId:  pulumi.Any(test1.Id),
		})
		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 test = new Aws.Fsx.OntapFileSystem("test", new()
    {
        StorageCapacity = 1024,
        SubnetIds = new[]
        {
            test1.Id,
            test2.Id,
        },
        DeploymentType = "MULTI_AZ_1",
        ThroughputCapacity = 512,
        PreferredSubnetId = test1.Id,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.fsx.OntapFileSystem;
import com.pulumi.aws.fsx.OntapFileSystemArgs;
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 test = new OntapFileSystem("test", OntapFileSystemArgs.builder()
            .storageCapacity(1024)
            .subnetIds(            
                test1.id(),
                test2.id())
            .deploymentType("MULTI_AZ_1")
            .throughputCapacity(512)
            .preferredSubnetId(test1.id())
            .build());

    }
}
resources:
  test:
    type: aws:fsx:OntapFileSystem
    properties:
      storageCapacity: 1024
      subnetIds:
        - ${test1.id}
        - ${test2.id}
      deploymentType: MULTI_AZ_1
      throughputCapacity: 512
      preferredSubnetId: ${test1.id}

The deploymentType property controls availability architecture. MULTI_AZ_1 places file system components in two subnets across different AZs. The preferredSubnetId specifies which subnet hosts the primary file server. When an AZ fails, FSx automatically fails over to the standby in the other AZ. The throughputCapacity property sets total file system throughput in MBps.

Scale capacity with multiple HA pairs

As data volumes grow, adding HA pairs increases both storage capacity and throughput by distributing workload across independent pairs.

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

const testhapairs = new aws.fsx.OntapFileSystem("testhapairs", {
    storageCapacity: 2048,
    subnetIds: [test1.id],
    deploymentType: "SINGLE_AZ_1",
    haPairs: 2,
    throughputCapacityPerHaPair: 128,
    preferredSubnetId: test1.id,
});
import pulumi
import pulumi_aws as aws

testhapairs = aws.fsx.OntapFileSystem("testhapairs",
    storage_capacity=2048,
    subnet_ids=[test1["id"]],
    deployment_type="SINGLE_AZ_1",
    ha_pairs=2,
    throughput_capacity_per_ha_pair=128,
    preferred_subnet_id=test1["id"])
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := fsx.NewOntapFileSystem(ctx, "testhapairs", &fsx.OntapFileSystemArgs{
			StorageCapacity: pulumi.Int(2048),
			SubnetIds: pulumi.StringArray{
				test1.Id,
			},
			DeploymentType:              pulumi.String("SINGLE_AZ_1"),
			HaPairs:                     pulumi.Int(2),
			ThroughputCapacityPerHaPair: pulumi.Int(128),
			PreferredSubnetId:           pulumi.Any(test1.Id),
		})
		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 testhapairs = new Aws.Fsx.OntapFileSystem("testhapairs", new()
    {
        StorageCapacity = 2048,
        SubnetIds = new[]
        {
            test1.Id,
        },
        DeploymentType = "SINGLE_AZ_1",
        HaPairs = 2,
        ThroughputCapacityPerHaPair = 128,
        PreferredSubnetId = test1.Id,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.fsx.OntapFileSystem;
import com.pulumi.aws.fsx.OntapFileSystemArgs;
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 testhapairs = new OntapFileSystem("testhapairs", OntapFileSystemArgs.builder()
            .storageCapacity(2048)
            .subnetIds(test1.id())
            .deploymentType("SINGLE_AZ_1")
            .haPairs(2)
            .throughputCapacityPerHaPair(128)
            .preferredSubnetId(test1.id())
            .build());

    }
}
resources:
  testhapairs:
    type: aws:fsx:OntapFileSystem
    properties:
      storageCapacity: 2048
      subnetIds:
        - ${test1.id}
      deploymentType: SINGLE_AZ_1
      haPairs: 2
      throughputCapacityPerHaPair: 128
      preferredSubnetId: ${test1.id}

The haPairs property specifies how many HA pairs to deploy. Each pair operates independently, so two pairs double your effective capacity and throughput. When using haPairs, you must specify throughputCapacityPerHaPair instead of throughputCapacity. This example deploys two HA pairs in a single AZ, each with 128 MBps throughput, for 256 MBps total.

Deploy Gen2 architecture for higher performance

Gen2 deployment types provide higher throughput per HA pair and support more HA pairs than Gen1 architectures.

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

const testmultiazgen2 = new aws.fsx.OntapFileSystem("testmultiazgen2", {
    storageCapacity: 1024,
    subnetIds: [
        test1.id,
        test2.id,
    ],
    deploymentType: "MULTI_AZ_2",
    haPairs: 1,
    throughputCapacityPerHaPair: 384,
    preferredSubnetId: test1.id,
});
import pulumi
import pulumi_aws as aws

testmultiazgen2 = aws.fsx.OntapFileSystem("testmultiazgen2",
    storage_capacity=1024,
    subnet_ids=[
        test1["id"],
        test2["id"],
    ],
    deployment_type="MULTI_AZ_2",
    ha_pairs=1,
    throughput_capacity_per_ha_pair=384,
    preferred_subnet_id=test1["id"])
package main

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

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := fsx.NewOntapFileSystem(ctx, "testmultiazgen2", &fsx.OntapFileSystemArgs{
			StorageCapacity: pulumi.Int(1024),
			SubnetIds: pulumi.StringArray{
				test1.Id,
				test2.Id,
			},
			DeploymentType:              pulumi.String("MULTI_AZ_2"),
			HaPairs:                     pulumi.Int(1),
			ThroughputCapacityPerHaPair: pulumi.Int(384),
			PreferredSubnetId:           pulumi.Any(test1.Id),
		})
		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 testmultiazgen2 = new Aws.Fsx.OntapFileSystem("testmultiazgen2", new()
    {
        StorageCapacity = 1024,
        SubnetIds = new[]
        {
            test1.Id,
            test2.Id,
        },
        DeploymentType = "MULTI_AZ_2",
        HaPairs = 1,
        ThroughputCapacityPerHaPair = 384,
        PreferredSubnetId = test1.Id,
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.fsx.OntapFileSystem;
import com.pulumi.aws.fsx.OntapFileSystemArgs;
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 testmultiazgen2 = new OntapFileSystem("testmultiazgen2", OntapFileSystemArgs.builder()
            .storageCapacity(1024)
            .subnetIds(            
                test1.id(),
                test2.id())
            .deploymentType("MULTI_AZ_2")
            .haPairs(1)
            .throughputCapacityPerHaPair(384)
            .preferredSubnetId(test1.id())
            .build());

    }
}
resources:
  testmultiazgen2:
    type: aws:fsx:OntapFileSystem
    properties:
      storageCapacity: 1024
      subnetIds:
        - ${test1.id}
        - ${test2.id}
      deploymentType: MULTI_AZ_2
      haPairs: 1
      throughputCapacityPerHaPair: 384
      preferredSubnetId: ${test1.id}

MULTI_AZ_2 is a Gen2 deployment type that supports higher per-pair throughput values. Gen2 architectures use different throughput tiers: 384, 768, 1536, 3072, and 6144 MBps per HA pair, compared to Gen1’s 128-4096 MBps range. This example deploys one HA pair with 384 MBps throughput across two AZs.

Beyond these examples

These snippets focus on specific file system features: multi-AZ and single-AZ deployment types, HA pair scaling and Gen2 architecture, and throughput capacity configuration. They’re intentionally minimal rather than full storage deployments.

The examples reference pre-existing infrastructure such as VPC subnets in appropriate availability zones. They focus on configuring the file system rather than provisioning the surrounding network infrastructure.

To keep things focused, common file system patterns are omitted, including:

  • Security groups and network access control (securityGroupIds)
  • Route table configuration (routeTableIds)
  • Backup scheduling and retention (automaticBackupRetentionDays, dailyAutomaticBackupStartTime)
  • Encryption keys and admin passwords (kmsKeyId, fsxAdminPassword)
  • IOPS configuration (diskIopsConfiguration)

These omissions are intentional: the goal is to illustrate how each file system feature is wired, not provide drop-in storage modules. See the FSx ONTAP File System resource reference for all available configuration options.

Let's create AWS FSx for NetApp ONTAP File Systems

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

Try Pulumi Cloud for FREE

Frequently Asked Questions

Deployment & Architecture
What deployment types are available for FSx ONTAP file systems?
Four deployment types are supported: MULTI_AZ_1, MULTI_AZ_2, SINGLE_AZ_1, and SINGLE_AZ_2. Multi-AZ deployments require 2 subnets, while single-AZ deployments require 1 subnet. The deployment type is immutable after creation.
How many HA pairs can I configure?
For SINGLE_AZ_1, MULTI_AZ_1, and MULTI_AZ_2 deployments, you can configure 1 HA pair. For SINGLE_AZ_2 deployments, you can configure 1 to 12 HA pairs.
What's the difference between single-AZ Gen1 and Gen2 deployments?
SINGLE_AZ_2 (Gen2) supports up to 12 HA pairs and higher storage capacity (up to 1PB), while SINGLE_AZ_1 (Gen1) supports only 1 HA pair with lower capacity limits. Gen2 also uses different throughput values per HA pair.
How many subnets do I need?
Multi-AZ deployments (MULTI_AZ_1, MULTI_AZ_2) require 2 subnets, while single-AZ deployments (SINGLE_AZ_1, SINGLE_AZ_2) require 1 subnet. You must also specify a preferredSubnetId.
Performance & Capacity
What are the storage capacity limits for each deployment type?

Storage limits vary by deployment type:

  • SINGLE_AZ_1 and MULTI_AZ_1: 1024 to 196608 GiB
  • MULTI_AZ_2: 1024 to 524288 GiB
  • SINGLE_AZ_2: 1024 to 1048576 GiB (1PB), but the 1PB maximum requires 2 or more HA pairs; with 1 HA pair, the maximum is 524288 GiB (512TB)
What's the difference between throughputCapacity and throughputCapacityPerHaPair?
throughputCapacity specifies total throughput for the file system and is used when NOT configuring haPairs. throughputCapacityPerHaPair specifies per-HA-pair throughput and is used when configuring haPairs. You must specify one or the other, but not both.
What throughput values are valid for Gen2 deployments?
For MULTI_AZ_2 and SINGLE_AZ_2 with 1 HA pair, valid values are 384, 768, 1536, 3072, and 6144 MBps per HA pair. For SINGLE_AZ_2 with more than 1 HA pair, valid values are 1536, 3072, and 6144 MBps per HA pair.
Configuration & Updates
What properties can't I change after creating the file system?
The following properties are immutable: deploymentType, endpointIpAddressRange, kmsKeyId, preferredSubnetId, subnetIds, securityGroupIds, and storageType.
Why am I seeing a perpetual diff on securityGroupIds after importing?
The securityGroupIds argument cannot be read after creation via the FSx API. On imported resources, Pulumi will always show a difference if this argument is set. Either omit securityGroupIds from your program or use ignore_changes to suppress the diff.
Backups & Maintenance
How do I configure automatic backups?
Set automaticBackupRetentionDays to a value between 1 and 90 (setting it to 0 disables automatic backups). If you want to specify a backup time, also set dailyAutomaticBackupStartTime in HH:MM format, which requires automaticBackupRetentionDays to be configured.
What format should I use for maintenance and backup windows?
Use d:HH:MM format for weeklyMaintenanceStartTime (e.g., 1:03:00 for Monday at 3 AM UTC) and HH:MM format for dailyAutomaticBackupStartTime (e.g., 05:00 for 5 AM daily UTC).

Using a different cloud?

Explore storage guides for other cloud providers: