Skip to content

Terraform Provider

The DataRecs Terraform provider (terraform-provider-datarecs) manages 14 resource types and one data source. It is not yet published to the Terraform/OpenTofu registry — install it locally via dev_overrides until that changes.

Clone terraform-datarecs-config, build the binary, and point Terraform at it directly — no required_providers block or registry lookup involved while using dev_overrides:

Terminal window
git clone https://github.com/datarecs/terraform-datarecs-config
cd terraform-datarecs-config
go build -o terraform-provider-datarecs
~/.terraformrc
provider_installation {
dev_overrides {
"registry.terraform.io/datarecs/datarecs" = "/absolute/path/to/terraform-datarecs-config"
}
direct {}
}

With dev_overrides active, Terraform uses the local binary for any config referencing datarecs/datarecs and skips version/lock-file checks entirely — omit required_providers, or it will be ignored anyway. tofu plan/tofu apply will print a warning noting the override is in effect; that’s expected.

provider "datarecs" {
api_key = var.datarecs_api_key
host = "https://api.datarecs.io" # optional — this is already the default
}
ParameterDescriptionDefault
api_keyA DataRecs API key. Also settable via DATARECS_API_KEY.Required
hostThe DataRecs API base URL. Also settable via DATARECS_HOST.https://api.datarecs.io

All 14 resources below are generated directly from the provider’s schema (go generate ./...tfplugindocs), so this list can’t silently drift out of sync with the code. Each shows required attributes, notable optional ones, and any RequiresReplace (in-place update not supported — Terraform destroys and recreates) caveat.

resource "datarecs_workspace" "production" {
name = "production"
}

Required: name. Optional: description, metadata (map), settings (map). Read-only: id, slug, version.

resource "datarecs_api_key" "ci" {
name = "ci-pipeline"
scopes = [datarecs_workspace.production.id]
permissions = ["view_job", "run_job", "view_job_results"]
}

Required: name. Optional: description, metadata, scopes (workspace IDs, or ["*"] for tenant-wide), permissions (lowercase snake_case strings, e.g. view_job/run_job — not the TypeScript enum’s PascalCase member names), expiry_time. scopes and permissions both RequiresReplace — narrowing/widening access means a new key. See Managing API Keys for the full permission model and the 6 permissions that can never be granted to a key.

resource "datarecs_connection" "warehouse" {
name = "warehouse-postgres"
type = "postgres"
workspace_id = datarecs_workspace.production.id
credentials = {
host = "warehouse.internal"
port = "5432"
database = "analytics"
username = var.db_username
password = var.db_password
}
}

Required: name, type, credentials (map, sensitive), workspace_id. Optional: description, metadata, workspace_ids (sharing; defaults to [workspace_id]). Read-only: id, config, version. type and workspace_id RequiresReplace; credentials updates in place (how you rotate a password). See Creating a Connection for the credentials shape per connector type.

resource "datarecs_job" "daily_check" {
name = "daily-balance-check"
workspace_id = datarecs_workspace.production.id
dimensions = ["region"]
measures = [{ name = "amount", aggregation = "SUM" }]
connections = [
{
connection_id = datarecs_connection.source_a.id
source_schema = "public"
source_table = "orders"
column_mapping = { region = "region" }
},
{
connection_id = datarecs_connection.source_b.id
source_schema = "public"
source_table = "orders"
column_mapping = { region = "region" }
}
]
stages = [
{
dimensions = ["region"]
tolerances = [{ measure_name = "amount", type = "ABSOLUTE", value = 0.01 }]
}
]
}

Required: name, workspace_id, dimensions, measures ({name, aggregation}), connections ({connection_id, source_schema, source_table, column_mapping}, optional filters/source_database), stages ({dimensions, tolerances}). Optional: stage_execution_strategy, max_stage_concurrency, notification_emails, email_detail_level, max_email_rows. See Configuring a Reconciliation Job for every field.

resource "datarecs_job_schedule" "nightly" {
job_id = datarecs_job.daily_check.id
workspace_id = datarecs_workspace.production.id
cron_expression = "0 2 * * *"
timezone = "UTC"
}

Required: job_id, workspace_id, cron_expression (5-field cron). Optional: enabled (default true), timezone (default UTC).

resource "datarecs_job_group" "finance" {
name = "finance-reconciliations"
workspace_id = datarecs_workspace.production.id
job_ids = [datarecs_job.daily_check.id]
}

Required: name, workspace_id, job_ids. Optional: description.

resource "datarecs_webhook_endpoint" "slack" {
url = "https://hooks.example.com/datarecs"
description = "Slack failure alerts"
rate_limit_rps = 10
}

Required: url (HTTPS). Optional: description, enabled, rate_limit_rps (default 50), payload_format (standard/slack/teams/custom), payload_template, header_template, content_type. Read-only: id, signing_secret (sensitive, populated only on creation), version. See Using Webhooks and Customising Webhook Payloads.

resource "datarecs_webhook_subscription" "run_complete" {
endpoint_id = datarecs_webhook_endpoint.slack.id
event_types = ["reconciliation.run.completed", "reconciliation.run.errored"]
}

Required: endpoint_id, event_types (unprefixed dotted strings; ["*"] for all; supports prefix patterns like "reconciliation.*"). Optional: enabled, filters (map).

resource "datarecs_webhook_secret" "slack_token" {
endpoint_id = datarecs_webhook_endpoint.slack.id
name = "slack_token"
value = var.slack_token
}

Required: endpoint_id (RequiresReplace), name (RequiresReplace, must match ^[A-Za-z_][A-Za-z0-9_]*$), value (sensitive — referenced from payload/header templates as {{ secrets.<name> }}). The plaintext value is never persisted to Terraform state — only its SHA-256 digest (value_sha256) is, which is what drives rotation detection. Rotate by changing value.

resource "datarecs_email_settings" "tenant" {
email_detail_level = "STAGE_SUMMARY"
allow_workspace_override = true
}

A singleton — exactly one per tenant. Required: email_detail_level (DISABLED/STATUS_ONLY/STAGE_SUMMARY/FULL_DATA), allow_workspace_override. Optional: max_email_rows (default 25, max 1000), template_footer_text, template_legal_disclaimer. No import support.

resource "datarecs_email_recipient_rule" "team_domain" {
rule_type = "DOMAIN"
pattern = "*@acme.com"
}

Required: rule_type (EXACT/DOMAIN/WILDCARD), pattern. Optional: description. Rules are immutable server-side — changing rule_type, pattern, or description destroys and recreates. No import support.

resource "datarecs_encryption_key" "byok" {
gcp_project_id = var.gcp_project_id
keyring_name = "datarecs-tenant-keyring"
key_name = "datarecs-tenant-key"
}

Required: gcp_project_id, keyring_name, key_name. Read-only: encryption_mode, kms_key_uri, migration_status, tenant_service_account. See Bring your own key.

resource "datarecs_storage_bucket" "byos" {
gcp_project_id = var.gcp_project_id
bucket_name = "acme-datarecs-artifacts"
bucket_region = "us-central1"
}

Required: gcp_project_id, bucket_name, bucket_region. Read-only: migration_status, storage_mode, storage_provider, tenant_service_account. See Bring your own storage.

resource "datarecs_oidc_connector" "github_actions" {
name = "github-actions"
issuer_url = "https://token.actions.githubusercontent.com"
audience = "https://api.datarecs.io/${data.datarecs_tenant_info.current.tenant_id}"
permissions = ["view_job", "run_job"]
claim_conditions = [
{
claim_name = "repository"
operator = "equals"
expected_value = "acme/data-pipelines"
}
]
}

Required: name, issuer_url, audience, permissions, claim_conditions (at least one; each {claim_name, operator, expected_value}, operator one of equals/starts_with/ends_with/contains/matches). Read-only: status, created_at, updated_at. Enables keyless CI/CD authentication via OIDC federation — no long-lived API key stored in your CI provider.

data "datarecs_tenant_info" "current" {}
output "tenant_id" {
value = data.datarecs_tenant_info.current.tenant_id
}

Read-only: id, tenant_id, gcp_project_id, tenant_service_account. Useful for building an OIDC connector’s audience (above) or referencing your tenant’s service account without hardcoding it.

ResourceImport support
datarecs_workspace, datarecs_api_key, datarecs_connection, datarecs_job, datarecs_job_schedule, datarecs_job_group, datarecs_webhook_endpoint, datarecs_webhook_subscription, datarecs_webhook_secret, datarecs_encryption_key, datarecs_storage_bucket, datarecs_oidc_connectorYes
datarecs_email_settings, datarecs_email_recipient_ruleNo — create these as new Terraform-managed resources
Terminal window
tofu import datarecs_workspace.production <workspace-id>
tofu import datarecs_connection.warehouse <connection-id>
tofu import datarecs_webhook_endpoint.slack <endpoint-id>
VariableDescription
DATARECS_API_KEYAPI key (alternative to the provider’s api_key argument)
DATARECS_HOSTAPI host (alternative to the provider’s host argument). This is the provider’s own variable — the CLI’s equivalent is DATARECS_API_URL, a different name for a different tool.