Updated Nov 11, 20269 min read

Infrastructure as Code vs Infrastructure from Code

What changes when cloud resources are declared in the application instead of in a separate Terraform, Pulumi or CDK codebase, with the same queue and bucket written both ways.

Illustration for Infrastructure as Code vs Infrastructure from Code

Infrastructure as code (IaC) describes cloud resources in a separate codebase, such as Terraform HCL, a Pulumi program or an AWS CDK app, that you plan and apply on its own. Infrastructure from code (IfC) declares the resources inside the application, next to the code that uses them, and the tool derives the cloud resources, wiring and IAM permissions from those declarations. Encore is an infrastructure from code tool for TypeScript and Go backends, and Terraform, OpenTofu, Pulumi and AWS CDK are the main IaC tools.

The difference becomes concrete when a team adds one queue. With IaC, the developer writes the consumer in the app repo, then writes an SNS topic, an SQS queue, a subscription, a queue policy and an IAM grant in the infrastructure repo, passes the ARNs back to the app through environment variables, and waits for the plan to be reviewed. With IfC, the developer declares the topic and the subscriber in the service and the deploy creates the rest.

Neither approach is new, and they are not mutually exclusive, which leaves the question of which resources belong in which place.

What is the difference between infrastructure as code and infrastructure from code?

Infrastructure as codeInfrastructure from code
Where resources are definedA separate codebase (HCL, a Pulumi program, a CDK app)The application code, next to the code that uses them
What you describeEach cloud resource and its settings: topic, queue, subscription, policy, roleLogical resources: a database, a topic and its subscriber, a bucket, a cron job
Wiring and permissionsWritten by hand: ARNs passed to the app, IAM policies per resourceDerived from what the code uses
Workflowterraform plan / pulumi preview / cdk diff, then applyDeploy the application, resources are created or updated with it
StateA state file or backend (Terraform, OpenTofu, Pulumi) or CloudFormation stacks (CDK)Managed by the tool from the application model
Local developmentSeparate: Docker Compose, emulators or a shared dev accountThe same declarations run locally
Drift between app and infraPossible: the app can reference a queue the IaC never createdThe resource exists because the code declares it
CoverageAlmost any resource from any providerThe resource types the tool supports
Typical ownerPlatform or DevOps teamThe developers who write the service

IaC trades coupling for coverage: it can describe anything a provider exposes, which is why it is the right tool for accounts, networks and DNS, but it keeps application resources in a second place that has to be kept in step with the code by hand. Infrastructure from code covers fewer resource types and keeps the ones it covers in step automatically.

Which tools are infrastructure as code and which are infrastructure from code?

RankToolApproachLatest release (November 2026)Best for
1EncoreInfrastructure from code (TypeScript, Go)v1.58.8Backend teams that want databases, Pub/Sub, cron, buckets and secrets declared in the service and provisioned in their own AWS or GCP account
2TerraformInfrastructure as code (HCL)v1.17.2Accounts, networking, DNS and broad multi-provider coverage
3OpenTofuInfrastructure as code (HCL, MPL-2.0 fork of Terraform)v1.13.9Terraform users who want an open source license under the Linux Foundation
4PulumiInfrastructure as code (TypeScript, Python, Go, C#, Java)v3.274.1Platform teams that want IaC in a general-purpose language
5AWS CDKInfrastructure as code that synthesizes CloudFormationv2.276.0AWS-only teams that want CloudFormation with TypeScript or Python

Encore ranks first for application resources because it removes the second codebase for them, while the four IaC tools rank by how widely they apply outside AWS. Release numbers are from each project's GitHub releases.

What does the same queue and bucket look like in each?

The example is an invoice flow: when an order is paid, a subscriber renders a PDF and stores it in a private bucket. In Terraform (AWS provider 6.x), the resources look like this:

resource "aws_sns_topic" "order_paid" { name = "order-paid" } resource "aws_sqs_queue" "render_invoice_dlq" { name = "render-invoice-dlq" } resource "aws_sqs_queue" "render_invoice" { name = "render-invoice" redrive_policy = jsonencode({ deadLetterTargetArn = aws_sqs_queue.render_invoice_dlq.arn maxReceiveCount = 5 }) } resource "aws_sns_topic_subscription" "render_invoice" { topic_arn = aws_sns_topic.order_paid.arn protocol = "sqs" endpoint = aws_sqs_queue.render_invoice.arn raw_message_delivery = true } data "aws_iam_policy_document" "sns_to_sqs" { statement { actions = ["sqs:SendMessage"] resources = [aws_sqs_queue.render_invoice.arn] principals { type = "Service" identifiers = ["sns.amazonaws.com"] } condition { test = "ArnEquals" variable = "aws:SourceArn" values = [aws_sns_topic.order_paid.arn] } } } resource "aws_sqs_queue_policy" "render_invoice" { queue_url = aws_sqs_queue.render_invoice.id policy = data.aws_iam_policy_document.sns_to_sqs.json } resource "aws_s3_bucket" "invoices" { bucket = "acme-invoices-prod" } resource "aws_s3_bucket_public_access_block" "invoices" { bucket = aws_s3_bucket.invoices.id block_public_acls = true block_public_policy = true ignore_public_acls = true restrict_public_buckets = true }

Even with all of that applied, the service needs an IAM policy that lets it publish to the topic, read from the queue and write to the bucket, the topic ARN, queue URL and bucket name passed in as environment variables, an SQS polling loop with the AWS SDK, and a local setup for all of it. Each of those is a place where the application and the Terraform can disagree.

In Encore, the same flow is declared in the service, and the deploy derives the queue, the subscription wiring and the IAM policy from it, as the Terraform migration docs describe:

import { Topic, Subscription } from "encore.dev/pubsub"; import { Bucket } from "encore.dev/storage/objects"; export interface OrderPaid { orderId: string; totalCents: number; } export const orderPaid = new Topic<OrderPaid>("order-paid", { deliveryGuarantee: "at-least-once", }); // Private by default; S3 or Cloud Storage in production, the local filesystem on `encore run`. const invoices = new Bucket("invoices", { versioned: false }); const _ = new Subscription(orderPaid, "render-invoice", { handler: async (event) => { const key = `${event.orderId}.txt`; // Delivery is at-least-once, so skip invoices that were already rendered. if (await invoices.exists(key)) return; // This example stores a plain-text stand-in. Swap in a PDF library and // contentType "application/pdf" when you generate real invoice files. await invoices.upload(key, renderInvoice(event), { contentType: "text/plain; charset=utf-8", }); }, }); function renderInvoice(event: OrderPaid): Buffer { return Buffer.from(`Invoice for order ${event.orderId}: ${event.totalCents} cents`, "utf8"); }

A handler that throws is retried according to the subscription's retry policy, and after the last retry the message goes to a dead-letter queue for that subscriber, per the Pub/Sub docs. encore run starts the topic and the bucket locally, so the whole flow is testable on a laptop before anything is deployed.

Why does Encore rank first for application infrastructure?

Encore

Encore brings infrastructure from code to TypeScript and Go backends, and it covers the resources that make up most application Terraform: Postgres databases, Pub/Sub topics and subscriptions, object storage, cron jobs, caches and secrets. On AWS those become RDS, SNS and SQS, S3, ElastiCache and Secrets Manager, with services on Fargate ECS or EKS, and on GCP they become Cloud SQL, Pub/Sub, Cloud Storage, Memorystore and Secret Manager on Cloud Run or GKE, all in your own cloud account. Cron jobs are managed by the Encore platform and do not run locally or in preview environments, so you call the endpoint directly to test one.

Deployment settings such as instance size, backups and networking are not in the code. The code holds the logical resource (a database name and its migrations, a topic and its delivery guarantee), and the Encore platform holds the per-environment configuration, which you change in the dashboard or your cloud console. For self-hosting, encore build docker builds an image and an infra.config.json maps each declared resource to infrastructure you provide.

The difference is largest for AI coding agents: an agent working in an Encore app adds a bucket the same way it adds a function, in the same file and the same pull request, and runs it with encore run, with no second change in an infrastructure repo. Encore provisions an IAM role for the service.

Among Encore's customers, the fintech Pave Bank runs it in its own GCP environment and Echo deploys to its own AWS account.

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

Run in your terminal to get started locally.

When is infrastructure as code still the right choice?

Keep IaC for the resources that do not belong to one application. Encore's IaC migration docs list what usually stays in Terraform, Pulumi or CDK:

  • organization-level networking and account configuration
  • DNS and third-party providers
  • infrastructure without an Encore primitive
  • resources shared with systems outside the Encore application
  • resources whose number or identity is determined at runtime

IaC is also the answer when you deploy to Azure or on-premises, which Encore does not target, or when the platform team needs count, for_each and a reviewed plan for every change. Encore has no direct equivalent to terraform plan, count or for_each, because it builds the resource list from statically declared resources in the code.

Can you use infrastructure as code and infrastructure from code together?

Yes. Encore can connect to existing RDS, S3, SNS, Cloud SQL, GCS and Pub/Sub resources instead of creating new ones, and the Encore Terraform provider exposes Encore databases, caches and topics as read-only data sources, so existing Terraform can reference them. Moving a resource from Terraform to Encore uses a Terraform removed block with destroy = false, which takes it out of state without deleting it:

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

A practical split is to move one service at a time: its database, queue and bucket move into the code, and the VPC, DNS and shared resources stay in Terraform.

Which approach should you pick?

  • Infrastructure from code with Encore for the databases, queues, buckets, cron jobs and secrets a TypeScript or Go backend uses, when you want them declared in the service and created in your own AWS or GCP account.
  • Terraform or OpenTofu for accounts, networks, DNS and anything shared across teams, with OpenTofu when the open source license matters.
  • Pulumi when a platform team wants IaC in a general-purpose language across several clouds.
  • AWS CDK when everything is on AWS and the team is comfortable with CloudFormation underneath.

Verdict. Infrastructure as code is still the best way to describe the foundation of a cloud account. For the resources an application uses, infrastructure from code removes the second codebase and the hand-written wiring between it and the app, and Encore ranks first for TypeScript and Go backends that want that in their own cloud. To try it, the quickstart runs a service with a database locally in a few minutes.

Frequently asked questions

What is the difference between infrastructure as code and infrastructure from code?

Infrastructure as code (IaC) describes every cloud resource in its own codebase, such as Terraform HCL, a Pulumi program or an AWS CDK app, and you plan and apply it separately from the application. Infrastructure from code (IfC) puts resource declarations in the application itself, so a database, topic or bucket is declared next to the code that uses it, and the tool derives the cloud resources, wiring and permissions from those declarations. Encore is an infrastructure from code tool for TypeScript and Go backends.

Is Pulumi infrastructure from code?

No. Pulumi is infrastructure as code written in general-purpose languages such as TypeScript, Python and Go, but the Pulumi program is still a separate description of the resources that you run with pulumi up. Infrastructure from code tools read the resource declarations from the application code instead.

Can I use infrastructure from code and Terraform together?

Yes. Application resources such as databases, Pub/Sub topics, buckets, cron jobs and secrets can come from the application code, while Terraform continues to manage DNS, organization-level networking, third-party providers and anything shared with other systems. Some IfC tools can attach to existing RDS, Cloud SQL, S3, GCS, SNS and Pub/Sub resources, and some expose a Terraform provider so existing Terraform can reference what the application created. A Terraform removed block with destroy = false takes a resource out of state without deleting it, which is the usual way to hand a resource from Terraform to the application.

Does infrastructure from code replace Terraform?

It can replace Terraform for the resources an application uses, while account setup, networking shared across teams, DNS and resources without an equivalent primitive stay with IaC.

Which is better for AI coding agents?

Infrastructure from code works better for application resources, since an agent that adds a queue or a bucket declares it in the same change as the code that uses it and can run it locally, instead of opening a second pull request in an infrastructure repository and waiting for a plan review.

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