Updated Nov 5, 20266 min read

What Is an AWS VPC? Subnets, Gateways and Security Groups for Backends

An Amazon VPC is the private network your AWS resources run in. How CIDR ranges, public and private subnets, NAT gateways, security groups and endpoints fit together, and the layout a production backend needs.

An Amazon Virtual Private Cloud (VPC) is the private network that your EC2 instances, Fargate tasks, RDS databases and caches run in. Every AWS account comes with a default VPC in each Region, where every subnet is public, which is fine for experiments and a poor fit for a database holding customer data.

A production backend needs a VPC where the load balancer is reachable from the internet, application containers are not, and databases cannot reach the internet at all. This guide explains the building blocks of a VPC, the standard layout for a backend, and how Encore (infrastructure from code) provisions that layout for each environment.

AWS VPC at a glance

ComponentWhat it doesWhere it shows up in a backend
CIDR blockThe private IP range of the VPC, such as 10.0.0.0/16Must not overlap with networks you peer with
SubnetA slice of the VPC's range in one Availability ZoneOne per tier per AZ
Route tableDecides where traffic from a subnet goesPublic tier routes to the internet gateway
Internet gatewayConnects the VPC to the internetUsed by the load balancer and NAT gateway
NAT gatewayOutbound-only internet access for private subnetsContainers calling third-party APIs
Security groupStateful allow rules on a network interface"Database accepts 5432 from the app only"
Network ACLStateless allow and deny rules on a subnetCoarse guardrails between tiers
VPC endpointPrivate access to AWS services without the internetS3 and DynamoDB gateway endpoints

How a VPC works

A VPC lives in one Region and has a primary IPv4 range chosen when you create it. You divide that range into subnets, and each subnet sits in exactly one Availability Zone, so a highly available setup repeats each tier in at least two zones. The Amazon VPC user guide covers the full model, including IPv6 and multiple ranges.

Whether a subnet is public or private is decided by its route table. A subnet whose table sends 0.0.0.0/0 to an internet gateway is public. A private subnet sends that traffic to a NAT gateway in a public subnet, which lets containers call Stripe or an LLM API while staying unreachable from outside. A subnet with no default route at all is isolated, which is where databases belong.

Security groups attach to network interfaces, hold only allow rules, and can reference other security groups, so a database can accept port 5432 from the application's group without listing IPs. Network ACLs attach to subnets, are stateless and support deny rules, and are commonly used as a second, coarser layer.

Gateway endpoints for S3 and DynamoDB route that traffic through the AWS network instead of the NAT gateway, which keeps bucket traffic private and off the NAT gateway's data processing charges. Other services such as Secrets Manager or SQS use interface endpoints, which place a network interface in your subnets.

The three-tier layout for a backend

Most production backends on AWS converge on the same structure, repeated across two or three Availability Zones:

TierContainsRoute to the internetAccepts traffic from
PublicApplication Load Balancer, NAT gatewayInternet gatewayThe internet on 80 and 443
Private (compute)ECS tasks, EKS nodes, EC2 instancesOutbound through NATThe load balancer
Isolated (storage)RDS, ElastiCacheNoneThe compute tier

Building it by hand means a VPC, six or more subnets, route tables and associations, an internet gateway, NAT gateways with Elastic IPs, security groups per tier and service, and subnet groups for RDS and ElastiCache, which is typically a few hundred lines of Terraform before the first service deploys. Each new environment repeats it with a different CIDR range, and each new database or cache needs its security group rules updated.

How Encore provisions the VPC

Encore

Encore is infrastructure from code for TypeScript and Go, with a platform that provisions and deploys into your own AWS or GCP account. For each environment, Encore creates an isolated VPC spanning two Availability Zones with the three tiers above: a public subnet with the Application Load Balancer, internet gateway and NAT gateway, a compute subnet for Fargate or EKS that accepts traffic only from the load balancer, and a storage subnet with no internet access for databases and caches, as documented in the AWS infrastructure docs.

The Infrastructure page in the Encore dashboard with a database's configuration panel open, showing fields for vCPUs, memory, storage, availability type, max connections and backups.
Each provisioned resource can be reviewed and its configuration edited per environment in the Encore dashboard. The screenshot shows a GCP Cloud SQL database.

Set up the app

Get started
brew install encoredev/tap/encore &&
encore app create
Copy

Run in your terminal to get started locally.

~
$ encore app create inventory --example=ts/empty$ cd inventory && mkdir inventory

The code never mentions subnets or security groups, and a database declared in a service ends up in the storage subnet, reachable from that service's containers:

// inventory/encore.service.ts import { Service } from "encore.dev/service"; export default new Service("inventory");
// inventory/stock.ts import { api } from "encore.dev/api"; import { SQLDatabase } from "encore.dev/storage/sqldb"; // RDS for PostgreSQL in the storage subnet on AWS. const db = new SQLDatabase("inventory", { migrations: "./migrations" }); export const get = api( { expose: true, method: "GET", path: "/stock/:sku" }, async ({ sku }: { sku: string }): Promise<{ sku: string; quantity: number }> => { const row = await db.queryRow<{ quantity: number }>` SELECT quantity FROM stock WHERE sku = ${sku}`; return { sku, quantity: row?.quantity ?? 0 }; }, );
-- inventory/migrations/1_create_stock.up.sql CREATE TABLE stock ( sku TEXT PRIMARY KEY, quantity INTEGER NOT NULL DEFAULT 0 );

encore run starts Postgres locally, and the deploy creates the VPC, subnets, gateways and security groups along with the RDS instance. By default Encore reserves a random /16 private range per environment, and if you plan to peer with an existing network you can set the range when creating the environment, as described in configure network settings. Resource settings are edited per environment in the infrastructure configuration dashboard.

An AI coding agent adding a cache or a second database writes one declaration in TypeScript, and the network placement follows from it.

Connecting the AWS account is a one-time step covered in the own-cloud deployment guide.

Best fit: Teams who want a production VPC layout on AWS for every environment, created from the services they declare.

Good to know

  • Plan CIDR ranges before peering or Transit Gateway, since overlapping ranges cannot be routed between.
  • One NAT gateway per Availability Zone avoids cross-zone traffic and a single point of failure for outbound calls.
  • Security groups referencing other groups survive scaling events, while IP-based rules do not.

Frequently asked questions

What is a VPC in AWS?

An Amazon Virtual Private Cloud is a logically isolated virtual network in one AWS Region. You choose its IP range, split it into subnets in different Availability Zones, and control routing and traffic with route tables, gateways, security groups and network ACLs.

What is the difference between a public and a private subnet?

A public subnet has a route to an internet gateway, so resources with public IPs can be reached from the internet. A private subnet has no such route. Resources there can reach the internet only through a NAT gateway, and cannot be reached from outside.

What is the difference between security groups and network ACLs?

Security groups attach to network interfaces, only allow traffic, and are stateful, so return traffic is allowed automatically. Network ACLs attach to subnets, support allow and deny rules, and are stateless, so inbound and outbound rules must both permit a connection.

How do I get a production VPC for a backend without writing Terraform?

With Encore, you write the backend in TypeScript or Go and declare resources such as new SQLDatabase() in code. When you deploy to your AWS account, Encore creates a VPC per environment across two Availability Zones, with a public subnet for the load balancer, a private compute subnet for your services and an isolated storage subnet for databases.

Deploy to your cloud on AWS and Google Cloud
without managing infrastructure

Encore lets developers and agents define application infrastructure directly in code, then automatically provisions it from local development to production in your AWS or GCP account.

~/orders — claude
Claude Code
Claude Code v2.1.180Opus 5.5~/orders