Executando o SDK da Anthropic em Runtimes de Edge
O pacote oficial @anthropic-ai/sdk é construído sobre fetch, então ele roda sem modificações em runtimes de edge como Vercel Edge Functions, Cloudflare Workers e Deno Deploy, não apenas em Node.js. Esta página cobre como configurar o cliente e transmitir respostas corretamente em cada plataforma.
Resumo
Runtimes de edge são ambientes JavaScript leves que rodam próximos à requisição, muitas vezes sem a superfície completa da API do Node.js. Eles não têm fs, net, ou muitos outros built-ins do Node disponíveis.
O @anthropic-ai/sdk evita esse problema porque seu caminho de requisição é construído sobre a API padrão fetch, ReadableStream e AbortController, todos disponíveis em qualquer runtime de edge moderno.
As principais diferenças entre deployments de edge e Node.js são como você lê a chave de API (o acesso a variáveis de ambiente difere por plataforma) e como você retorna uma resposta em stream (handlers de edge tipicamente retornam um objeto Response diretamente em vez de escrever em um http.ServerResponse do Node.js).
Esta página percorre uma Vercel Edge Function (via um Next.js route handler), uma Cloudflare Worker e notas sobre Deno Deploy, cada uma configurando o cliente e transmitindo uma resposta de volta para o chamador.
Timeouts e cancelamento funcionam da mesma forma em edge como em Node.js: passe um AbortSignal para a requisição, ou confie na própria configuração de timeout do SDK, mas lembre-se que a plataforma também impõe seu próprio limite de tempo de execução em cima de qualquer coisa que você configure.
Receita
Cartão de receita de referência rápida, pronto para copiar e colar.
// Funciona identicamente em Node.js, Vercel Edge, Cloudflare Workers e Deno Deploy
import Anthropic from "@anthropic-ai/sdk";
const anthropic = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY,
});
const message = await anthropic.messages.create({
model: "claude-sonnet-5",
max_tokens: 1024,
messages: [{ role: "user", content: "Explique runtimes de edge em um parágrafo." }],
});
console.log(message.content);Quando usar isso:
- Servir respostas Claude de baixa latência de um local próximo ao usuário (Vercel Edge, Cloudflare Workers rodam na edge da rede).
- Fazer deploy em uma plataforma que não suporta o runtime completo do Node.js (Cloudflare Workers, Deno Deploy).
- Transmitir uma resposta de chat diretamente de volta para o navegador sem bufferizar a resposta completa primeiro.
- Manter o tempo de cold-start de uma função serverless baixo; runtimes de edge geralmente iniciam mais rápido que funções Node.js.
Exemplo Funcional
Vercel Edge Function (Next.js route handler)
// app/api/chat/route.ts
import Anthropic from "@anthropic-ai/sdk";
export const runtime = "edge";
const anthropic = new Anthropic({
apiKey: process.env.ANTHROPIC_API_KEY,
});
export async function POST(req: Request) {
const { prompt } = await req.json();
const stream = await anthropic.messages.create({
model: "claude-sonnet-5",
max_tokens: 1024,
messages: [{ role: "user", content: prompt }],
stream: true,
});
const encoder = new TextEncoder();
const body = new ReadableStream({
async start(controller) {
for await (const event of stream) {
if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
controller.enqueue(encoder.encode(event.delta.text));
}
}
controller.close();
},
});
return new Response(body, {
headers: { "Content-Type": "text/plain; charset=utf-8" },
});
}O que isso demonstra:
- Definir
export const runtime = "edge"opta o Next.js route handler para o runtime Vercel Edge. - A chave de API é lida de
process.env.ANTHROPIC_API_KEY, que a Vercel injeta em edge functions da mesma forma que faz para funções Node.js, desde que a variável de ambiente esteja definida nas configurações do projeto. - O iterador assíncrono do SDK (
for await (const event of stream)) é encapsulado em umReadableStreampara que o handler possa retornar umaResponseem stream em vez de esperar pela mensagem completa. - Apenas deltas de bloco de conteúdo
text_deltasão encaminhados para o cliente; outros tipos de evento (message start, content block start/stop, message stop) são ignorados para este caso simples de streaming de texto.
Cloudflare Worker
// src/worker.ts
import Anthropic from "@anthropic-ai/sdk";
export interface Env {
ANTHROPIC_API_KEY: string;
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
if (request.method !== "POST") {
return new Response("Use POST", { status: 405 });
}
const anthropic = new Anthropic({
apiKey: env.ANTHROPIC_API_KEY,
});
const { prompt } = await request.json<{ prompt: string }>();
const stream = await anthropic.messages.create({
model: "claude-sonnet-5",
max_tokens: 1024,
messages: [{ role: "user", content: prompt }],
stream: true,
});
const encoder = new TextEncoder();
const body = new ReadableStream({
async start(controller) {
for await (const event of stream) {
if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
controller.enqueue(encoder.encode(event.delta.text));
}
}
controller.close();
},
});
return new Response(body, {
headers: { "Content-Type": "text/plain; charset=utf-8" },
});
},
};O que isso demonstra:
- Cloudflare Workers passa configurações e segredos através de um objeto
envtipado passado parafetch, não através deprocess.env. OANTHROPIC_API_KEYé declarado em uma interfaceEnve lido comoenv.ANTHROPIC_API_KEY. - O segredo em si é definido fora do código, com
wrangler secret put ANTHROPIC_API_KEY, então ele nunca vive no repositório ou no arquivowrangler.toml. - O cliente é instanciado dentro do handler
fetch(não no escopo do módulo) para que ele sempre pegue os bindingsenvpara a requisição atual. - O padrão de streaming é idêntico ao exemplo Vercel Edge porque ambas as plataformas implementam os mesmos padrões web
ReadableStreameResponse.
Cancelando a Chamada Upstream na Desconexão do Cliente
Ambos os exemplos acima podem encaminhar o AbortSignal da requisição de entrada para a chamada do SDK, então uma desconexão do cliente cancela a requisição upstream para Claude em vez de deixá-la completar:
const message = await anthropic.messages.create(
{
model: "claude-sonnet-5",
max_tokens: 1024,
messages: [{ role: "user", content: prompt }],
},
{ signal: request.signal },
);- Conectar
AbortControlleraosignalda requisição de entrada significa que cancelar o cliente (fechar a aba do navegador, navegar para longe) também cancela a chamada upstream para Claude, em vez de deixá-la completar e gastar tokens para uma resposta que ninguém lerá. request.signalestá disponível no objetoRequesttanto em Vercel Edge Functions quanto em Cloudflare Workers porque ambas implementam a API padrão Fetch.
Mergulho Profundo
Como Funciona
- O
@anthropic-ai/sdkenvia requisições com a função globalfetchem vez de um cliente HTTP específico do Node, então ele não tem dependência de built-ins do Node comohttp,https, ounetpara seu caminho de requisição principal. - Respostas em stream da API de Mensagens chegam como server-sent events, que o SDK parseia e expõe como um iterador assíncrono de eventos de mensagem tipados (
for await (const event of stream)). - Runtimes de edge executam seu handler em um sandbox leve, frequentemente baseado em isolados V8, não em um processo Node.js completo, que é por que APIs exclusivas do Node (
fs,child_process, módulos nativos) não estão disponíveis e por que um SDK baseado em fetch é o fator decisivo para compatibilidade. - Como o ciclo de requisição/resposta em um handler de edge é construído sobre os mesmos primitivos
Request/Response/ReadableStreamque o SDK usa internamente, você pode canalizar o stream do SDK diretamente para o valor de retorno da função sem uma camada de adaptador.
Tratamento da Chave de API por Plataforma
| Plataforma | Onde a chave vive | Como você a lê |
|---|---|---|
| Vercel Edge Function | Variáveis de ambiente do projeto (dashboard Vercel ou .env.local para dev local) | process.env.ANTHROPIC_API_KEY |
| Cloudflare Worker | Segredo definido via wrangler secret put ANTHROPIC_API_KEY | env.ANTHROPIC_API_KEY (passado como argumento para fetch) |
| Deno Deploy | Variável de ambiente do projeto definida no dashboard Deno Deploy (ou .env para dev local com deno run --env) | Deno.env.get("ANTHROPIC_API_KEY") |
Notas sobre Deno Deploy
// main.ts (Deno Deploy)
import Anthropic from "npm:@anthropic-ai/sdk";
const anthropic = new Anthropic({
apiKey: Deno.env.get("ANTHROPIC_API_KEY"),
});
Deno.serve(async (request: Request) => {
const { prompt } = await request.json();
const message = await anthropic.messages.create({
model: "claude-sonnet-5",
max_tokens: 1024,
messages: [{ role: "user", content: prompt }],
});
return Response.json(message);
});- Deno Deploy importa pacotes npm com o especificador
npm:, entãoimport Anthropic from "npm:@anthropic-ai/sdk"funciona sem umpackage.jsonou etapa de build. - Segredos são lidos com
Deno.env.get(...), nãoprocess.env; Deno expõe um shimprocesspara compatibilidade, masDeno.envé o caminho nativo e recomendado. Deno.serveé o ponto de entrada HTTP embutido no Deno Deploy e, como as outras duas plataformas, aceita e retorna objetosRequest/Responsepadrão.
Notas sobre TypeScript
// Estreita a união de eventos de streaming antes de ler delta.text
for await (const event of stream) {
if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
// event.delta.text é tipado com segurança como string aqui
process.stdout.write(event.delta.text);
}
}- O SDK envia seus próprios tipos TypeScript, então
message.content, eventos de streaming e classes de erro são todos tipados sem pacotes@typesextras. - Eventos de streaming são uma união discriminada em
event.type; estreitar com uma verificaçãoif(como acima) é o que permite ao TypeScript saber queevent.delta.textexiste, em vez de recorrer a uma asserção de tipo. - Evite casts
as anyna opçãoapiKeydo cliente. Seprocess.env.ANTHROPIC_API_KEY(ouenv.ANTHROPIC_API_KEY) forundefinedem tempo de execução porque a variável não foi definida, deixe o SDK lançar seu erro de autenticação normal em vez de silenciar o verificador de tipo.
Parâmetros e Valores de Retorno
| Parâmetro | Tipo | Descrição |
|---|---|---|
apiKey | string | Chave de API da Anthropic. Obrigatório, a menos que definida via ANTHROPIC_API_KEY em um ambiente que o SDK lê automaticamente (apenas Node.js; runtimes de edge devem passá-la explicitamente). |
timeout | number | Milissegundos antes que o SDK aborte a requisição do lado do cliente. Independente do limite de execução da própria plataforma de edge. |
maxRetries | number | Número de novas tentativas automáticas em erros transitórios (limites de taxa, falhas de rede, respostas 5xx). Padrão é 2. |
signal | AbortSignal | Passado por requisição para cancelar uma chamada em andamento, por exemplo anthropic.messages.create(params, { signal }). |
Armadilhas
- Ler
process.envem Cloudflare Workers. Cloudflare Workers não preenchemprocess.envcom segredos por padrão; eles passam configurações através do argumentoenvno handlerfetch. Correção: leiaenv.ANTHROPIC_API_KEYdentro do handler, nãoprocess.env.ANTHROPIC_API_KEYno escopo do módulo. - Instanciar o cliente no escopo do módulo em Cloudflare Workers. Se você construir o cliente
Anthropicfora da funçãofetch,envnão estará disponível ainda quando o módulo carregar. Correção: construa o cliente dentro da função handler ondeenvé passado como argumento. - Assumir que runtimes de edge não têm timeout. Vercel Edge Functions, Cloudflare Workers e Deno Deploy cada um impõe seu próprio tempo máximo de execução ou tempo de CPU por requisição, além de qualquer coisa que você configure no cliente SDK. Correção: verifique os limites atuais para seu plano em cada plataforma e projete gerações de longa duração em torno de streaming (retorne saída parcial conforme ela chega) em vez de esperar por uma única resposta grande não-streamed.
- Esquecer de definir
stream: truee depois tentar iterar o resultado. Chamaranthropic.messages.create()semstream: trueretorna um único objetoMessageresolvido, não um iterador assíncrono; tentar um loopfor awaitsobre ele falha. Correção: passestream: truenos parâmetros da requisição sempre que você pretende consumir a resposta como um stream. - Não estreitar a união de eventos de streaming antes de ler
delta.text. Eventos de streaming incluem vários tipos (message_start,content_block_start,content_block_delta,content_block_stop,message_stop, e mais), e apenas eventoscontent_block_deltacomdelta.type === "text_delta"carregam.text. Correção: verifique ambosevent.typeeevent.delta.typeantes de lerevent.delta.text. - Deixar a chave de API em código do lado do cliente. Como edge functions rodam no lado do servidor, é tentador pensar que qualquer código no mesmo repositório é seguro, mas uma chave codificada em um route handler que também envia um bundle cliente (ou copiada para uma Cloudflare Worker commitada no controle de versão) pode vazar. Correção: sempre carregue a chave de uma variável de ambiente ou loja de segredos, nunca a codifique, e adicione arquivos
.env*ao.gitignore. - Assumir que
AbortControllerprecisa de um import específico do Node.AbortControllereAbortSignalsão globais no Node.js 18+, todos os principais navegadores, e todos os runtimes de edge cobertos aqui, então nenhum import ou polyfill é necessário. Correção: apenas use oAbortControllerglobal, ou encaminherequest.signalde umRequestde entrada quando você quiser que desconexões do cliente cancelem a chamada upstream para Claude.
Alternativas
| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
| Função serverless Node.js (runtime Node Vercel, AWS Lambda) | Você precisa de APIs completas do Node.js (acesso ao sistema de arquivos, certos pacotes npm nativos) ao lado da chamada do SDK. | A latência para o local de edge mais próximo importa mais do que a compatibilidade com Node, ou a plataforma fatura funções de edge e Node de forma diferente e edge é mais barata para seu tráfego. |
| Um servidor backend dedicado (Express, Fastify) chamando o SDK | Você já executa um processo de servidor de longa duração e deseja logging centralizado, pooling de conexões ou integrações não-HTTP. | Você deseja escalonamento por requisição para zero e baixa latência de cold-start, que funções de edge e serverless fornecem de forma mais natural do que um servidor sempre ativo. |
Chamar a API de Mensagens com fetch bruto em vez do SDK | Você precisa de um bundle mínimo com zero dependências, ou está em um runtime que o SDK ainda não verificou. | Você quer formas tipadas de requisição/resposta, tratamento de retentativas e timeout embutidos, e parsing de eventos de streaming, que o SDK fornece prontamente. |
FAQs
O SDK TypeScript da Anthropic precisa de alguma build ou pacote especial de runtime de edge?
Não. Instale o mesmo pacote @anthropic-ai/sdk que você usaria no Node.js. Ele funciona em runtimes de edge porque seu caminho de requisição é construído sobre fetch, ReadableStream e AbortController, todos os quais são APIs Web padrão disponíveis em ambientes de edge.
Por que `process.env.ANTHROPIC_API_KEY` não funciona no meu Cloudflare Worker?
- Cloudflare Workers não preenchem automaticamente
process.envcom segredos da mesma forma que Node.js. - Segredos e variáveis são passados como o argumento
envpara o handlerfetchem vez disso. - Leia a chave como
env.ANTHROPIC_API_KEYdentro do handler, e defina-a comwrangler secret put ANTHROPIC_API_KEY.
Posso transmitir uma resposta Claude diretamente de volta para o navegador a partir de uma edge function?
Sim. Envolva o iterador assíncrono do SDK em um ReadableStream, enfileire cada delta de texto conforme ele chega, e retorne esse stream como o corpo de um objeto Response padrão. Tanto Vercel Edge Functions quanto Cloudflare Workers aceitam um ReadableStream como corpo de Response nativamente.
Como defino a chave de API para um projeto Deno Deploy?
Defina-a como uma variável de ambiente no dashboard do projeto Deno Deploy (ou em um arquivo .env local para desenvolvimento), então leia-a com Deno.env.get("ANTHROPIC_API_KEY") em vez de process.env.
Preciso instalar algo diferente para importar o SDK no Deno?
Nenhuma etapa de instalação separada é necessária. Use o especificador npm: para importar diretamente, por exemplo import Anthropic from "npm:@anthropic-ai/sdk", e o Deno resolve o pacote npm em tempo de execução.
O `maxRetries` e `timeout` ainda funcionarão em runtimes de edge?
Sim, ambas as opções funcionam da mesma forma que no Node.js, pois são implementadas sobre fetch e timers padrão. Lembre-se que a plataforma de edge também impõe seu próprio tempo máximo de execução independentemente, então um timeout generoso do SDK não substitui o limite da plataforma.
O que acontece se eu esquecer de definir `stream: true`?
anthropic.messages.create() retorna um único objeto Message resolvido em vez de um iterador assíncrono. Tentar um loop for await sobre um resultado não-streamed falhará, então certifique-se de que stream: true esteja definido sempre que você pretende consumir a resposta incrementalmente.
Como cancelo uma requisição Claude em andamento se o usuário navegar para longe?
Encaminhe o AbortSignal da requisição de entrada para a chamada do SDK, por exemplo anthropic.messages.create(params, { signal: request.signal }). Quando o cliente desconecta, a plataforma aborta o sinal e o SDK cancela a requisição upstream para Claude.
Qual tipo de evento de streaming realmente contém o texto que quero exibir?
Eventos content_block_delta onde event.delta.type === "text_delta" carregam o texto incremental em event.delta.text. Outros tipos de evento como message_start, content_block_start, e message_stop marcam limites estruturais no stream e não carregam conteúdo de texto.
É seguro codificar minha chave de API diretamente no arquivo de origem de uma Cloudflare Worker para um teste rápido?
Não. Mesmo para testes, carregue a chave de uma variável de ambiente ou segredo do Cloudflare. Uma chave commitada no controle de versão (mesmo que temporariamente) pode acabar no histórico de versionamento ou em um repositório público, e segredos do Workers definidos com wrangler secret put são a maneira suportada de mantê-la fora do codebase completamente.
O mesmo código roda sem alteração entre Vercel Edge, Cloudflare Workers e Deno Deploy?
O uso do SDK (construção do cliente, messages.create, streaming) é o mesmo em todos os três. O que difere é como cada plataforma expõe variáveis de ambiente/segredos (process.env na Vercel, um argumento env no Cloudflare, Deno.env.get no Deno) e, para Cloudflare, como a assinatura do handler fetch é moldada.
Preciso de um polyfill para `AbortController` em alguma dessas plataformas?
Não. AbortController e AbortSignal estão globalmente disponíveis no Node.js 18+, e em Vercel Edge Functions, Cloudflare Workers e Deno Deploy, já que todos implementam a superfície padrão da API Fetch.
Relacionados
- Noções Básicas do SDK TypeScript/JavaScript - instalando o SDK e enviando sua primeira chamada tipada à API de Mensagens.
- Iteradores Assíncronos para Streaming no SDK TypeScript - um olhar mais atento ao consumo de deltas de mensagem transmitidos.
- Padrões de Retry, Timeout e AbortController no SDK TypeScript - ajustando backoff e cancelamento com mais detalhes.
- Construindo um Endpoint de Chat em Stream com Next.js e o SDK TypeScript - um endpoint de chat completo construído no padrão de streaming mostrado aqui.
- O Modelo Mental do SDK TypeScript da Anthropic - como o modelo de requisição/resposta e streaming do SDK se encaixa.
Versões da Stack: Escrito contra a linha de modelos Claude atual em ~junho de 2026 - Claude Fable 5, Claude Opus 4.8, Claude Sonnet 5 (o padrão), e Claude Haiku 4.5 - e o SDK oficial
@anthropic-ai/sdkTypeScript (última versão). Nomes de modelos, versões de SDK e preços mudam rapidamente - verifique os detalhes atuais em platform.claude.com/docs antes de confiar neles.