Terraform Search vs AzAPI capabilities

Terraform Search vs AzAPI capabilities

terraform query compared with azapi_resource_list.

Terraform Search vs AzAPI capabilities

Terraform’s search / list feature promises a declarative way to discover existing infrastructure and (optionally) generate resource + import blocks so you can adopt it under Terraform.

How does this compare to the features in the AzAPI provider (notably azapi_resource_list)?

If this post feels like déjà vu - you might be thinking of a similar post I did about Terraform Actions vs Resource Actions. There certainly are interesting parallels!

TL;DR

  • Terraform search / list — declarative discovery via new files (.tfquery.hcl) and a new workflow terraform query; geared to generate configuration + imports. Very limited AWS-only coverage at the time of writing.

  • AzAPI azapi_resource_list — a Terraform data source that lists Azure resources in-scope; use plain HCL to iterate/filter (optionally, with more expressive filtering support using JMESPath). Full coverage for any Azure resource via the control plane API.

Terraform search / list (.tfquery.hcl) — generate config + imports

Terraform Search introduces a declarative approach to discovering existing resources.

Instead of manually importing or scanning, you define what you want to list in a .tfquery.hcl file — for example, “all S3 buckets” or “all virtual networks.”

Running terraform query executes those definitions, optionally generating ready-to-use resource stubs. The result is a repeatable discovery-and-scaffold workflow that helps you bring unmanaged infrastructure under Terraform control.

Minimal .tfquery.hcl example (see HashiCorp docs):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# example.tfquery.hcl

provider "aws" {
  region = "us-east-1"
}

list "aws_instance" "all_vms" {
  provider = aws

  # Optionally, can use a config block to filter
  config {
    filter {
      name   = "tag:Environment"
      values = ["dev"]
    }
  }
  
}

Run with the query workflow:

1
2
terraform query # or...
terraform query -generate-config-out=vms.tf

Notes:

  • The feature is expressed as a separate query workflow (terraform query) and can produce output with -generate-config-out. The generated code is a useful scaffold, but is not error-free (unsure if this is because this is in beta)
  • Provider-specific config is set inside the config {} block of the list query and you must reference the provider explicitly.
  • As with all discovery flows, start narrow (resource-group/parent scope) to avoid huge result sets and API-rate limits. A limit property can restrict the returned results.

I’m not sure about the separate workflow at the moment; I can see some benefits to assess compliance or IaC blind spots in your infra. I’m curious where HashiCorp take this (my guess is it enables aspects of Project Infragraph).


Compare to AzAPI

AzAPI introduced azapi_resource_list as a normal Terraform data source, back in late 2023.

It’s no different to any other data source - plugs into your existing .tf files,

  1. pick a type (ARM resource type + API version),
  2. scope it with a parent_id (subscription / resource group / resource),
  3. iterate over data.azapi_resource_list.<name>.value with HCL (for / if) to extract the fields you need.

Example — list VM names in a resource group

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
data "azapi_client_config" "current" {}

data "azapi_resource_list" "vms_rg" {
  type      = "Microsoft.Compute/virtualMachines@2025-04-01"
  parent_id = "/subscriptions/${data.azapi_client_config.current.subscription_id}/resourceGroups/my-rg"
}

output "vm_names" {
  value = [for r in data.azapi_resource_list.vms_rg.output.value : r.name]
}

This calls the VM list API for the resource group and uses a simple HCL for expression to return name.

Unlike terraform query, since these are simply data sources, you can reference these in other aspects of your solution as well.

ARM list calls can return many objects, when dealing with large numbers of objects, choosing an appropriate parent_id can reduce the chance of hitting rate limits.

Simple filtering can just use standard HCL constructs:

1
2
3
4
5
6
locals {
  prod_vms = [
    for vm in data.azapi_resource_list.vms_rg.output.value :
      vm if lookup(vm.tags, "environment", "") == "production"
  ]
}

JMESPath filtering

AzAPI additionally supports JMESPath expressions, to give you more flexibility, for example:

  • Large or deeply nested responses (avoid pulling full payloads into HCL),

  • Uses projection to return exactly the structure you want

  • Performance/clarity (smaller, more targeted outputs).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
data "azapi_resource_list" "acr" {
  type      = "Microsoft.ContainerRegistry/registries@2025-05-01-preview"
  parent_id = "/subscriptions/${data.azapi_client_config.current.subscription_id}"

  response_export_values = {
    registries = "value[].{name: name, loginServer: properties.loginServer, sku: sku.name}"
  }
}

output "acr_summary" {
  value = data.azapi_resource_list.acr.output.registries
}
1
2
3
4
5
6
7
8
Changes to Outputs:
  + acr_summary = [
      + {
          + loginServer = "crmyregistry01.azurecr.io"
          + name        = "crmyregistry01"
          + sku         = "Premium"
        },
    ]

Resource creation

Whilst azapi_resource_list doesn’t itself generate resource + import stubs the way terraform query / .tfquery.hcl can, there are several well-established alternatives that can fill this gap, here’s some examples from Microsoft and the broader community

Azure Export for Terraform (aztfexport) — generate config + import blocks

If you want a higher-level “export everything I select” flow, Microsoft maintains aztfexport (Azure Export for Terraform). It can query resources, generate Terraform configuration and (optionally) produce import.tf blocks or run terraform import for you. See the repository and releases.

Highlights:

  • Can target groups, subscriptions or queries and export to azurerm or azapi provider formats.
  • Has options to generate import blocks (--generate-import-block) and various output options. It is useful for bulk onboarding where you want both HCL and state.
  • Limitations and caveats are documented in the project (it is not a perfect reproduction tool — review generated code before applying).

VS Code and the Microsoft Terraform extension

The Microsoft Terraform extension provides autocompletion, validation and schema-aware editing.

You can use it to paste resources from the portal in JSON form, and it will convert them to AzAPI.

screenshot showing json resource converted to AzAPI resource

This extension also integrates with aztfexport.

Terraformer

Terraformer (GitHub - GoogleCloudPlatform/terraformer) and similar tools can generate .tf and .tfstate by calling provider APIs and producing HCL. They support many providers and have different filtering/formatting options.

Caveats

In nearly all cases, generated code is rarely perfect — always review and test before production use.

Conclusion

Terraform Search/List isn’t available in the azurerm provider. If you need discovery now, AzAPI’s azapi_resource_list gives you similar capabilities across all Azure resources, with a native HCL workflow and optional JMESPath filtering.

You don’t have to choose: azapi works alongside azurerm capabilities.

Give it a try, and add a little discovery to your Azure tooling today.

If you’ve experimented with terraform query or AzAPI’s resource_list, I’d love to hear what workflows you’re finding useful.

References

This post is licensed under CC BY 4.0 by the author.