Generated banner for Azure Search Documents TS
Generated logo for Azure Search Documents TS

Azure Search Documents TS

MicrosoftOfficialCreated by Microsoft

  • Skill
  • Tool integration
  • Data and AI
  • MIT
  • No issues found

From the author

Build search applications using Azure AI Search SDK for JavaScript (@azure/search-documents). Use when creating/managing indexes, implementing vector/hybrid search, semantic ranking, or building agentic retrieval with knowledge bases.
— the description by Microsoft

AutoGineer summary

Written by AutoGineer from the skill’s own files, not by the author

The azure-search-documents-ts skill provides a comprehensive guide to using the @azure/search-documents SDK for JavaScript and TypeScript. It covers the full lifecycle of search application development, including index creation, document management, and advanced retrieval techniques. Developers can implement full-text search, vector search, hybrid search, and semantic ranking to build robust, AI-powered search experiences. The skill also details how to handle authentication using Azure Identity, manage index schemas, and perform batch operations for efficient data ingestion.

What it does

  • Create and manage search indexes with custom field definitions.
  • Implement vector search using pre-computed embeddings or integrated vectorization.
  • Execute hybrid search queries combining keyword and vector retrieval.
  • Enable semantic ranking for improved relevance in natural language queries.
  • Perform batch operations for uploading, merging, or deleting documents.
  • Configure autocomplete and suggestion features for search interfaces.

When to use it

  • When building search-enabled applications on the Azure platform.
  • When implementing RAG (Retrieval-Augmented Generation) pipelines with knowledge bases.
  • When you need to support complex search requirements like semantic reranking or vector-based similarity.
  • When managing search index schemas programmatically in a TypeScript environment.

Advantages

  • Native support for modern search paradigms like vector and hybrid search.
  • Strongly-typed TypeScript interfaces for index and search configurations.
  • Seamless integration with Azure Identity for secure authentication.
  • Built-in support for semantic ranking to enhance search result quality.

Usage examples

“How do I create a search index with a vector field using the Azure SDK?”
The agent provides a code snippet demonstrating the use of SearchIndexClient to define an index with vectorSearch profiles and vectorSearchDimensions.
“Show me how to perform a hybrid search with text and vector queries.”
The agent provides an example using the search method with both a search string and vectorSearchOptions to combine keyword and vector results.
“How can I enable semantic ranking for my search results?”
The agent explains how to configure semanticSearch in the index and use queryType: 'semantic' in the search options.
“How do I upload multiple documents to my index in one go?”
The agent demonstrates the use of the indexDocuments method with an array of actions to perform batch uploads, merges, or deletions.

Install

  1. Download the skill as a ZIP:

    https://mp-staging.autogineer.com/agent-skills/microsoft/azure-search-documents-ts/download
  2. Unzip it into the cross-client skills folder of your project:

    mkdir -p .agents/skills && unzip azure-search-documents-ts.zip -d .agents/skills

Documentation by Microsoft

Azure AI Search SDK for TypeScript

Build search applications with vector, hybrid, and semantic search capabilities.

Installation

npm install @azure/search-documents @azure/identity

Environment Variables

AZURE_SEARCH_ENDPOINT=https://<service-name>.search.windows.net
AZURE_SEARCH_INDEX_NAME=my-index
AZURE_SEARCH_ADMIN_KEY=<admin-key>  # Optional if using Entra ID
AZURE_TOKEN_CREDENTIALS=prod # Required only if DefaultAzureCredential is used in production

Authentication

import { SearchClient, SearchIndexClient } from "@azure/search-documents";
import { DefaultAzureCredential, ManagedIdentityCredential } from "@azure/identity";

const endpoint = process.env.AZURE_SEARCH_ENDPOINT!;
const indexName = process.env.AZURE_SEARCH_INDEX_NAME!;
// Local dev: DefaultAzureCredential. Production: set AZURE_TOKEN_CREDENTIALS=prod or AZURE_TOKEN_CREDENTIALS=<specific_credential>
const credential = new DefaultAzureCredential({requiredEnvVars: ["AZURE_TOKEN_CREDENTIALS"]});
// Or use a specific credential directly in production:
// See https://learn.microsoft.com/javascript/api/overview/azure/identity-readme?view=azure-node-latest#credential-classes
// const credential = new ManagedIdentityCredential();

// For searching
const searchClient = new SearchClient(endpoint, indexName, credential);

// For index management
const indexClient = new SearchIndexClient(endpoint, credential);

Core Workflow

Create Index with Vector Field
import { SearchIndex, SearchField, VectorSearch } from "@azure/search-documents";

const index: SearchIndex = {
  name: "products",
  fields: [
    { name: "id", type: "Edm.String", key: true },
    { name: "title", type: "Edm.String", searchable: true },
    { name: "description", type: "Edm.String", searchable: true },
    { name: "category", type: "Edm.String", filterable: true, facetable: true },
    {
      name: "embedding",
      type: "Collection(Edm.Single)",
      searchable: true,
      vectorSearchDimensions: 1536,
      vectorSearchProfileName: "vector-profile",
    },
  ],
  vectorSearch: {
    algorithms: [
      { name: "hnsw-algorithm", kind: "hnsw" },
    ],
    profiles: [
      { name: "vector-profile", algorithmConfigurationName: "hnsw-algorithm" },
    ],
  },
};

await indexClient.createOrUpdateIndex(index);
Index Documents
const documents = [
  { id: "1", title: "Widget", description: "A useful widget", category: "Tools", embedding: [...] },
  { id: "2", title: "Gadget", description: "A cool gadget", category: "Electronics", embedding: [...] },
];

const result = await searchClient.uploadDocuments(documents);
console.log(`Indexed ${result.results.length} documents`);
const results = await searchClient.search("widget", {
  select: ["id", "title", "description"],
  filter: "category eq 'Tools'",
  orderBy: ["title asc"],
  top: 10,
});

for await (const result of results.results) {
  console.log(`${result.document.title}: ${result.score}`);
}
const queryVector = await getEmbedding("useful tool"); // Your embedding function

const results = await searchClient.search("*", {
  vectorSearchOptions: {
    queries: [
      {
        kind: "vector",
        vector: queryVector,
        fields: ["embedding"],
        kNearestNeighborsCount: 10,
      },
    ],
  },
  select: ["id", "title", "description"],
});

for await (const result of results.results) {
  console.log(`${result.document.title}: ${result.score}`);
}
Hybrid Search (Text + Vector)
const queryVector = await getEmbedding("useful tool");

const results = await searchClient.search("tool", {
  vectorSearchOptions: {
    queries: [
      {
        kind: "vector",
        vector: queryVector,
        fields: ["embedding"],
        kNearestNeighborsCount: 50,
      },
    ],
  },
  select: ["id", "title", "description"],
  top: 10,
});
// Index must have semantic configuration
const index: SearchIndex = {
  name: "products",
  fields: [...],
  semanticSearch: {
    configurations: [
      {
        name: "semantic-config",
        prioritizedFields: {
          titleField: { name: "title" },
          contentFields: [{ name: "description" }],
        },
      },
    ],
  },
};

// Search with semantic ranking
const results = await searchClient.search("best tool for the job", {
  queryType: "semantic",
  semanticSearchOptions: {
    configurationName: "semantic-config",
    captions: { captionType: "extractive" },
    answers: { answerType: "extractive", count: 3 },
  },
  select: ["id", "title", "description"],
});

for await (const result of results.results) {
  console.log(`${result.document.title}`);
  console.log(`  Caption: ${result.captions?.[0]?.text}`);
  console.log(`  Reranker Score: ${result.rerankerScore}`);
}

Filtering and Facets

// Filter syntax
const results = await searchClient.search("*", {
  filter: "category eq 'Electronics' and price lt 100",
  facets: ["category,count:10", "brand"],
});

// Access facets
for (const [facetName, facetResults] of Object.entries(results.facets || {})) {
  console.log(`${facetName}:`);
  for (const facet of facetResults) {
    console.log(`  ${facet.value}: ${facet.count}`);
  }
}

Autocomplete and Suggestions

// Create suggester in index
const index: SearchIndex = {
  name: "products",
  fields: [...],
  suggesters: [
    { name: "sg", sourceFields: ["title", "description"] },
  ],
};

// Autocomplete
const autocomplete = await searchClient.autocomplete("wid", "sg", {
  mode: "twoTerms",
  top: 5,
});

// Suggestions
const suggestions = await searchClient.suggest("wid", "sg", {
  select: ["title"],
  top: 5,
});

Batch Operations

// Batch upload, merge, delete
const batch = [
  { upload: { id: "1", title: "New Item" } },
  { merge: { id: "2", title: "Updated Title" } },
  { delete: { id: "3" } },
];

const result = await searchClient.indexDocuments({ actions: batch });

Key Types

import {
  SearchClient,
  SearchIndexClient,
  SearchIndexerClient,
  SearchIndex,
  SearchField,
  SearchOptions,
  VectorSearch,
  SemanticSearch,
  SearchIterator,
} from "@azure/search-documents";

Best Practices

  1. Use hybrid search - Combine vector + text for best results

  2. Enable semantic ranking - Improves relevance for natural language queries

  3. Batch document uploads - Use uploadDocuments with arrays, not single docs

  4. Use filters for security - Implement document-level security with filters

  5. Index incrementally - Use mergeOrUploadDocuments for updates

  6. Monitor query performance - Use includeTotalCount: true sparingly in production

Files

references/semantic-ranking.md

@azure/search-documents - Semantic Ranking Patterns

Reference documentation for semantic search and ranking in the Azure AI Search TypeScript SDK.

Source: Azure SDK for JS - search-documents


Installation

npm install @azure/search-documents @azure/identity

SemanticSearchOptions Interface

interface SemanticSearchOptions {
  /** Name of the semantic configuration to use */
  configurationName?: string;
  
  /** Error handling mode: "partial" or "fail" */
  errorMode?: SemanticErrorMode;
  
  /** Max wait time for semantic processing (ms) */
  maxWaitInMilliseconds?: number;
  
  /** Extract answers from documents */
  answers?: QueryAnswer;
  
  /** Extract captions with highlighting */
  captions?: QueryCaption;
  
  /** AI-generated query rewrites */
  queryRewrites?: QueryRewrites;
  
  /** Separate query for semantic reranking */
  semanticQuery?: string;
  
  /** Fields for semantic search */
  semanticFields?: string[];
  
  /** Enable debug info */
  debugMode?: QueryDebugMode;
}

Enable semantic ranking with queryType: "semantic":

import { SearchClient } from "@azure/search-documents";
import { DefaultAzureCredential } from "@azure/identity";

interface Article {
  id: string;
  title: string;
  content: string;
  category: string;
}

const client = new SearchClient<Article>(
  process.env["AZURE_SEARCH_ENDPOINT"]!,
  "articles",
  new DefaultAzureCredential()
);

const results = await client.search("what causes climate change", {
  queryType: "semantic",
  semanticSearchOptions: {
    configurationName: "my-semantic-config",
  },
  select: ["id", "title", "content"],
  top: 10,
});

for await (const result of results.results) {
  console.log(`${result.document.title}`);
  console.log(`Reranker Score: ${result.rerankerScore}`);
}

Extractive Captions

Extract representative passages with keyword highlighting:

const results = await client.search("renewable energy benefits", {
  queryType: "semantic",
  semanticSearchOptions: {
    configurationName: "my-semantic-config",
    captions: {
      captionType: "extractive",
      highlight: true,
    },
  },
});

for await (const result of results.results) {
  console.log(`Title: ${result.document.title}`);
  
  // Access captions
  result.captions?.forEach((caption) => {
    console.log(`Caption: ${caption.text}`);
    console.log(`Highlighted: ${caption.highlights}`); // With <em> tags
  });
}
Caption Options
interface QueryCaption {
  /** Caption type: "extractive" | "none" */
  captionType: QueryCaptionType;
  
  /** Include highlighting with <em> tags */
  highlight?: boolean;
}

Extractive Answers

Extract direct answers for Q&A-style queries:

const results = await client.search("what is the speed of light", {
  queryType: "semantic",
  semanticSearchOptions: {
    configurationName: "science-config",
    answers: {
      answerType: "extractive",
      count: 3,           // Number of answers to extract
      threshold: 0.7,     // Minimum confidence threshold
    },
  },
});

// Access answers at the result set level
if (results.answers && results.answers.length > 0) {
  console.log("Top Answers:");
  results.answers.forEach((answer, i) => {
    console.log(`${i + 1}. ${answer.text}`);
    console.log(`   Highlights: ${answer.highlights}`);
    console.log(`   Score: ${answer.score}`);
    console.log(`   Document: ${answer.key}`);
  });
}
Answer Options
interface QueryAnswer {
  /** Answer type: "extractive" | "none" */
  answerType: QueryAnswerType;
  
  /** Number of answers to return (1-10) */
  count?: number;
  
  /** Minimum confidence threshold (0-1) */
  threshold?: number;
}

Query Rewrites

Enable AI-generated query rewrites for better recall:

const results = await client.search("ML algorithms", {
  queryType: "semantic",
  semanticSearchOptions: {
    configurationName: "tech-config",
    queryRewrites: {
      rewritesType: "generative",
      count: 3, // Number of rewrites to generate
    },
  },
});

// Access generated rewrites
if (results.queryRewrites && results.queryRewrites.length > 0) {
  console.log("Query Rewrites:");
  results.queryRewrites.forEach((rewrite) => {
    console.log(`- ${rewrite}`);
  });
}

Combine semantic ranking with vector search for best results:

const results = await client.search("climate change solutions", {
  // Enable semantic reranking
  queryType: "semantic",
  semanticSearchOptions: {
    configurationName: "articles-semantic",
    captions: { captionType: "extractive", highlight: true },
    answers: { answerType: "extractive", count: 3 },
  },
  
  // Add vector search
  vectorSearchOptions: {
    queries: [
      {
        kind: "text",
        text: "climate change solutions",
        kNearestNeighborsCount: 50,
        fields: ["contentVector"],
      },
    ],
  },
  
  // Keyword search fields
  searchFields: ["title", "content"],
  
  top: 10,
  select: ["id", "title", "content", "category"],
});

// Results are:
// 1. Retrieved via hybrid (keyword + vector)
// 2. Reranked by semantic model
// 3. Enriched with captions and answers

Semantic Query Override

Use different queries for retrieval vs. semantic reranking:

const results = await client.search("ML", {
  // "ML" used for keyword matching
  queryType: "semantic",
  semanticSearchOptions: {
    configurationName: "tech-config",
    // Full question used for semantic reranking
    semanticQuery: "What are the best machine learning algorithms for classification?",
    captions: { captionType: "extractive" },
  },
});

Debug Mode

Get detailed information about semantic processing:

const results = await client.search("quantum computing applications", {
  queryType: "semantic",
  semanticSearchOptions: {
    configurationName: "science-config",
    debugMode: "semantic", // "disabled" | "speller" | "semantic" | "all"
  },
});

for await (const result of results.results) {
  // Access debug info per document
  console.log(`Document: ${result.document.title}`);
  console.log(`Debug Info:`, result.documentDebugInfo);
}

Error Handling

Control behavior when semantic processing fails:

const results = await client.search("complex query here", {
  queryType: "semantic",
  semanticSearchOptions: {
    configurationName: "my-config",
    
    // "partial" - Return results without semantic enrichment on failure
    // "fail" - Return error if semantic processing fails
    errorMode: "partial",
    
    // Timeout for semantic processing
    maxWaitInMilliseconds: 5000,
  },
});

Index Semantic Configuration

Define semantic configuration in your index:

import { SearchIndexClient, SearchIndex } from "@azure/search-documents";

const indexClient = new SearchIndexClient(endpoint, credential);

const index: SearchIndex = {
  name: "articles",
  fields: [
    { name: "id", type: "Edm.String", key: true },
    { name: "title", type: "Edm.String", searchable: true },
    { name: "content", type: "Edm.String", searchable: true },
    { name: "summary", type: "Edm.String", searchable: true },
    { name: "category", type: "Edm.String", filterable: true },
  ],
  semanticSearch: {
    configurations: [
      {
        name: "articles-semantic",
        prioritizedFields: {
          // Title field (highest priority for reranking)
          titleField: {
            fieldName: "title",
          },
          // Content fields (used for caption/answer extraction)
          contentFields: [
            { fieldName: "content" },
            { fieldName: "summary" },
          ],
          // Keyword fields (boost exact matches)
          keywordsFields: [
            { fieldName: "category" },
          ],
        },
      },
    ],
    defaultConfiguration: "articles-semantic",
  },
};

await indexClient.createOrUpdateIndex(index);

Complete Example

import { SearchClient } from "@azure/search-documents";
import { DefaultAzureCredential } from "@azure/identity";

interface Document {
  id: string;
  title: string;
  content: string;
  contentVector: number[];
  category: string;
}

async function semanticHybridSearch(query: string) {
  const client = new SearchClient<Document>(
    process.env["AZURE_SEARCH_ENDPOINT"]!,
    "knowledge-base",
    new DefaultAzureCredential()
  );

  const results = await client.search(query, {
    queryType: "semantic",
    semanticSearchOptions: {
      configurationName: "default-semantic",
      captions: { captionType: "extractive", highlight: true },
      answers: { answerType: "extractive", count: 3, threshold: 0.7 },
    },
    vectorSearchOptions: {
      queries: [
        {
          kind: "text",
          text: query,
          kNearestNeighborsCount: 50,
          fields: ["contentVector"],
        },
      ],
    },
    searchFields: ["title", "content"],
    top: 10,
    select: ["id", "title", "content", "category"],
  });

  // Process answers first (highest quality extracts)
  const response: {
    answers: Array<{ text: string; score: number; documentId: string }>;
    results: Array<{
      document: Document;
      score: number;
      rerankerScore: number;
      captions: string[];
    }>;
  } = {
    answers: [],
    results: [],
  };

  // Extract answers
  if (results.answers) {
    response.answers = results.answers.map((a) => ({
      text: a.highlights || a.text || "",
      score: a.score ?? 0,
      documentId: a.key || "",
    }));
  }

  // Extract results with captions
  for await (const result of results.results) {
    response.results.push({
      document: result.document,
      score: result.score ?? 0,
      rerankerScore: result.rerankerScore ?? 0,
      captions: result.captions?.map((c) => c.highlights || c.text || "") ?? [],
    });
  }

  return response;
}

// Usage
const response = await semanticHybridSearch("how does photosynthesis work");

console.log("=== Direct Answers ===");
response.answers.forEach((a, i) => {
  console.log(`${i + 1}. ${a.text} (score: ${a.score})`);
});

console.log("\n=== Search Results ===");
response.results.forEach((r, i) => {
  console.log(`${i + 1}. ${r.document.title}`);
  console.log(`   Reranker Score: ${r.rerankerScore}`);
  console.log(`   Caption: ${r.captions[0] || "N/A"}`);
});

Best Practices

  1. Use extractive answers - For Q&A scenarios, answers provide direct responses

  2. Enable captions - They provide relevant snippets without returning full content

  3. Combine with hybrid search - Semantic + vector + keyword yields best results

  4. Set appropriate thresholds - Filter low-confidence answers

  5. Configure semantic fields - Prioritize title > content > keywords

  6. Use partial error mode - Gracefully degrade when semantic processing fails

  7. Monitor latency - Semantic processing adds ~100-300ms latency


See Also

Requirements and compatibility

Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta

“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.

Needs: Needs Node.js

Security

No issues found by our static scan· No issues found

A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.

Attribution and licence

Created by
Microsoft
Publisher
Microsoft (Official)
Source
microsoft/skills · .github/plugins/azure-sdk-typescript/skills/azure-search-documents-ts · commit 0696600
Licence
MIT License (redistribution allowed)
  • LICENSE (added by AutoGineer from LICENSE)
  • ATTRIBUTION.md (written by AutoGineer)
Synced

AutoGineer is not affiliated with or endorsed by Microsoft.

Download ZIP

The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download azure-search-documents-ts.zip