Skip to content
Learni
View all tutorials
Cloud & IA

How to Master AWS Bedrock with TypeScript in 2026

Lire en français

Introduction

AWS Bedrock provides access to foundation models such as Claude, Llama, or Titan through a unified API without managing infrastructure. In 2026, adoption is surging for RAG use cases and autonomous agents. This expert tutorial walks you through advanced TypeScript integration step by step, from basic client setup to resilient production architectures. You will learn professional techniques for handling streaming, knowledge bases, and IAM security.

Prerequisites

  • Node.js 20+ and TypeScript 5.4+
  • AWS account with Bedrock access (us-east-1 or eu-west-3)
  • Solid knowledge of IAM and SDK v3
  • AWS CLI configured with credentials

Initializing the Bedrock Client

src/lib/bedrock-client.ts
import { BedrockRuntimeClient, InvokeModelCommand } from '@aws-sdk/client-bedrock-runtime';

const client = new BedrockRuntimeClient({
  region: 'eu-west-3',
  credentials: {
    accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
  },
});

This reusable client configures the region and credentials via environment variables. Always use SDK v3 for better performance and tree-shaking.

Simple Model Invocation

src/services/invoke-model.ts
import { InvokeModelCommand } from '@aws-sdk/client-bedrock-runtime';

export async function invokeClaude(prompt: string) {
  const command = new InvokeModelCommand({
    modelId: 'anthropic.claude-3-5-sonnet-20241022-v2:0',
    contentType: 'application/json',
    accept: 'application/json',
    body: JSON.stringify({
      anthropic_version: 'bedrock-2023-05-31',
      max_tokens: 1024,
      messages: [{ role: 'user', content: prompt }],
    }),
  });
  const response = await client.send(command);
  return JSON.parse(new TextDecoder().decode(response.body));
}

Complete working code to invoke Claude 3.5. Always validate the modelId and manage tokens to avoid quota errors.

Handling Response Streaming

src/services/stream-response.ts
import { InvokeModelWithResponseStreamCommand } from '@aws-sdk/client-bedrock-runtime';

export async function* streamClaude(prompt: string) {
  const command = new InvokeModelWithResponseStreamCommand({
    modelId: 'anthropic.claude-3-5-sonnet-20241022-v2:0',
    contentType: 'application/json',
    body: JSON.stringify({
      anthropic_version: 'bedrock-2023-05-31',
      max_tokens: 2048,
      messages: [{ role: 'user', content: prompt }],
    }),
  });
  const response = await client.send(command);
  for await (const event of response.body!) {
    if (event.chunk) {
      const chunk = JSON.parse(new TextDecoder().decode(event.chunk.bytes));
      yield chunk.delta?.text || '';
    }
  }
}

Streaming reduces perceived latency. Use an async generator to consume chunks in real time within a Next.js API route or WebSocket.

Knowledge Base Integration

src/services/knowledge-base.ts
import { BedrockAgentRuntimeClient, RetrieveAndGenerateCommand } from '@aws-sdk/client-bedrock-agent-runtime';

const agentClient = new BedrockAgentRuntimeClient({ region: 'eu-west-3' });

export async function retrieveAndGenerate(query: string, kbId: string) {
  const command = new RetrieveAndGenerateCommand({
    input: { text: query },
    retrieveAndGenerateConfiguration: {
      type: 'KNOWLEDGE_BASE',
      knowledgeBaseConfiguration: {
        knowledgeBaseId: kbId,
        modelArn: 'arn:aws:bedrock:eu-west-3::foundation-model/anthropic.claude-3-5-sonnet-20241022-v2:0',
      },
    },
  });
  return await agentClient.send(command);
}

This method enables managed RAG without vector infrastructure. The kbId comes from the Bedrock console after indexing your S3 documents.

Error Handling and Retry

src/utils/retry.ts
import { ThrottlingException, ServiceQuotaExceededException } from '@aws-sdk/client-bedrock-runtime';

export async function withRetry<T>(fn: () => Promise<T>, maxRetries = 3): Promise<T> {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if ((error instanceof ThrottlingException || error instanceof ServiceQuotaExceededException) && i < maxRetries - 1) {
        await new Promise(r => setTimeout(r, 1000 * Math.pow(2, i)));
        continue;
      }
      throw error;
    }
  }
  throw new Error('Max retries exceeded');
}

Implement exponential backoff for Bedrock throttling errors. This is critical in production to maintain availability.

Best Practices

  • Always enable CloudWatch logging and monitor InvokeModel metrics
  • Use IAM roles with least privilege (bedrock:InvokeModel on specific models)
  • Validate and sanitize prompts to prevent injections
  • Cache frequent responses with Redis or DynamoDB
  • Configure Bedrock guardrails to filter sensitive content

Common Errors to Avoid

  • Forgetting to request model access in the Bedrock console (AccessDenied error)
  • Ignoring token limits and receiving truncated responses
  • Failing to handle ThrottlingException exceptions in production
  • Using root credentials instead of dedicated IAM roles

Going Further

Deepen your knowledge of autonomous agents and multi-model architectures in our AWS Bedrock Advanced training.