Lately, I’ve been chipping away at a fun little side project: building out my own self-managed development environment using Terraform Stacks. The idea is to bring automation and structure to how I deploy and manage Azure, Auth0, and Entra ID — treating my own infrastructure with the same level of rigor I’d expect on a real dev team. And honestly, it’s been pretty satisfying… until I had to import an Auth0 resource.

My Terraform Stack Setup

Everything in my environment — resource groups in Azure, app registrations in Entra ID, and APIs in Auth0 — is managed through a single Terraform Stack. It’s elegant in theory: a shared stack file defines variables and behaviors across environments, letting me deploy the same infrastructure to both dev and prod with only a change in context. It’s helped me keep things DRY and consistent.

As part of this setup, I wanted to manage an Auth0 API (technically a “resource server”) that I had manually created earlier during prototyping. Since I was just getting started with the auth0 provider, I did the first round of provisioning in the Auth0 dashboard, just to see how things worked.

The First Import

Once I was confident that I understood how Auth0 resources worked, I added the following to my Terraform stack file to import the existing API into Terraform’s state:

import {
  to = auth0_resource_server.backend
  id = var.auth0.audience
}

resource "auth0_resource_server" "backend" {
  name       = "${var.application_name}-${var.environment_name}"
  identifier = var.auth0.audience
}

In my dev environment, this worked beautifully.

The plan succeeded. Terraform recognized the existing resource and even updated it to align with my naming conventions. I had that satisfying moment where my manual work was now fully owned by code.

And Then… Production

But then I tried to run a plan for prod, where the Auth0 resource didn’t yet exist. That’s when I hit a brick wall.

Terraform tried to run the same import block and bombed out with a classic, scary error:

Error: While attempting to import an existing object to "auth0_resource_server.backend", the provider detected that no object exists with the given id. Only pre-existing objects can be imported; check that the id is correct and that it is associated with the provider's configured region or endpoint, or use "terraform apply" to create a new remote object for this resource.

This was expected behavior, but frustrating all the same. Terraform doesn’t provide a way to scope import blocks to specific environments. So even though I only wanted the import to run in dev, it ran in prod too—and failed. Hard.

There’s no built-in conditional logic for import blocks, no environment guards, nothing. The only real option is to tolerate the error during plan and push forward.

The GitOps Compromise

This approach, while technically functional, definitely breaks the GitOps vibe I was going for. Normally, my flow is clean: write code, open a PR, run plan, approve, merge, done. But when I have an import block in the mix, the plan fails in any environment where the resource doesn’t exist yet.

To get around it, I had to break my flow:

  1. Add the import block.
  2. Commit and push to a feature branch.
  3. Watch as plans fail in prod.
  4. Manually run terraform apply only in dev to import the resource.
  5. Then open a second PR to remove the import block once it’s no longer needed.

This kind of temporary change feels pretty awkward in version-controlled infrastructure. If I were on an actual team, submitting a PR like this would raise red flags. Reviewers would see failed plans and either block the PR or have to understand that it’s supposed to fail in non-target environments. They’d need to trust that I’m only running the apply in the right place at the right time. That’s a lot of implicit trust for what’s basically a one-off housekeeping task.

Conclusion

This experience revealed an interesting friction point in Terraform Stacks: importing existing resources doesn’t align well with multi-environment workflows, especially when you’re trying to keep things clean and automated.

My side project is still moving forward, and I’m glad I figured out how to bring my Auth0 resources under Terraform control — but the process was definitely messier than I’d like. I think there should be a better way to specify which deployment the import block targets. In fact, all refactoring blocks should probably add a deployment-target meta-argument when working with Terraform Stacks. This might be challenging as these refactoring blocks are also supported by Terraform CLI.

It’s a reminder that day-two operations in infrastructure as code often require a bit of improvisation. Even in a solo project, with full control over environments and commits, there are moments when you have to bend the rules.

Ideally, future versions of Terraform — or wrapper tooling around Stacks — will provide more graceful ways to handle environment-specific imports. Until then, a little bit of manual discipline and cleanup will have to do.