Getting Started
This guide matches the README quickstart for the 0.28.x line. TerraDart is alpha — breaking changes land only on minor bumps; see Status & versioning for the change policy and the path to beta.
Prerequisites
Section titled “Prerequisites”- Dart SDK ≥ 3.6
- Terraform CLI ≥ 1.11.0
- Credentials for your target provider (e.g. Google Cloud Application Default Credentials
gcloud auth application-default login, or provider environment variables)
1. Add dependencies
Section titled “1. Add dependencies”Choose terradart_core along with the provider factory package(s) your stack requires:
dependencies: terradart_core: ^0.28.x terradart_google: ^0.28.x # for Google Cloud (GA) # terradart_google_beta: ^0.28.x # for Google Cloud beta-only resources # terradart_appwrite: ^0.28.x # for Appwrite # terradart_cloudflare: ^0.28.x # for Cloudflare edge infrastructureCheck pub.dev for the latest patch, then run:
dart pub getThe GA hashicorp/google catalog is filled. Beta-only types live in terradart_google_beta (128 resource factories). terradart_appwrite is filled at the current pin (38 resource factories + 24 data sources). terradart_cloudflare is filled at cloudflare/cloudflare 5.23.0 (257 resource factories + 446 data sources).
2. Define a Stack
Section titled “2. Define a Stack”Create lib/orders_stack.dart (or follow the pubsub quickstart):
import 'package:terradart_core/terradart_core.dart';import 'package:terradart_google/provider.dart';import 'package:terradart_google/pubsub.dart';
final class OrdersStack extends Stack { OrdersStack({required String projectId}) : super(providers: [GoogleProvider(project: projectId)]) { final topic = add(GooglePubsubTopic( localName: 'orders', name: TfArg.literal('orders-prod'), )); addExport('ORDERS_TOPIC_NAME', ResourceIdExport(topic.nameRef)); setAppExportsOutputPath('lib/generated/orders_stack.app.dart'); }}3. Synth Terraform JSON
Section titled “3. Synth Terraform JSON”From bin/infra.dart:
import 'package:my_pkg/orders_stack.dart';
Future<void> main() async { final stack = OrdersStack(projectId: 'YOUR-PROJECT-ID'); await stack.writeTo('tf-out');}dart run bin/infra.dartThis writes tf-out/main.tf.json and, when exports are literal-resolvable, lib/generated/orders_stack.app.dart.
4. Plan and apply
Section titled “4. Plan and apply”cd tf-outterraform initterraform planterraform applyYour existing remote state backend and modules stay unchanged — TerraDart only replaces HCL/JSON authoring.
5. The boundary (optional)
Section titled “5. The boundary (optional)”Import generated constants in app code instead of string literals:
import 'generated/orders_stack.app.dart';
bool acceptsTopic(String eventTopic) => eventTopic == OrdersStackExports.ORDERS_TOPIC_NAME;Rename orders-prod in the Stack without updating the subscriber and dart analyze fails. See Architecture — AppExport and the runnable pubsub quickstart (lib/subscriber_stub.dart).
6. Composing GA and Beta providers (Firebase + Google Cloud)
Section titled “6. Composing GA and Beta providers (Firebase + Google Cloud)”You can seamlessly combine Google Cloud GA resources (terradart_google) with beta-only resources (terradart_google_beta, such as Firebase project configuration and Web App registration) in a single Stack:
graph TB
subgraph Client["Firebase App (Beta)"]
WebApp["GoogleFirebaseWebApp<br/>(Frontend Client)"]
end
subgraph GCP["Google Cloud Infrastructure (GA)"]
CloudRun["GoogleCloudRunV2Service<br/>(Backend API)"]
Firestore["GoogleFirestoreDatabase<br/>(Native Mode / (default))"]
Storage["GoogleStorageBucket<br/>(User Uploads)"]
CloudRun -->|Read/Write Data| Firestore
CloudRun -->|Store Assets| Storage
end
WebApp -.REST API Calls.-> CloudRun
dependencies: terradart_core: ^0.28.x terradart_google: ^0.28.x terradart_google_beta: ^0.28.ximport 'package:terradart_core/terradart_core.dart';// GA: Google Cloud backend infrastructureimport 'package:terradart_google/cloud_run.dart';import 'package:terradart_google/firestore.dart';import 'package:terradart_google/provider.dart';import 'package:terradart_google/storage.dart';// Beta: Firebase project and app registrationimport 'package:terradart_google_beta/firebase.dart';import 'package:terradart_google_beta/provider.dart';
final class MobileAppBackendStack extends Stack { MobileAppBackendStack({required String projectId}) : super( providers: [ GoogleProvider(project: projectId, region: 'asia-northeast1'), GoogleBetaProvider(project: projectId, region: 'asia-northeast1'), ], ) { // 1. [Beta] Enable Firebase on the project final fb = add(GoogleFirebaseProject( localName: 'firebase', project: TfArg.literal(projectId), ));
// 2. [Beta] Register Firebase client app add(GoogleFirebaseWebApp( localName: 'web_client', displayName: TfArg.literal('Web Client'), project: TfArg.literal(projectId), dependsOn: [fb], ));
// 3. [GA] Firestore Database (Native mode) final db = add(GoogleFirestoreDatabase( localName: 'db', name: TfArg.literal('(default)'), locationId: TfArg.literal('asia-northeast1'), type: TfArg.literal(FirestoreDatabaseType.firestoreNative), dependsOn: [fb], ));
// 4. [GA] Cloud Storage for user uploads final uploadsBucket = add(GoogleStorageBucket( localName: 'uploads', name: TfArg.literal('$projectId-uploads'), location: TfArg.literal('ASIA-NORTHEAST1'), storageClass: TfArg.literal(BucketStorageClass.standard), uniformBucketLevelAccess: TfArg.literal(true), ));
// 5. [GA] Cloud Run v2 backend service add(GoogleCloudRunV2Service( localName: 'api', name: TfArg.literal('api-server'), location: TfArg.literal('asia-northeast1'), template: CloudRunV2ServiceTemplate( containers: [ CloudRunV2ServiceServiceContainer( name: TfArg.literal('server'), image: TfArg.literal( 'us-docker.pkg.dev/cloudrun/container/hello', ), env: [ CloudRunV2ServiceEnvVar( name: TfArg.literal('UPLOAD_BUCKET'), source: CloudRunV2ServiceEnvVarFromLiteral( TfArg.ref(uploadsBucket.nameRef), ), ), ], ), ], ), dependsOn: [db], )); }}Wrappers from terradart_google_beta automatically attach provider = "google-beta" in the synthesized Terraform JSON. See the complete runnable recipe in cookbook/firebase-app-backend.
Every factory also takes a provider: parameter — Terraform’s provider meta-argument. Register a second configuration of a provider with alias: and select it per resource; everything else keeps using the default configuration:
final class MultiRegionStack extends Stack { MultiRegionStack({required String projectId}) : super(providers: [ GoogleProvider(project: projectId, region: 'asia-northeast1'), GoogleProvider(alias: 'eu', project: projectId, region: 'europe-west1'), ]) { add(GoogleStorageBucket( localName: 'assets_eu', name: TfArg.literal('my-app-assets-eu'), location: TfArg.literal('EUROPE-WEST1'), provider: 'google.eu', // provider = google.eu )); }}Synth emits provider.google as a list when a name has more than one configuration, and rejects a provider: that matches no registered configuration. provider: 'google-beta' on a GA-catalog factory puts that one resource on the beta provider.
Next steps
Section titled “Next steps”- Why TerraDart — motivation and comparisons
- Architecture —
synth(),writeTo(), curated coverage - Coverage — every curated factory, its barrel, and runnable examples
- Migrating — read before every minor bump
- Status & versioning — alpha vs beta vs 1.0
- Examples and cookbook for fuller stacks