Skip to main content

Overview

DatabaseFactory builds database resources from a type-safe props object. Each type is a separate overload, so TypeScript narrows the available options as soon as you set type.
For S3 storage buckets, use the StorageFactory instead.

Basic Usage

Database Types

Aurora

Aurora Serverless v2 cluster running PostgreSQL or MySQL:
Behaviour:
  • Serverless v2 writer plus one reader by default. Set readers: false for a single-instance cluster.
  • Storage encrypted at rest, SSL enforced through the parameter group.
  • Deletion protection on, and the removal policy defaults to SNAPSHOT.
  • Enhanced Monitoring on at a one-minute interval, and Database Insights on in standard mode.

RDS Instance

A single database instance for predictable workloads:
Behaviour:
  • Fixed instance size, with storage autoscaling to 500 GiB.
  • Multi-AZ on by default. Pass multiAz: false for a single-AZ instance.
  • IAM database authentication on by default, alongside password auth.
  • t4g.micro is free-tier eligible.

Global Aurora

Multi-region Aurora cluster:
Behaviour:
  • Cross-region replication with low-latency reads in each secondary region.
  • Managed failover to a secondary region.
  • primaryRegion is required. Synth fails without it.

DynamoDB

Serverless key-value and document store:
Behaviour:
  • On-demand billing by default (PAY_PER_REQUEST).
  • Point-in-time recovery on by default.
  • Encrypted with the AWS-managed aws/dynamodb KMS key by default, which bills KMS API requests.
The factory does not configure DynamoDB global tables. For a multi-region relational store, use GlobalAurora.

ClickHouse

Single-node ClickHouse analytics database on EC2 with an ECS task, an EBS data volume and an S3 cold tier:
Behaviour:
  • Database name is fixed at analytics.
  • schemaAdmin is required. Its name must match ^[a-z][a-z0-9_]*$ and must not carry the reserved fjall prefix. Its profile names a key in profiles, or one of the four defaults: high_throughput_ingest, audit_append, read_only, ddl_admin.
  • Scheduled OPTIMIZE TABLE FINAL every 6 hours, plus a daily backup to S3 at 03:00 UTC that restores what it wrote into a scratch database to verify it.
  • storageGb grows only. EBS refuses to shrink a volume and permits one modification per volume per 6 hours.

Configuration Parameters

Defaults the backup tier owns

Four defaults on this page read the application’s backup tier (App.getApp(name, { backup: { tier } })) rather than a fixed value. An application with no backup tier, or backup: false, gets the Standard column. Setting the parameter on the resource overrides the tier for that resource. fjall destroy switches deletion protection off on every database, table and load balancer in a stack before deleting it, so a protected table never wedges a destroy; it only stops a delete that nobody asked for.

Shared (Aurora, Instance, GlobalAurora)

When a proxy fronts the database, clients connect on the engine-default port even if you set a custom port. RDS Proxy has no port parameter.
DatabaseInsightsConfig takes two fields: CredentialsConfig takes username and an opt-in secretRotation block. Rotation resources are created only when you pass an object. secretRotation: { automaticallyAfterDays: 30 } is the scaffolded form.

Cluster (Aurora and Global Aurora)

AuroraReadersConfig takes count (default 1), or a per-reader instances array, plus defaultEnableDatabaseInsights. count and instances are mutually exclusive.

Aurora only

removalPolicy: RemovalPolicy.DESTROY takes the data with it when the stack is deleted. No snapshot, no recovery. Reserve it for disposable dev clusters.
serverlessV2MinCapacity: 0 requires Aurora PostgreSQL 16.3 or later. Synth fails on an older engineVersion.

Global Aurora only

Global Aurora does not accept removalPolicy, engineVersion, or the serverless v2 capacity props.

Instance

ReadReplicaConfig takes instanceType and availabilityZone. The replica inherits the primary’s instanceType when unset. monitoringInterval and preferredMaintenanceWindow are cluster-only props. Instance databases apply the same defaults but expose no override. Aurora and Global Aurora ignore instanceType because their instances are serverless v2.
Multi-AZ is on by default and bills for a standby. Pass multiAz: false for development instances.

DynamoDB

Attribute types are "S" (string), "N" (number) and "B" (binary). encryption and deletionProtection follow the backup tier unless set here.
AWS_MANAGED encrypts with the AWS-managed aws/dynamodb KMS key and bills KMS API requests. AWS_OWNED uses an AWS-owned key at no cost. CUSTOMER_MANAGED encrypts with the stack’s shared customer-managed key (one key per stack, created on first use, about $1–3 a month).

ClickHouse

Changing instanceType or storageGb versions the launch template and triggers an ASG instance refresh. On a single-node cluster that refresh is a restart: data survives, the cluster is unavailable across the window.

Common Patterns

Production Aurora

Development Database

Single-Instance Aurora

Drop the default reader when one writer is enough:

Scale-to-Zero Aurora

Session Store

Accessing Database Information

Relational Databases

getConnectionString() returns <scheme>://<host>:<port>/<dbname> and deliberately excludes credentials. Secrets Manager references cannot be interpolated at synth time without baking plaintext into the CloudFormation template. Compose the final URL at runtime from the injected user and password.

DynamoDB

ClickHouse

Connecting to Compute

Lambda

connections sits at the root of the Lambda props. The factory injects the application VPC automatically when connections are present.

ECS

connections sits on each service inside services[], not at the compute root. Each service gets its own least-privilege grants.

Granting Access

Relational Databases

connections handles security groups and IAM grants. For a manual grant:
grantIamConnect issues short-lived rds-db:connect tokens for a named database user, so the grantee never reads a stored password. It is Instance-only and throws at synth on Aurora or Global Aurora:

DynamoDB

Schema Migrations

A migrations block turns the database into a schema-version gate. Every container of every service whose connections include the database receives EXPECTED_SCHEMA_VERSION at synth time, and eligible services gain a fjall-schema-gate container that verifies the live schema before any application container starts.
tool: "custom" takes the same dir plus a versionResolver: (dir: string) => string. ClickHouse uses its own block with dir and an optional versionResolver, and no tool field. See Deployment safety for the full gate behaviour.

Security

Every database the factory builds arrives with:
  • Encryption at rest. Storage encryption on for relational types, KMS encryption for DynamoDB tables.
  • Encryption in transit. rds.force_ssl=1 for PostgreSQL, require_secure_transport=ON for MySQL.
  • Secrets Manager credentials. Master credentials generated into a secret, never rendered into the template.
  • VPC isolation. Private subnets unless publiclyAccessible is set.
  • Least-privilege security groups. Rules created per connected service, not per cluster.

Best Practices

  1. Use Aurora for variable workloads, Instance for predictable small ones.
  2. Set readers: false on non-production Aurora clusters to halve the instance bill.
  3. Set multiAz: false and deletionProtection: false on development instances.
  4. Set databaseInsights: { mode: "advanced" } in production for 15 months of query history.
  5. Declare connections rather than hand-wiring security groups and IAM.
  6. Declare migrations so a schema mismatch stops the deployment instead of crash-looping.

Next Steps

Aurora Reference

Aurora cluster options in depth

DynamoDB Reference

Table, index and stream configuration

Compute Factory

Deploy Lambda and ECS compute resources

Deployment Safety

Schema gates and destructive-change consent