1---
2title: GCP
3description: Google Cloud in one Effect program — Cloud Run services and jobs, Firestore, Pub/Sub, BigQuery, Secret Manager, and Memorystore, with IAM granted by the bindings themselves.
4---
5
6GCP with alchemy means the Cloud Run service and everything it talks
7to live in the same TypeScript program. The Firestore database is
8declared on the service that reads it. The service calls Google APIs
9through typed bindings that carry their own IAM. `bun alchemy deploy`
10builds the container, mints a runtime service account, grants exactly
11the roles the bindings need, and ships it; `alchemy destroy` takes all
12of that back down, service account included.
13
14New here? [Set up credentials](/gcp/setup), then pick the guide that
15matches what you're building.
16
17## What are you building?
18
19- **An HTTP API with a datastore and a secret** →
20 [Serve an API on Cloud Run](/gcp/guides/cloud-run-api). A link
21 shortener on one Cloud Run service, Firestore for state, Secret
22 Manager for the API key.
23- **An ingestion pipeline** →
24 [Ingest events into BigQuery](/gcp/guides/event-pipeline). A service
25 publishes to Pub/Sub, a Cloud Run Job drains the subscription into
26 BigQuery, and the service triggers the job.
27- **Something that needs a cache** →
28 [Cache with Memorystore](/gcp/guides/memorystore). Redis on a
29 private IP, reached over Direct VPC egress.
30- **Wondering where the IAM comes from** →
31 [How bindings grant IAM](/gcp/guides/bindings).
32
33Each guide walks a runnable example under `examples/` end to end.
34
35## What it looks like
36
37```typescript
38// src/Api.ts
39export default class Api extends GCP.Function<Api>()(
40 "Api",
41 { main: import.meta.url, location: "us-central1" },
42 Effect.gen(function* () {
43 // Resources — deployed with the service.
44 const links = yield* GCP.Firestore.Database("Links", {
45 location: "us-central1",
46 type: "FIRESTORE_NATIVE",
47 });
48
49 // A binding grants its role on the runtime service account.
50 const db = yield* GCP.Firestore.ReadWriteDatabase(links);
51
52 return {
53 fetch: Effect.gen(function* () {
54 yield* db.set("links/demo", { url: "https://alchemy.run" });
55 const link = yield* db.get("links/demo");
56 return yield* HttpServerResponse.json(link?.fields ?? {});
57 }).pipe(Effect.orDie),
58 };
59 }).pipe(Effect.provide(GCP.Firestore.ReadWriteDatabaseHttp)),
60) {}
61```
62
63Three ideas carry the whole provider:
64
65- **Resources** (`Firestore.Database`, `PubSub.Topic`,
66 `BigQuery.Table`, `SecretManager.Secret`, `Redis.Instance`, …) are
67 Stack-managed. Alchemy creates, updates, and deletes them.
68- **Bindings** (`ReadWriteDatabase`, `WriteTopic`, `ReadTable`,
69 `ReadSecret`, `RunJob`, …) are what the container calls at
70 runtime. Yielding one grants the IAM role it needs on a per-host
71 service account and returns a callable. Provide the matching `*Http`
72 layer once at the end.
73- **Outputs** like `table.tableId` are yielded at plan time to get an
74 accessor, then yielded again where the value is needed. That's how a
75 resource id reaches runtime without an environment variable.
76
77## Hosts
78
79| Host | Entry | Use it for |
80| --- | --- | --- |
81| `GCP.Function` (= `GCP.Run.Service`) | `fetch` | HTTP services that scale to zero |
82| `GCP.Run.Job` | `run` | batch work that starts, finishes, and exits |
83| `GCP.Run.WorkerPool` | `run` | always-on consumers with no request path |
84| `GCP.CloudFunctions.Function` | `fetch` | gen2 functions built in the cloud (Node.js) |
85
86The Run hosts build a container image locally, so Docker has to be
87running to deploy them. Cloud Functions build from an uploaded archive.
88
89## Event sources
90
91Google calls your code through an event source: `consumeTopicMessages`
92(Pub/Sub push or pull), `consumeBucketEvents` (Cloud Storage),
93`consumeSchedule` (Cloud Scheduler), and `consumeEvents` (Eventarc).
94See [How bindings grant IAM](/gcp/guides/bindings#event-sources).
95
96## Examples
97
98Every example deploys, is exercised by a live integration test, and
99tears itself down.
100
101| Example | What it shows |
102| --- | --- |
103| `gcp-cloud-run-api` | HTTP API on Cloud Run with Firestore and Secret Manager |
104| `gcp-cloud-function` | Effect-native Cloud Function (Node 22) over Firestore |
105| `gcp-event-pipeline` | Service → Pub/Sub → Cloud Run Job → BigQuery |
106| `gcp-pubsub-worker` | Job queue: API publishes, a WorkerPool pulls |
107| `gcp-pubsub-fanout` | Push fan-out to two services, attribute filter, dead-letter topic |
108| `gcp-storage-uploads` | Upload API plus a bucket-event indexer |
109| `gcp-cron` | Two Cloud Scheduler crons on one service, rows in BigQuery |
110| `gcp-scheduled-job` | Nightly Cloud Run Job from Cloud Scheduler and an admin route |
111| `gcp-eventarc-firestore` | Eventarc reacting to Firestore document creation |
112| `gcp-secrets-kms` | Encryption API with KMS and a Secret Manager API key |
113| `gcp-service-to-service` | Private service called with Google-signed identity (`InvokeService`) |
114| `gcp-cloud-sql-drizzle` | Drizzle over Cloud SQL Postgres via the Cloud Run socket |
115| `gcp-memorystore-redis` | Rate limiter on Memorystore over Direct VPC |
116| `gcp-gke` | Guestbook on GKE Autopilot: Deployments, a seed Job, Firestore via Workload Identity |
117| `gcp-vertex-ai` | Gemini on Vertex AI (`GenerateContent`) |
118| `gcp-static-site` | Static site from a public Cloud Storage bucket |
119
120## Reference
121
122[Run.Service](/providers/gcp/run/service) ·
123[Run.Job](/providers/gcp/run/job) ·
124[Firestore.Database](/providers/gcp/firestore/database) ·
125[PubSub.Topic](/providers/gcp/pubsub/topic) ·
126[BigQuery.Table](/providers/gcp/bigquery/table) ·
127[SecretManager.Secret](/providers/gcp/secretmanager/secret) ·
128[Storage.Bucket](/providers/gcp/storage/bucket) ·
129[Redis.Instance](/providers/gcp/redis/instance)
130
131The full list is under **Resources** in the sidebar.
132
133## Out of scope
134
135Alchemy manages infrastructure, not end-user content. APIs whose objects
136are a person's data — Gmail messages and settings, Forms, Calendar events, Drive files,
137Classroom courses, Chat messages, Tasks, Keep notes, People contacts,
138Blogger posts, YouTube videos and reports, Fitness data, Apps Script
139projects, Street View photos, Fact Check claims, and Business Profile
140listings — are deliberately not modelled as resources. Neither is
141`prodtt-sasportal`, a test-environment copy of the SAS Portal API.
142
143The advertising and marketing APIs — Analytics Admin, Display & Video 360,
144Tag Manager, Workspace Reseller, AdSense, AdSense Platform, Ad Exchange Buyer
145II, Campaign Manager 360 (DFA Reporting), and DoubleClick Bid Manager —
146are also out of scope: they act on a user's accounts and require user OAuth
147scopes, which a service account or Workload Identity host cannot hold. The
148Content API for Shopping and Apigee Registry are retired by Google and are not
149modelled.