Alright, let’s talk about EFS, or Elastic File System. Think of it as the grown-up, cloud-native answer to the classic NFS share you’d cobble together in a server room. You know the one—constantly running out of space, performance is a crapshoot, and its uptime depends on a single physical box and your team’s willingness to answer 3 a.m. pages. EFS takes that concept, throws out the physical hardware, and gives you a managed, highly available, and scaling network file system that can be accessed by thousands of EC2 instances, Lambda functions, and on-prem servers (via Direct Connect or VPN) simultaneously. It’s NFS for the cloud era, and it’s almost magic. Almost.

The killer feature, the one that makes me actually recommend it, is its multi-AZ nature right out of the box. You create an EFS file system, and Amazon automatically replicates its data across every Availability Zone in your chosen region. Every mount target you create (one per AZ, in the VPC subnet of your choice) gives you a front door to that same, consistent dataset. This means an EC2 instance in us-east-1a and another in us-east-1b can read and write to the exact same files at the same time. It’s trivial to set up truly stateless, horizontally scaling web servers that share application code, upload directories, or session data. Try doing that with an EBS volume.

Mounting Your Fancy New File System

You’ve created the file system in the AWS console—easy enough. Now, let’s get an EC2 instance connected to it. The key here is the mount helper. Amazon provides a package that makes this a one-liner, and you should use it. It handles all the messy NFSv4.1 protocol stuff for you.

First, on your Amazon Linux 2 or 2023 instance, install the sucker:

sudo dnf install -y amazon-efs-utils

Now, create a directory to mount it to and use the mount command with the helper. You’ll need your File System ID (fs-12345678) and an AZ-specific mount target DNS name, which the helper can actually figure out for you automatically (see, handy!).

sudo mkdir /mnt/my-shared-data
sudo mount -t efs -o tls fs-12345678:/ /mnt/my-shared-data

That’s it. The -o tls option tells it to encrypt data in transit, which you should always, always do. Check it with df -hT, and you’ll see your new terabyte-scale file system ready for action. For a permanent mount, you’ll want to add an entry to /etc/fstab. The best practice is to use the _netdev option so the system doesn’t hang on boot waiting for a network resource that might not be available yet.

# Add this line to /etc/fstab
fs-12345678:/ /mnt/my-shared-data efs _netdev,tls 0 0

Performance and Pricing: The Catch(es)

Here’s where the designers made some… interesting choices. EFS has two performance modes: generalPurpose (default) and maxIO. For probably 99% of workloads, you want generalPurpose. It provides lower latency and is sensible. maxIO trades latency for higher overall throughput and is basically only for massively parallel, throughput-hungry workloads like big data processing. It’s a sledgehammer; don’t use it unless you’re sure you need it.

Then there’s throughput modes. This is the real kicker. The default and most common is “Bursting”. Your file system earns throughput credits based on its size (a frankly absurd 50 MiB/s per TiB of data stored). A tiny 100 GiB file system gets a measly 5 MiB/s baseline. It can burst to 100+ MiB/s, but only for short periods before it exhausts its credits and throttles you back to that pathetic baseline. This is the number one cause of “EFS is so slow!” complaints. Someone mounts a 50 GiB file system for their web application’s upload directory, a user drops a 2GB file, and the whole thing grinds to a halt. The solution? Use the “Provisioned Throughput” mode. You pay a extra for a fixed MiB/s rate, independent of your storage size. It costs more, but it’s predictable. Or, just make your file system larger. It’s a weird tax, but it’s the reality.

The Lifecycle Management Gambit

This is a genuinely great feature. EFS can automatically move files you haven’t accessed for a set period (say, 30, 60, or 90 days) into the EFS Infrequent Access (IA) storage class. It’s the same data, in the same file system, but it costs significantly less to store. The trade-off is a cost to retrieve each GB of data you read from IA. The magic is it’s transparent to your applications; they just see the file, albeit with a small latency hit on first access.

You enable it with a lifecycle policy. This is a no-brainer for archives, old project data, or logs you might need to look at once a year. Just be honest with yourself about the access patterns. If your app is constantly re-reading the same old config file, the retrieval costs will eat you alive.

# Use the AWS CLI to add a lifecycle policy
# This moves files not accessed in 30 days to IA
aws efs put-lifecycle-configuration \
    --file-system-id fs-12345678 \
    --lifecycle-policies "TransitionToIA=AFTER_30_DAYS"

So, when do you use it? For shared Linux code bases, central configuration management, log aggregation from multiple hosts, or home directories for a fleet of instances. When do you avoid it? For high-performance, low-latency databases (use EBS), or for a single-instance boot volume (that’s just weird). It’s a brilliant tool, but like any brilliant tool, you have to understand its quirks—especially its performance model—or it will bite you.