Claude API Google Cloud Functions Setup Guide
Setting up the Claude API inside Google Cloud Functions means writing an HTTP-triggered (or background) function that calls Anthropic's Messages API, storing your API key securely, and deploying it with the right runtime and memory settings. The whole thing takes about 15 minutes once you know the gotchas around environment variables, timeouts, and streaming.
This guide walks through a working setup for both the 1st gen and 2nd gen Cloud Functions runtime, using Node.js, and covers what breaks when people try this for the first time: cold starts, missing dependencies, and functions that time out on long Claude responses.
Prerequisites
You need:
- A Google Cloud project with billing enabled and the Cloud Functions API turned on
- The
gcloudCLI installed and authenticated - A Claude API key — either directly from Anthropic, or a
sub_live_...key from SubToAPI if you want a single key that also gives you usage metadata and team access control - Node.js 18+ locally for testing before deploy
Project structure
Cloud Functions (2nd gen) expects a simple layout:
claude-function/
├── index.js
├── package.json
Install the Anthropic SDK (or just use fetch, since Cloud Functions runtimes ship with it natively from Node 18 onward — no extra dependency required if you want to keep the bundle small):
npm init -y
npm install @anthropic-ai/sdk
Writing the function
Here's a minimal HTTP-triggered function that accepts a prompt and returns Claude's response:
const Anthropic = require('@anthropic-ai/sdk');
const client = new Anthropic({
apiKey: process.env.CLAUDE_API_KEY,
});
exports.claudeHandler = async (req, res) => {
if (req.method !== 'POST') {
res.status(405).send('Use POST');
return;
}
try {
const { prompt } = req.body;
if (!prompt) {
res.status(400).json({ error: 'Missing "prompt" in request body' });
return;
}
const message = await client.messages.create({
model: 'claude-sonnet-4-5',
max_tokens: 1024,
messages: [{ role: 'user', content: prompt }],
});
res.status(200).json(message);
} catch (err) {
console.error(err);
res.status(500).json({ error: err.message });
}
};
If you're routing through SubToAPI instead of calling Anthropic directly, swap the client setup for a plain fetch call:
exports.claudeHandler = async (req, res) => {
const { prompt } = req.body;
const response = await fetch('https://api.subtoapi.app/v1/messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${process.env.SUBTOAPI_KEY}`,
},
body: JSON.stringify({
model: 'claude-sonnet-4-5',
max_tokens: 1024,
messages: [{ role: 'user', content: prompt }],
}),
});
const data = await response.json();
res.status(response.status).json(data);
};
This is useful if you're already managing a team of developers calling Claude from multiple Cloud Functions and want one dashboard for usage and cost tracking instead of a raw Anthropic key passed around in environment variables. See the quickstart for the request format.
Storing the API key
Never hardcode the key or commit it in .env files that get bundled with the function. Use Google Secret Manager:
echo -n "sk-ant-your-key-here" | gcloud secrets create claude-api-key --data-file=-
Then reference it at deploy time instead of a plain environment variable — this keeps the key out of build logs and the Cloud Functions console.
Deploying
For 2nd gen Cloud Functions (recommended — it runs on Cloud Run under the hood, giving you longer timeouts and more memory headroom):
gcloud functions deploy claudeHandler \
--gen2 \
--runtime=nodejs20 \
--trigger-http \
--allow-unauthenticated \
--memory=256MB \
--timeout=60s \
--set-secrets=CLAUDE_API_KEY=claude-api-key:latest \
--region=us-central1
Drop --allow-unauthenticated if the function should only be called by other authenticated services — for anything public-facing, put an API gateway or your own auth layer in front of it.
Timeout and memory settings that matter
Claude responses, especially longer ones, can take 10-30 seconds to generate depending on max_tokens and model choice. The default Cloud Functions timeout (60s for HTTP, lower for background) is usually fine, but if you're generating long completions or doing multi-turn tool use, bump it:
- Timeout: set to at least 120s for anything beyond simple Q&A
- Memory: 256MB is enough for basic JSON handling; bump to 512MB if you're parsing large documents or images before sending them to Claude
- Concurrency: 2nd gen functions support concurrent requests per instance — set
--concurrency=1if your function holds shared state, otherwise leave it default for better cost efficiency
Streaming inside Cloud Functions
Streaming Server-Sent Events from a Cloud Function is possible on 2nd gen (since it runs on Cloud Run), but it adds complexity: you need to keep the HTTP response open and pipe chunks through as they arrive. For most Cloud Functions use cases — webhooks, scheduled jobs, lightweight API endpoints — a single blocking call is simpler and more reliable. If you need streaming as a core feature, a long-running Cloud Run service is usually a better fit than Cloud Functions. SubToAPI's streaming docs cover the SSE format if you go that route.
Testing locally before deploy
Use the Functions Framework to test without redeploying every time:
npm install @google-cloud/functions-framework
npx functions-framework --target=claudeHandler
Then hit it with curl:
curl -X POST http://localhost:8080 \
-H "Content-Type: application/json" \
-d '{"prompt": "Summarize this in one sentence: ..."}'
Common mistakes
- Forgetting
req.bodyparsing — Cloud Functions parses JSON automatically if theContent-Typeheader is set correctly; if it isn't,req.bodycomes back empty - Setting timeout too low — the default on 1st gen functions is 60s, but some combination of large prompts and long
max_tokenswill blow past that - Leaking the API key in logs — never
console.logthe full request object if it contains headers - Cold starts on low-traffic functions — if latency matters, consider
--min-instances=1to keep one warm instance, at a small ongoing cost
If you want to skip key management and secret rotation entirely, generating a sub_live_... key from SubToAPI and pointing your Cloud Function at it gives you the same Messages API shape plus per-key usage limits, which is useful if multiple functions or team members are hitting Claude under one account. Check pricing for plan details.
Questions
Do I need the Anthropic SDK, or can I just use fetch in a Cloud Function? Fetch is enough. Node 18+ runtimes on Cloud Functions include native fetch, so you can skip the SDK dependency entirely and keep your deployment package smaller — useful since cold start time scales with bundle size.
What timeout should I set for a Claude-calling Cloud Function? Start at 120 seconds for anything beyond short completions. Long max_tokens values or multi-turn tool use can take well past the default 60-second timeout on 1st gen functions.
Can I stream Claude responses from a Cloud Function? Technically yes on 2nd gen (Cloud Run-backed) functions, but it's fragile. For streaming-heavy use cases, a dedicated Cloud Run service or a hosted API layer is more reliable than a short-lived function.