Skip to content

BYO Infrastructure

ThinkWork creates all its infrastructure by default, but most production teams already have a VPC, a database, and an identity system. Rather than creating parallel infrastructure, ThinkWork can adopt yours.

Every major infrastructure component has a create_* flag and a corresponding existing_* variable. Set create_vpc = false and provide existing_vpc_id, and ThinkWork deploys into your VPC instead of creating one.

The most common scenario: you already have a VPC with private subnets and NAT gateways, and you want ThinkWork to deploy into it.

terraform.tfvars
create_vpc = false
existing_vpc_id = "vpc-0a1b2c3d4e5f67890"
# Provide at least 2 private subnets for Aurora and Lambda
existing_private_subnet_ids = [
"subnet-0a1b2c3d4e5f67890",
"subnet-0b2c3d4e5f6789012"
]
# Provide at least 2 public subnets for the NAT gateway (if already exists)
existing_public_subnet_ids = [
"subnet-0c3d4e5f678901234",
"subnet-0d4e5f6789012345"
]
# If you have an existing NAT gateway, specify its ID
# existing_nat_gateway_id = "nat-0a1b2c3d4e5f67890"

Your existing VPC must have:

  • At least 2 private subnets in different AZs (for Aurora Multi-AZ and Lambda ENIs)
  • At least 2 public subnets in different AZs (for load balancers, if used)
  • DNS resolution and DNS hostnames enabled on the VPC
  • Outbound internet access from private subnets (NAT gateway or VPC endpoints)
  • Inbound HTTPS (443) from 0.0.0.0/0 to public subnets (for API Gateway and CloudFront origins)

If you have an existing Aurora Postgres or RDS Postgres cluster, ThinkWork can use it instead of creating a new one.

terraform.tfvars
create_database = false
existing_db_host = "mydb.cluster-xyz.us-east-1.rds.amazonaws.com"
existing_db_port = 5432
existing_db_name = "thinkwork"
existing_db_username = "thinkwork_app"
db_password = "your-existing-db-password"
# The Lambda security group needs access to your DB security group
existing_db_security_group_id = "sg-0a1b2c3d4e5f67890"
RequirementDetails
EnginePostgres 15+ or Aurora Postgres 15+
Min storage20 GB
Extensionspgvector, uuid-ossp, pg_trgm
ConnectivityPrivate subnet, accessible from Lambda security group

To enable required extensions (run once as a superuser):

CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "pg_trgm";
CREATE EXTENSION IF NOT EXISTS "vector";

ThinkWork runs migrations via a Lambda function invoked during deploy. The migration runner uses the db_password variable to connect. After initial deploy, schema changes in subsequent ThinkWork versions are applied automatically on thinkwork deploy -s <stage>.

To preview schema changes before applying, use thinkwork plan -s <stage> — it prints the Terraform plan including any migration Lambda invocations.

If your team already uses Cognito for authentication, ThinkWork can attach to your existing user pool.

terraform.tfvars
create_cognito = false
existing_user_pool_id = "us-east-1_ABC123XYZ"
existing_user_pool_arn = "arn:aws:cognito-idp:us-east-1:123456789012:userpool/us-east-1_ABC123XYZ"
existing_identity_pool_id = "us-east-1:12345678-abcd-efgh-ijkl-123456789012"
# ThinkWork will create a new app client in your existing pool
# unless you provide an existing one
# existing_user_pool_client_id = "1abc2def3ghi4jkl"

Your existing user pool must have:

  • Email as a required attribute
  • Username or email sign-in enabled
  • ALLOW_USER_SRP_AUTH and ALLOW_REFRESH_TOKEN_AUTH auth flows enabled
  • A compatible password policy (ThinkWork enforces minimum 8 characters)
# terraform.tfvars — full BYO configuration
stage = "prod"
region = "us-east-1"
account_id = "123456789012"
# Bring your own network
create_vpc = false
existing_vpc_id = "vpc-0a1b2c3d4e5f67890"
existing_private_subnet_ids = ["subnet-aaa", "subnet-bbb"]
existing_public_subnet_ids = ["subnet-ccc", "subnet-ddd"]
# Bring your own database
create_database = false
existing_db_host = "prod.cluster-abc.us-east-1.rds.amazonaws.com"
existing_db_port = 5432
existing_db_name = "thinkwork_prod"
existing_db_username = "thinkwork"
db_password = "secure-password-here"
existing_db_security_group_id = "sg-0a1b2c3d4e5f"
# Bring your own Cognito
create_cognito = false
existing_user_pool_id = "us-east-1_PROD123"
existing_user_pool_arn = "arn:aws:cognito-idp:us-east-1:123456789012:userpool/us-east-1_PROD123"
existing_identity_pool_id = "us-east-1:prod-identity-pool-id"
# ThinkWork still creates: AppSync, API Gateway, Lambda, S3, Step Functions,
# CloudFront, KMS, SES, Bedrock KB (backed by Aurora pgvector), EventBridge, IAM

You can mix and match. A common pattern for teams migrating to ThinkWork:

# Bring your existing VPC and Cognito, but let ThinkWork create the database
create_vpc = false
existing_vpc_id = "vpc-existing"
# ... subnet IDs ...
create_cognito = false
existing_user_pool_id = "us-east-1_existing"
# ... other Cognito vars ...
# Database: let ThinkWork create Aurora (default behavior)
create_database = true
db_password = "new-password-for-thinkwork-db"
database_engine = "aurora-serverless"

If your private subnets have no NAT gateway, enable VPC endpoints so Lambda functions can reach AWS services privately:

create_vpc_endpoints = true
# Creates Interface endpoints for: Bedrock, BedrockRuntime, S3, STS,
# Cognito, AppSync, DynamoDB, SecretsManager, SSM, ECR, Logs