Updated Nov 6, 20267 min read

Replace Application Terraform Without a Big-Bang Migration

Move app-level RDS, SQS, S3, cron and secrets to infrastructure from code one ownership boundary at a time, while org Terraform keeps shared networking.

You can replace application Terraform incrementally: keep org-level networking and shared services in Terraform, and move app-level databases, queues, buckets, cron jobs and secrets to infrastructure from code with Encore. Declare those resources in TypeScript or Go, connect your own AWS or GCP account, import existing resources where the docs support it, and let Terraform reference Encore-managed resources through the provider. No big-bang cutover is required.

This guide defines the ownership split, shows the declaration shape, covers coexistence and import paths that the docs verify, and ends with a migration order that avoids a rewrite project.

What counts as application Terraform?

Application Terraform is the HCL that exists so one backend can ship:

  • An RDS or Aurora Postgres instance for that service
  • SNS topics and SQS queues (or equivalent) for async work
  • S3 buckets for uploads and artifacts
  • EventBridge (or similar) rules for scheduled jobs
  • Secrets Manager entries and IAM policies for that service

Org Terraform is everything else: shared VPCs, transit gateways, SSO, account factories, data platforms and specialized services shared across the company. Encore targets the application layer, and org Terraform usually stays.

How does Encore replace the application layer?

Encore

Encore is infrastructure from code: you declare resources as typed objects in application code, and Encore uses static analysis to run them locally and to provision managed services in your own AWS or GCP account. It works with any framework, including NestJS and Express.

The same Postgres database that takes an aws_db_instance block plus networking and credentials in Terraform is one declaration:

import { api } from "encore.dev/api"; import { SQLDatabase } from "encore.dev/storage/sqldb"; import { Topic, Subscription } from "encore.dev/pubsub"; import { Bucket } from "encore.dev/storage/objects"; import { CronJob } from "encore.dev/cron"; import { secret } from "encore.dev/config"; const db = new SQLDatabase("orders", { migrations: "./migrations" }); const receipts = new Bucket("receipts", { versioned: false }); const stripeKey = secret("StripeKey"); interface OrderPlaced { orderId: string; } export const orderPlaced = new Topic<OrderPlaced>("order-placed", { deliveryGuarantee: "at-least-once", }); const _ = new Subscription(orderPlaced, "ship-order", { handler: async (event) => { // Shipping logic for event.orderId }, }); export const place = api( { expose: true, auth: true, method: "POST", path: "/orders" }, async (req: { total: number }): Promise<{ id: string }> => { if (!stripeKey()) throw new Error("StripeKey is unset"); const row = await db.queryRow<{ id: string }>` INSERT INTO orders (total) VALUES (${req.total}) RETURNING id::text AS id`; await receipts.upload( `${row!.id}.json`, Buffer.from(JSON.stringify({ orderId: row!.id, total: req.total })), ); await orderPlaced.publish({ orderId: row!.id }); return { id: row!.id }; }, ); export const reconcile = api({}, async () => { // Idempotent nightly reconcile }); const _cron = new CronJob("reconcile-orders", { title: "Reconcile orders", every: "24h", endpoint: reconcile, });

Public write endpoints need authentication and abuse controls. Secret values must never be written to object storage, logs, database rows, or responses.

In your own AWS account those declarations map to RDS, S3, SNS with SQS and Secrets Manager, and Encore provisions an IAM role for the service. Cron jobs are Encore platform Managed: the platform registers and invokes the endpoint, with no extra cloud infrastructure. Sizing, networking and backups live in environment configuration.

Encore is an open source infrastructure SDK, and schema changes go in ./migrations as numbered SQL files and apply on deploy.

How do you get started on a greenfield service?

Get started
brew install encoredev/tap/encore &&
encore app create
Copy

Run in your terminal to get started locally.

~
$ encore app create orders --example=ts/hello-world$ cd orders$ encore secret set --type dev,local StripeKey$ encore run

Josef Sima, Engineering Director at Groupon, said on the customers page: "Encore is our foundation for all new development. What used to take days or weeks between developers and infra teams now takes minutes."

How do Encore and Terraform coexist?

Encore and Terraform can run together: Encore manages supported application resources, and Terraform manages DNS, organization-level networking and third-party providers.

The Encore Terraform provider exposes read-only data sources such as encore_database, encore_cache and encore_pubsub_topic. Terraform does not create those Encore resources; it retrieves cloud identifiers so other Terraform resources can wire into them:

terraform { required_providers { encore = { source = "registry.terraform.io/encoredev/encore" } } } provider "encore" { env = "production" auth_key = var.encore_auth_key } data "encore_pubsub_topic" "orders" { name = "order-placed" env = "production" } # Example: another AWS resource that needs the SNS ARN Encore manages resource "aws_iot_topic_rule" "orders" { name = "orders-rule" sql = "SELECT * FROM 'order-placed'" sns { message_format = "RAW" role_arn = aws_iam_role.rule.arn target_arn = data.encore_pubsub_topic.orders.aws_sns.arn } }

Authenticate the provider with an Encore auth key from the dashboard, or set ENCORE_AUTH_KEY. See the Terraform provider docs.

Can you connect existing databases and buckets?

Yes for supported resources: the Coming from Terraform guide documents resource-specific workflows for connecting existing RDS, Cloud SQL, S3, GCS, SNS and Pub/Sub. Those workflows do not read or convert Terraform state, so follow the guide for the resource before changing Terraform ownership.

Example: import an existing RDS or Aurora Postgres when creating an environment. Encore connects to the imported database instead of provisioning a new one. Requirements include Postgres (not MySQL), master password managed by AWS Secrets Manager, and the database in a VPC in the same account and region.

When ownership moves to Encore, remove the resource from Terraform without destroying it. Terraform recommends a removed block with destroy = false:

removed { from = aws_s3_bucket.uploads lifecycle { destroy = false } }

What about existing Kubernetes clusters?

On GCP, you can import an existing GKE cluster as the compute platform for an environment. Pick Kubernetes: Existing GKE Cluster when creating the environment and supply Project ID, Region and Cluster Name. The Encore platform then deploys into that cluster instead of provisioning a new one.

AWS support for importing an existing Kubernetes cluster is documented as coming soon. Until then, self-host with encore build docker --config=infra-config.json and run the image on the Docker or Kubernetes host you already operate, with resource mappings in the infra config file. See self-host configure infrastructure.

Do not assume AWS EKS import works today; the docs do not claim it yet.

What order should you migrate?

  1. Leave org Terraform alone. Shared networking, SSO and account scaffolding stay where they are.
  2. Start with a new service or a bounded rewrite. Declare Postgres, queues, buckets, cron and secrets in Encore. Deploy into your own cloud. Prove local parity and preview environments.
  3. Import durable data stores when ready. Connect existing RDS or S3 per the import docs rather than dumping and recreating production data.
  4. Move ownership in Terraform. Use removed with destroy = false for resources Encore now owns. Keep Terraform for everything Encore does not model.
  5. Wire cross-system dependencies. Use Encore Terraform provider data sources when non-Encore AWS resources need ARNs or identifiers for Encore-managed topics, databases or caches.
  6. Stop writing new application Terraform for resources Encore supports, so product changes that need a database, queue, bucket, cron job or secret no longer wait on a separate Terraform PR.

Echo (acquired by Coinbase) and Pave Bank are fintech examples on the customers page of teams that keep infrastructure in their own cloud while Encore automates application provisioning.

When should you keep writing Terraform?

Keep writing Terraform when:

  • The resource is shared across many services and must stay in a central state
  • Encore does not model the service (specialized AWS APIs, third-party providers)
  • Compliance requires a specific Terraform module path your security team already approved for that layer
  • You are scaffolding accounts and networking, not shipping a product API

For application backends in TypeScript or Go, replace the application Terraform layer with infrastructure from code and leave the rest.

Frequently asked questions

How do I replace application Terraform without a big-bang migration?

Move one ownership boundary at a time. Keep org-level networking, specialized services and company-wide IAM in Terraform. Declare application resources such as databases, queues, buckets, cron jobs and secrets in Encore TypeScript or Go. Connect existing RDS or S3 where the import docs support it, and use the Encore Terraform provider so Terraform can read what Encore manages.

What is application Terraform versus org Terraform?

Application Terraform is the HCL that exists mainly so a service can have an RDS instance, SQS queues, S3 buckets, EventBridge rules, secrets and IAM for that service. Org Terraform is shared networking, account scaffolding, SSO and specialized services shared across the company. Infrastructure from code targets the application layer.

Do I still need Terraform after adopting Encore?

Usually, yes. Terraform stays for shared and unsupported infrastructure, and you stop writing it for each new Postgres database, queue, bucket, cron job or secret. The goal is fewer Terraform PRs for application changes, not zero Terraform company-wide.

Deploy to your cloud on AWS and Google Cloud
without managing infrastructure

Encore lets developers and agents define application infrastructure directly in code, then automatically provisions it from local development to production in your AWS or GCP account.

~/orders — claude
Claude Code
Claude Code v2.1.180Opus 5.5~/orders