SaaS subscription stack (WorkOS + Datadog on AWS)¶
Source: examples/saas-subscription-api.yaml
To check and price this model from a clone of the repository:
infra-cost-model validate examples/saas-subscription-api.yaml
infra-cost-model compute --time-basis monthly examples/saas-subscription-api.yaml
# Example: SaaS subscription stack (WorkOS + Datadog on AWS)
# Demonstrates: SaaS vendors priced from vendor price rows
# (infra_cost_model/vendors/workos and infra_cost_model/vendors/datadog) next
# to AWS resources, with fixed monthly counts on non-IaC nodes.
#
# Issues: https://github.com/elecnix/infra-cost-model/issues/241,
# https://github.com/elecnix/infra-cost-model/issues/246
version: "1.0"
# The WorkOS and Datadog price rows ship with engine 0.3.0. An older engine
# prices these nodes differently or not at all, so the model states the
# version it needs and the engine refuses rather than reporting a number it
# cannot stand behind.
requiresEngine: ">=0.3.0"
workflow:
name: saas-subscription-api
entry: aws_apigatewayv2_api.public_api
frequency:
unit: perMinute
value: 500
nodes:
aws_apigatewayv2_api.public_api:
nodeType: routing
resourceAddress: aws_apigatewayv2_api.public_api
provider: aws
service: AmazonAPIGatewayHTTP
region: us-east-1
usageMetrics:
requests: { unit: requests, value: 1 }
# An HTTP API has no egress price of its own. AWS bills the response bytes
# as data transfer out to the internet.
data_transfer.public_api_egress:
nodeType: external
resourceAddress: data_transfer.public_api_egress
provider: aws
service: AWSDataTransfer
region: us-east-1
usageMetrics:
internetOutGb: { unit: GB, value: 0.00002 } # 20KB per request
aws_lambda_function.api:
nodeType: compute
resourceAddress: aws_lambda_function.api
provider: aws
service: AWSLambda
region: us-east-1
usageMetrics:
invocations: { unit: requests, value: 1 }
avgDurationMs: { unit: ms, value: 200 }
memoryMb: { unit: MB, value: 256 }
# WorkOS: identity, priced per user, per connection and per feature. These
# are counts, not traffic, so they carry `fixed: true` and their value is a
# monthly total rather than a per-invocation multiplier. The price rows are
# in infra_cost_model/vendors/workos/prices.yaml.
workos_identity:
nodeType: external
resourceAddress: workos_identity
provider: workos
service: WorkOS
region: global
usageMetrics:
# The first 1,000,000 monthly active users are free.
AuthKit-MAU: { unit: users, value: 900000, fixed: true }
# $125 a month for each of the first 15 SSO connections.
SSO-Connection: { unit: connections, value: 2, fixed: true }
# $99 a month for a custom domain.
Custom-Domain: { unit: months, value: 1, fixed: true }
# Datadog: Infrastructure Monitoring Enterprise, $23 per host a month billed
# annually. The price rows are in infra_cost_model/vendors/datadog/prices.yaml.
datadog_observability:
nodeType: external
resourceAddress: datadog_observability
provider: datadog
service: Infrastructure
region: global
usageMetrics:
Infra-Enterprise-Host: { unit: hosts, value: 6, fixed: true }
aws_dynamodb_table.tenants:
nodeType: storage
resourceAddress: aws_dynamodb_table.tenants
provider: aws
service: AmazonDynamoDB
region: us-east-1
usageMetrics:
# This metric counts only the calls over read edges. The API only reads
# tenants, so the table has no write edge and no write metric. A write
# metric here would count no calls, and the engine would warn (#322).
readRequests: { unit: requests, value: 1, edgeType: read }
edges:
# Every response leaves AWS as data transfer out
- from: aws_apigatewayv2_api.public_api
to: data_transfer.public_api_egress
rate: 1
- from: aws_apigatewayv2_api.public_api
to: aws_lambda_function.api
rate: 1
- from: aws_lambda_function.api
to: aws_dynamodb_table.tenants
rate: 1
type: read