Pre-alpha

Type-safe IaC for Dart.

Terraform stays. You author in Dart. Define typed GCP resources and emit standard *.tf.json for the terraform apply pipeline you already run.

GCP resources in Dart

Cloud SQL, IAM, and a multi-container Cloud Run service with a cloud-sql-proxy sidecar — the kind of infrastructure you would otherwise maintain in HCL or the console.

// infra/lib/app_infra.dart
// A Stack is one Terraform root module of GCP resources, written in Dart.
import 'package:terradart_core/terradart_core.dart';
import 'package:terradart_google/cloud_run.dart';
import 'package:terradart_google/cloud_sql.dart';
import 'package:terradart_google/iam.dart';
import 'package:terradart_google/provider.dart';

final class AppInfraStack extends Stack {
  AppInfraStack({required String projectId})
      : super(providers: [
          GoogleProvider(project: projectId, region: 'asia-northeast1'),
        ]) {
    add(GoogleSqlDatabaseInstance(
      localName: 'app_sql',
      name: TfArg.literal('app-sql'),
      databaseVersion: TfArg.literal(DatabaseVersion.postgres15),
      region: TfArg.literal('asia-northeast1'),
      settings: SqlDatabaseInstanceSettings(
        tier: TfArg.literal('db-f1-micro'),
      ),
    ));

    final runSa = add(GoogleServiceAccount(
      localName: 'run_sa',
      accountId: TfArg.literal('app-run-sa'),
    ));
    add(GoogleProjectIamMember(
      localName: 'run_sa_sql_client',
      project: TfArg.literal(projectId),
      role: TfArg.literal('roles/cloudsql.client'),
      member: TfArg.ref(runSa.iamMember),
    ));

    add(GoogleCloudRunV2Service(
      localName: 'app',
      name: TfArg.literal('app'),
      location: TfArg.literal('asia-northeast1'),
      template: CloudRunV2ServiceTemplate(
        serviceAccount: TfArg.ref(runSa.email),
        containers: [
          CloudRunV2ServiceServiceContainer(
            name: TfArg.literal('app'),
            image: TfArg.literal('gcr.io/cloudrun/hello'),
            ports: CloudRunV2ServiceContainerPort(
              containerPort: TfArg.literal(8080),
            ),
            env: [
              CloudRunV2ServiceEnvVar(
                name: TfArg.literal('DATABASE_URL'),
                source: CloudRunV2ServiceEnvVarFromLiteral(
                  TfArg.literal(
                    'postgresql://app-client@${projectId}.iam@localhost:5432/app',
                  ),
                ),
              ),
            ],
          ),
          CloudRunV2ServiceServiceContainer(
            name: TfArg.literal('cloud-sql-proxy'),
            image: TfArg.literal(
              'gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.18.1',
            ),
            args: TfArg.literal([
              '--port=5432',
              '--auto-iam-authn',
              '${projectId}:asia-northeast1:app-sql',
            ]),
          ),
        ],
      ),
    ));
  }
}

terradart_google ships a curated subset of the HashiCorp google provider — not every resource type yet. Factories expand release by release; see status and pub.dev. More complete stacks and dogfood patterns live in the cookbook and examples on GitHub (both growing).

A runnable quickstart in examples/ is on the way.

Connect infra and app code with types

A boundary held together by string literals

Topic names in HCL or the console and again in your Cloud Run functions handlers. Renames do not reach subscribers via dart fix. IAM members drift with no compiler visibility. Infra values flowing into app code are often the layer Dart’s type system never sees.

Terraform stays the execution layer

TerraDart is not a parallel runtime. Write Terraform’s resource model as Dart factories and sealed types, then generate *.tf.json for the provider you already use. terraform plan, apply, and remote state stay unchanged.

Dart types where HCL cannot help

Fixed values become enums. Exactly-one-of blocks become sealed classes. Your infra module is a final class … extends Stack — loops, config, and refactors work like any other Dart code.

Read the design rationale →

Where TerraDart fits

TerraDart fits teams already centered on Dart, already running Terraform (or a compatible pipeline) or managing GCP in the console, where the seam between infra and app code hurts.

TerraDartHCLCDKTFPulumi
Dart authoring YesNoNoNo
Drop-in for terraform apply YesYesYesDifferent model
Curated Dart factories for GCP YesNoNoNo
Project status Pre-alphaMatureArchived 2025Active

HCL has provider schema types; CDKTF bindings are typed in TypeScript and other languages. TerraDart’s difference is Dart-native authoring without replacing your Terraform execution pipeline.

See full comparison →

How it works in three steps

Author in Dart

Subclass Stack with curated google_* factories from terradart_google.

Generate Terraform JSON

stack.writeTo(...) writes *.tf.json — no custom apply runtime.

Apply with Terraform

terraform plan and apply unchanged; state stays where it is.

Details: /docs/architecture · README