AWS Lambda VPC Access Explained: Private Subnets, NAT Gateway, and RDS
AWS Lambda runs outside your VPC by default. You only attach it to a VPC when the function must reach private resources — such as an RDS database or ElastiCache cluster — that are not accessible from the public internet. Placing Lambda in a public subnet does not give it internet access. If a VPC-attached Lambda needs to call external APIs, it must be in a private subnet with a NAT Gateway.
Quick answer#
Four things to know before going further:
- Lambda is outside your VPC by default — it cannot reach private resources like RDS without explicit configuration.
- Only enable VPC access when the function genuinely needs it — if it only calls S3, DynamoDB, or public APIs, skip it entirely.
- A public subnet does not give Lambda internet access — Lambda has no public IP, so the Internet Gateway route is useless.
- For outbound internet from a VPC-attached Lambda, use a private subnet and route traffic through a NAT Gateway.
Simple explanation#
Think of your AWS account as an office building. The internet is outside. Your VPC is the building — it has a locked back office where your databases and caches live, and a public lobby with a door to the street.
By default, Lambda is like a remote contractor working from home. They can reach the internet just fine, but the back office is completely off-limits.
When you enable VPC access, Lambda gets a building pass. It can now walk into the back office and talk to your databases. But once it is inside, it cannot walk out the front door on its own — it has to go through the internal mail room (NAT Gateway) to send anything to the internet.
The building pass analogy: Without VPC access, Lambda is a remote contractor — internet access, no building entry. With VPC access, Lambda has a building pass and can reach internal systems. But it cannot use the public front door anymore. Internet traffic has to go through the mail room (NAT Gateway) in the lobby. The mail room holds the building’s public address; individual contractors do not get their own.
Why this matters#
The default Lambda execution environment has outbound internet access. Your function can call external APIs, reach public AWS endpoints, or download data with no networking configuration at all. This covers a large category of functions.
But production architectures typically put databases and caches in private subnets where they are not reachable from the public internet. An RDS PostgreSQL instance in a private subnet cannot be reached from outside the VPC — and if your Lambda function is running outside your VPC, it cannot reach that database either, even though both are in the same AWS account.
Enabling VPC access solves this. Lambda creates Elastic Network Interfaces (ENIs) in the subnets you specify, and your function’s traffic enters the VPC through those ENIs — exactly as if an EC2 instance in those subnets were making the same requests.
How AWS Lambda VPC access works#
When you configure VPC access, you provide three things:
- The VPC ID
- One or more subnets (private subnets, in at least two Availability Zones)
- One or more security groups
Lambda does not create a new ENI for every invocation. It uses a service called Hyperplane to manage a shared pool of ENIs at the VPC level. ENI creation happens when the function is first deployed or when the VPC configuration changes — not when the function is invoked.
This is the change AWS made in 2019 that eliminated the multi-second VPC cold start penalty. Today, VPC cold starts are only a few hundred milliseconds longer than non-VPC cold starts. For more on how Lambda manages concurrency, see Lambda scaling.
Once attached to a VPC, the function’s outbound traffic is governed by the route tables and security groups of the subnets you chose — the same rules that apply to EC2 instances in those subnets.
When to use this#
Enable VPC access when the Lambda function must reach a resource that is only available inside a VPC.
Use VPC access when Lambda needs to connect to:
- RDS or Aurora in a private subnet
- ElastiCache (Redis or Memcached) in a private subnet
- Internal EC2 instances or private services in private subnets
- Internal APIs on ECS or EKS that are not publicly exposed
- On-premises resources accessible through AWS Direct Connect or Site-to-Site VPN
When not to use this#
Do not enable VPC access just because the function is part of a VPC-heavy architecture. It adds operational overhead and can introduce NAT Gateway costs.
Skip VPC access when Lambda only needs to reach:
- Amazon S3 (accessible via public endpoint or S3 VPC endpoint without VPC attachment)
- DynamoDB (same — public endpoint or VPC endpoint)
- External HTTP APIs, with no private VPC resources involved
- Standard AWS service APIs (SQS, SNS, Secrets Manager) reachable from Lambda’s default environment
Rule of thumb: If none of your Lambda’s dependencies live behind a private subnet, you do not need VPC access. Adding it without a reason brings cost and complexity with no benefit.
Lambda in a VPC vs Lambda without VPC access#
| Lambda without VPC | Lambda in VPC, private subnet, no NAT | Lambda in VPC, private subnet + NAT Gateway | |
|---|---|---|---|
| Reaches private RDS / ElastiCache | No | Yes | Yes |
| Outbound internet access | Yes | No | Yes |
| Needs NAT Gateway | No | No | Yes |
| Additional cost | None | None | NAT Gateway hourly + data charges |
| Setup complexity | None | Low | Moderate |
The third column is the most common production setup. The second column works when the function only talks to resources inside the VPC and never needs to call the internet.
Internet access from a VPC-attached Lambda#
When you attach Lambda to a VPC, all outbound traffic routes through that VPC’s networking rules. The default internet access is gone.
The public subnet trap: Placing Lambda in a public subnet does NOT give it internet access. Lambda instances never receive a public IP address, so the Internet Gateway route in a public subnet is useless. This is the single most common Lambda VPC mistake. The fix is to always use a private subnet and route outbound internet traffic through a NAT Gateway.
To restore internet access after enabling VPC, you need:
- A NAT Gateway deployed in a public subnet
- The Lambda function placed in a private subnet
- The private subnet’s route table pointing
0.0.0.0/0to the NAT Gateway
| Lambda placement | Can reach VPC resources? | Can reach internet? |
|---|---|---|
| No VPC (default) | No | Yes |
| VPC, private subnet, no NAT Gateway | Yes | No |
| VPC, private subnet, NAT Gateway configured | Yes | Yes |
| VPC, public subnet | Yes | No — Lambda has no public IP |
See private vs public IP addresses for background on why the public subnet row fails.
Subnets, route tables, and security groups you need#
Subnets#
Use private subnets. Lambda does not accept inbound connections — it is invoked by AWS services, not by clients making direct network requests. Placing Lambda in a public subnet gains nothing and creates the misleading impression of internet access.
Specify at least two subnets in different Availability Zones. Lambda distributes function instances across the AZs you provide. A single AZ limits both availability and concurrency headroom.
AZ requirement: If you only configure one subnet and that AZ experiences an issue, Lambda cannot place new instances elsewhere. Always provide subnets in at least two AZs. See Subnets in AWS for how to identify which subnets are private.
Route tables#
The private subnets where Lambda runs need a route table that:
- Routes local VPC traffic internally (the
localroute — this is automatic) - Routes
0.0.0.0/0to the NAT Gateway if the function needs internet access
If the function only calls resources inside the VPC, no default route is needed. See route tables in AWS for how route table association works.
Security groups#
Assign Lambda a security group that acts as its network identity inside the VPC. Other resources — like RDS — can then reference this security group in their inbound rules instead of trying to track Lambda’s private IPs (which change as the function scales).
For Lambda to connect to RDS PostgreSQL:
- Lambda’s security group: outbound rule allowing TCP on port 5432 to the RDS security group (the default is to allow all outbound)
- RDS’s security group: inbound rule allowing TCP on port 5432 from the Lambda security group
Use the security group ID as the source in the RDS rule — not a CIDR range. Full pattern details in Security Groups Explained.
IAM permissions required#
The Lambda execution role needs permission to create and manage ENIs in your VPC. Without these, the function will fail to initialise.
Required permissions:
ec2:CreateNetworkInterface
ec2:DescribeNetworkInterfaces
ec2:DeleteNetworkInterface
ec2:DescribeSubnets
ec2:DescribeSecurityGroups
ec2:DescribeVpcs
The easiest approach is to attach the AWS managed policy AWSLambdaVPCAccessExecutionRole to the Lambda execution role:
aws iam attach-role-policy \
--role-name my-lambda-execution-role \
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole
See Lambda security model for execution role configuration in more detail.
Step-by-step configuration example#
This covers the most common case: Lambda needs to reach a private RDS database and also call a third-party API on the internet.
Target architecture:
- Lambda: two private subnets, one per AZ
- RDS: two private subnets, one per AZ
- NAT Gateway: one public subnet
- Private subnet route table:
0.0.0.0/0→ NAT Gateway - Security groups: Lambda SG allowed inbound on RDS SG port 5432
Step 1 — Create a Lambda function with VPC access
aws lambda create-function \
--function-name my-vpc-function \
--runtime python3.12 \
--role arn:aws:iam::123456789012:role/lambda-execution-role \
--handler index.handler \
--zip-file fileb://function.zip \
--vpc-config SubnetIds=subnet-private-az1,subnet-private-az2,SecurityGroupIds=sg-lambda-function
Step 2 — Update VPC config on an existing function
aws lambda update-function-configuration \
--function-name my-existing-function \
--vpc-config SubnetIds=subnet-private-az1,subnet-private-az2,SecurityGroupIds=sg-lambda-function
Step 3 — Allow Lambda to connect to RDS
# Add inbound rule to the RDS security group
aws ec2 authorize-security-group-ingress \
--group-id sg-rds-instance \
--protocol tcp \
--port 5432 \
--source-group sg-lambda-function
Step 4 — Remove VPC access (reverts Lambda to default internet access)
aws lambda update-function-configuration \
--function-name my-existing-function \
--vpc-config SubnetIds=[],SecurityGroupIds=[]
After steps 1–3, the function can reach RDS through the security group rule and reach the internet through the NAT Gateway. Both work simultaneously.
Cost and VPC endpoints#
NAT Gateway charges by the hour and by data processed. If your VPC-attached Lambda only needs to reach certain AWS services — S3, DynamoDB, SQS, Secrets Manager — you can use VPC interface or gateway endpoints to keep that traffic inside the AWS network without routing it through the NAT Gateway.
NAT Gateway cost: NAT Gateway is not free. It charges per hour plus per GB of data processed. For Lambda functions that call AWS services heavily (S3, DynamoDB), VPC endpoints eliminate most of that traffic from the NAT Gateway bill. See Lambda Cost Optimisation for specifics.
If the function also calls third-party HTTP APIs, you still need a NAT Gateway for that traffic. VPC endpoints only cover AWS services, not arbitrary internet destinations. See VPC endpoint policies for access control through endpoints.
Common beginner mistakes#
-
Putting Lambda in a public subnet expecting internet access. Lambda instances do not receive public IP addresses, so the Internet Gateway route does nothing for them. Fix: use a private subnet and add a NAT Gateway.
-
Forgetting the NAT Gateway after enabling VPC. Attaching Lambda to a VPC removes its default internet access. If the function calls external APIs or public AWS endpoints, those calls will time out silently. Fix: add a NAT Gateway in a public subnet and update the private subnet route table.
-
Not attaching the VPC IAM policy. Without
ec2:CreateNetworkInterfaceand related permissions, Lambda cannot provision ENIs and the function will fail to initialise. Fix: attachAWSLambdaVPCAccessExecutionRoleto the execution role. -
Specifying only one subnet. A single-AZ Lambda function cannot scale across AZs and is vulnerable to AZ-level issues. Fix: always specify subnets in at least two AZs.
-
Using a CIDR range in the RDS security group inbound rule. Lambda instances do not have stable private IPs. An IP-based rule will break as the function scales. Fix: reference the Lambda security group ID instead.
-
Enabling VPC access when the function does not need it. If the function only calls S3, DynamoDB, or public AWS APIs, VPC access adds NAT Gateway cost and complexity with no benefit. Fix: only enable VPC access when the function genuinely needs a private VPC resource.
Troubleshooting checklist#
Lambda cannot reach RDS:
- Lambda and RDS are in the same VPC
- RDS security group has an inbound rule from the Lambda security group on the correct port (5432 for PostgreSQL, 3306 for MySQL)
- Lambda execution role has
AWSLambdaVPCAccessExecutionRoleattached - Lambda subnets have available IP addresses (low IP count can cause ENI provisioning failures)
Lambda cannot reach the internet:
- Lambda is in a private subnet, not a public subnet
- A NAT Gateway exists in a public subnet in the same VPC
- The private subnet route table has a
0.0.0.0/0route pointing to the NAT Gateway - Lambda’s security group allows outbound traffic on the relevant port (default allows all outbound)
Lambda failing to initialise or timing out at startup:
- Lambda execution role has
AWSLambdaVPCAccessExecutionRoleattached - At least two subnets are specified in different AZs
- The subnets are private subnets (a private subnet has no
0.0.0.0/0route to an Internet Gateway)
For broader VPC connectivity issues, see Troubleshooting Network Issues.
Summary
- Lambda runs outside your VPC by default — it cannot reach private resources like RDS without explicit VPC configuration.
- Only enable VPC access when the function genuinely needs a private VPC resource.
- Always use private subnets in at least two Availability Zones for VPC-attached Lambda functions.
- Placing Lambda in a public subnet does NOT give it internet access — Lambda has no public IP.
- For outbound internet access, add a NAT Gateway in a public subnet and route the private subnet’s traffic through it.
- Use security group-to-security group rules (not IP ranges) for RDS and other resource access.
- Attach
AWSLambdaVPCAccessExecutionRoleto the Lambda execution role — without it, ENI provisioning will fail. - Consider VPC endpoints for AWS service traffic (S3, DynamoDB, SQS) to reduce NAT Gateway costs.
Frequently asked questions
Does Lambda run inside my VPC by default?
No. Lambda functions run in AWS-managed infrastructure that is separate from your VPC. To reach private resources like RDS or ElastiCache, you must explicitly attach the function to a VPC in the Lambda configuration.
Does Lambda in a public subnet have internet access?
No. Even if you place a Lambda function in a public subnet, it does not receive a public IP address. Without a public IP, the Internet Gateway route in the subnet is useless for Lambda traffic. The only way to give a VPC-attached Lambda outbound internet access is through a NAT Gateway in a public subnet, with the Lambda itself in a private subnet.
Do I need a NAT Gateway for Lambda VPC access?
Only if the Lambda function needs to reach the internet or public AWS endpoints after you attach it to a VPC. If the function only calls private resources like RDS or ElastiCache in the same VPC, no NAT Gateway is needed. NAT Gateway carries an ongoing hourly cost, so skip it if the function does not need outbound internet access.
Will putting Lambda in a VPC slow it down?
Barely, in modern AWS. Since 2019, Lambda uses Hyperplane ENIs that are shared at the VPC level rather than created per invocation. VPC cold starts today are typically only a few hundred milliseconds longer than non-VPC cold starts, which is acceptable for most workloads.
Can Lambda reach an RDS database in a private subnet?
Yes, once the Lambda is attached to the same VPC. Place both Lambda and RDS in private subnets, then configure the RDS security group to allow inbound traffic from the Lambda security group on the database port (5432 for PostgreSQL, 3306 for MySQL). No NAT Gateway is needed for Lambda-to-RDS traffic.