# Set up Azure AI Search in the AppHost

<Image
  src={searchIcon}
  alt="Azure AI Search logo"
  width={100}
  height={100}
  class:list={'float-inline-left icon'}
  data-zoom-off
/>

This article is the reference for the Aspire Azure AI Search Hosting integration. It enumerates the AppHost APIs — with examples for both `AppHost.cs` and `apphost.mts` — that you use to model an Azure AI Search resource in your [`AppHost`](/get-started/app-host/) project.

If you're new to the Azure AI Search integration, start with the [Get started with Azure AI Search integrations](/integrations/cloud/azure/azure-ai-search/azure-ai-search-get-started/) guide. For how consuming apps read the connection information this page exposes, see [Connect to Azure AI Search](../azure-ai-search-connect/).

## Installation

To start building an Aspire app that uses Azure AI Search, install the [📦 Aspire.Hosting.Azure.Search](https://www.nuget.org/packages/Aspire.Hosting.Azure.Search) NuGet package:

```bash title="Terminal"
aspire add azure-search
```

<LearnMore>
  Learn more about [`aspire add`](/reference/cli/commands/aspire-add/) in the command reference.
</LearnMore>

Or, choose a manual installation approach:

```csharp title="C# — AppHost.cs"
#:package Aspire.Hosting.Azure.Search@*
```

```xml title="XML — AppHost.csproj"
<PackageReference Include="Aspire.Hosting.Azure.Search" Version="*" />
```

```bash title="Terminal"
aspire add azure-search
```

<LearnMore>
  Learn more about [`aspire add`](/reference/cli/commands/aspire-add/) in the command reference.
</LearnMore>

This updates your `aspire.config.json` with the Azure AI Search hosting integration package:

```json title="aspire.config.json" ins={3}
{
  "packages": {
    "Aspire.Hosting.Azure.Search": "13.3.0"
  }
}
```

## Add Azure AI Search resource

Once you've installed the hosting integration in your AppHost project, you can add an Azure AI Search resource as shown in the following examples:

```csharp title="C# — AppHost.cs"
var builder = DistributedApplication.CreateBuilder(args);

var search = builder.AddAzureSearch("search");

builder.AddProject<Projects.ExampleProject>("apiservice")
    .WithReference(search);

// After adding all resources, run the app...
builder.Build().Run();
```
```typescript title="TypeScript — apphost.mts"
import { createBuilder } from './.aspire/modules/aspire.mjs';

const builder = await createBuilder();

const search = await builder.addAzureSearch("search");

await builder.addProject("apiservice", "../ExampleProject/ExampleProject.csproj")
    .withReference(search);

// After adding all resources, run the app...
await builder.build().run();
```
1. When Aspire adds an Azure AI Search resource, it implicitly calls `AddAzureProvisioning`, which adds support for generating Azure resources dynamically during app startup.

1. The app must configure the appropriate Azure subscription and location. For more information, see [Local provisioning: Configuration](/integrations/cloud/azure/local-provisioning/#configuration).

1. The `withReference` call configures a connection in the consuming project named after the referenced search resource, such as `search` in the preceding example.
**Note:** When you reference an Azure AI Search resource from the AppHost, Aspire makes connection properties available to the consuming project. For a complete list of these properties and per-language connection examples, see [Connect to Azure AI Search](../azure-ai-search-connect/).

## Connect to an existing Azure AI Search instance

You might have an existing Azure AI Search service that you want to connect to. Chain a call to mark the resource as existing rather than provisioning a new one:

```csharp title="C# — AppHost.cs"
var builder = DistributedApplication.CreateBuilder(args);

var existingSearchName = builder.AddParameter("existingSearchName");
var existingSearchResourceGroup = builder.AddParameter("existingSearchResourceGroup");

var search = builder.AddAzureSearch("search")
    .AsExisting(existingSearchName, existingSearchResourceGroup);

builder.AddProject<Projects.ExampleProject>("apiservice")
    .WithReference(search);

// After adding all resources, run the app...
builder.Build().Run();
```
```typescript title="TypeScript — apphost.mts"
import { createBuilder } from './.aspire/modules/aspire.mjs';

const builder = await createBuilder();

const existingSearchName = await builder.addParameter("existingSearchName");

const search = await builder.addAzureSearch("search");
await search.asExisting(existingSearchName);

await builder.addProject("apiservice", "../ExampleProject/ExampleProject.csproj")
    .withReference(search);

// After adding all resources, run the app...
await builder.build().run();
```
For more information on treating Azure AI Search resources as existing resources, see [Use existing Azure resources](/integrations/cloud/azure/overview/#use-existing-azure-resources).

## Provisioning-generated Bicep

If you're new to [Bicep](https://learn.microsoft.com/azure/azure-resource-manager/bicep/overview), it's a domain-specific language for defining Azure resources. With Aspire, you don't need to write Bicep by hand; instead, the provisioning APIs generate Bicep for you. When you publish your app, the generated Bicep is output alongside the manifest file. When you add an Azure AI Search resource, Bicep is generated to provision the search service with appropriate defaults.

```bicep title="Generated Bicep — search.bicep"
@description('The location for the resource(s) to be deployed.')
param location string = resourceGroup().location

resource search 'Microsoft.Search/searchServices@2023-11-01' = {
  name: take('search-${uniqueString(resourceGroup().id)}', 60)
  location: location
  properties: {
    hostingMode: 'default'
    disableLocalAuth: true
    partitionCount: 1
    replicaCount: 1
  }
  sku: {
    name: 'basic'
  }
  tags: {
    'aspire-resource-name': 'search'
  }
}

output connectionString string = 'Endpoint=https://${search.name}.search.windows.net'

output name string = search.name
```

The preceding Bicep provisions an Azure AI Search service with `disableLocalAuth: true`, which means authentication uses role-based access (managed identity) rather than API keys by default. Role assignments are created in a separate module:

```bicep title="Generated Bicep — search-roles.bicep"
@description('The location for the resource(s) to be deployed.')
param location string = resourceGroup().location

param search_outputs_name string

param principalType string

param principalId string

resource search 'Microsoft.Search/searchServices@2023-11-01' existing = {
  name: search_outputs_name
}

resource search_SearchIndexDataContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(search.id, principalId, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8ebe5a00-799e-43f5-93ac-243d3dce84a7'))
  properties: {
    principalId: principalId
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8ebe5a00-799e-43f5-93ac-243d3dce84a7')
    principalType: principalType
  }
  scope: search
}

resource search_SearchServiceContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(search.id, principalId, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7ca78c08-252a-4471-8644-bb5ff32d4ba0'))
  properties: {
    principalId: principalId
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7ca78c08-252a-4471-8644-bb5ff32d4ba0')
    principalType: principalType
  }
  scope: search
}
```

The generated Bicep is a starting point and is influenced by changes to the provisioning infrastructure in C#. Customizations to the Bicep file directly will be overwritten, so make changes through the C# provisioning APIs to ensure they are reflected in the generated files.

## Customize provisioning infrastructure

All Aspire Azure resources are subclasses of the `AzureProvisioningResource` type. This type enables the customization of the generated Bicep by providing a fluent API to configure the Azure resources using the `ConfigureInfrastructure` API:

```csharp title="C# — AppHost.cs"
var builder = DistributedApplication.CreateBuilder(args);

builder.AddAzureSearch("search")
    .ConfigureInfrastructure(infra =>
    {
        var searchService = infra.GetProvisionableResources()
                                  .OfType<SearchService>()
                                  .Single();

        searchService.PartitionCount = 6;
        searchService.ReplicaCount = 3;
        searchService.SearchSkuName = SearchServiceSkuName.Standard3;
        searchService.Tags.Add("ExampleKey", "Example value");
    });
```
```typescript title="TypeScript — apphost.mts"
import { createBuilder } from './.aspire/modules/aspire.mjs';

const builder = await createBuilder();

const search = await builder.addAzureSearch("search");
await search.configureInfrastructure(async (infra) => {
    // Customize the provisioning infrastructure here.
    // Changes made via the C# AzureResourceInfrastructure API
    // are accessible through the infra object.
});

await builder.build().run();
```
The preceding C# code:

- Chains a call to the `ConfigureInfrastructure` API:
  - The `infra` parameter is an instance of the `AzureResourceInfrastructure` type.
  - The provisionable resources are retrieved by calling the `GetProvisionableResources` method.
  - The single `SearchService` resource is retrieved.
    - The `PartitionCount` is set to `6`.
    - The `ReplicaCount` is set to `3`.
    - The `SearchSkuName` is set to `Standard3`.
    - A tag is added to the search resource with a key of `ExampleKey` and a value of `Example value`.

For more information, see [Azure.Provisioning customization](/integrations/cloud/azure/customize-resources/#azureprovisioning-customization).

## Role assignments

By default, the Azure AI Search hosting integration generates role assignments for `SearchIndexDataContributor` and `SearchServiceContributor` in the provisioned Bicep. You can customize the roles assigned to a resource:

Role assignments are generated automatically in the provisioned Bicep. To clear the default role assignments and assign custom ones, use `ClearDefaultRoleAssignments` and then configure via `ConfigureInfrastructure`:

```csharp title="C# — AppHost.cs"
var builder = DistributedApplication.CreateBuilder(args);

var search = builder.AddAzureSearch("search");

builder.AddProject<Projects.ExampleProject>("apiservice")
    .WithReference(search)
    .WithRoleAssignments(search, AzureSearchRole.SearchIndexDataReader);
```

Use `withRoleAssignments` to assign specific roles from the `AzureSearchRole` enum to a resource:

```typescript title="TypeScript — apphost.mts"
import { createBuilder, AzureSearchRole } from './.aspire/modules/aspire.mjs';

const builder = await createBuilder();

const search = await builder.addAzureSearch("search");

const api = await builder.addProject("apiservice", "../ExampleProject/ExampleProject.csproj")
    .withReference(search);

// Assign only the data-reader role to the api project
await search.withRoleAssignments(api, [AzureSearchRole.SearchIndexDataReader]);

await builder.build().run();
```

The available roles are defined in the `AzureSearchRole` enum:

| Role                          | Description                                                           |
| ----------------------------- | --------------------------------------------------------------------- |
| `SearchIndexDataContributor`  | Full access to Azure AI Search index data (read, write, and delete). |
| `SearchIndexDataReader`       | Read-only access to Azure AI Search index data.                      |
| `SearchServiceContributor`    | Manage search service resources (not data).                          |

## Connection properties

For the full reference of Azure AI Search connection properties — and how consuming apps in C#, TypeScript, Python, and Go read them — see [Connect to Azure AI Search](../azure-ai-search-connect/).

## Hosting integration health checks

The Azure AI Search hosting integration doesn't register a standalone health check by default because Azure AI Search is a managed cloud service. Health verification happens through the C# client integration. For more information, see [Connect to Azure AI Search](../azure-ai-search-connect/).