Google Cloud,
minus the cloud.
One binary emulates 108 GCP services on a single local endpoint. Point the Go, Python, Node, or Java SDK at it. Point gcloud, Terraform, or plain REST at it. Build, test, and price a whole architecture with no project, no credentials, no bill.
docker run -p 4443:4443 -p 8085:8085 kiri
Slow, costly, online only
Every test run needs credentials and a network round trip, spends real money, pollutes shared projects, and cannot run offline or in CI cheaply.
Five binaries, five services
Google ships emulators for Pub/Sub, Firestore, Bigtable, Datastore, and Spanner. Separate processes, separate flags, and no view of cost.
One endpoint. The whole platform. Priced.
108 services answer locally, share state across REST and gRPC, persist to disk, and carry a real pricing catalog. Any Google Cloud client works, because every one of them accepts an endpoint override.
Start the emulator
Build the image from source and run it. REST on 4443, gRPC on 8085.
# one binary, two ports docker build -t kiri -f docker/Dockerfile . docker run -p 4443:4443 -p 8085:8085 kiri
Confirm it is up
A bare request to the root returns the service count.
curl http://localhost:4443/
{"emulator":"kiri","status":"ok","services":108,"grpc_port":8085}Connect your client
Pick your tool. Nothing in your app changes but the endpoint. See the full client guide below.
# Storage and Pub/Sub honor the standard emulator env vars export STORAGE_EMULATOR_HOST=http://localhost:4443 export PUBSUB_EMULATOR_HOST=localhost:8085
client, _ := storage.NewClient(ctx, option.WithEndpoint("http://localhost:4443/storage/v1/"), option.WithoutAuthentication())
export STORAGE_EMULATOR_HOST=http://localhost:4443 export PUBSUB_EMULATOR_HOST=localhost:8085
from google.cloud import storage client = storage.Client( project="my-project", client_options={"api_endpoint": "http://localhost:4443"})
export PUBSUB_EMULATOR_HOST=localhost:8085
const {Storage} = require('@google-cloud/storage'); const storage = new Storage({ projectId: 'my-project', apiEndpoint: 'http://localhost:4443', });
Storage storage = StorageOptions.newBuilder() .setHost("http://localhost:4443") .setProjectId("my-project") .build() .getService();
Pub/Sub reads PUBSUB_EMULATOR_HOST the same as every other language.
# skip auth, then override the endpoint per service gcloud config set auth/disable_credentials true gcloud config set api_endpoint_overrides/storage http://localhost:4443/storage/v1/ gcloud storage buckets list
provider "google" { project = "my-project" # per-service custom endpoints point Terraform at kiri storage_custom_endpoint = "http://localhost:4443/storage/v1/" compute_custom_endpoint = "http://localhost:4443/compute/v1/" pubsub_custom_endpoint = "http://localhost:4443/v1/" }
Set GOOGLE_OAUTH_ACCESS_TOKEN=dummy so the provider skips real auth.
# the wire format is the real GCP JSON API curl -X POST "http://localhost:4443/storage/v1/b?project=my-project" \ -H 'Content-Type: application/json' \ -d '{"name":"my-bucket"}'
Price the architecture before you build it.
kiri carries a live pricing catalog with real Compute, Storage, and BigQuery SKUs. Provision resources locally, then ask what a month would cost. No other GCP emulator does this.
The panel is a real run: an order pipeline (Storage to Pub/Sub to a Compute worker) provisioned through the actual SDKs, priced against the catalog, and checked against a budget.
| Variable | Default | Purpose |
|---|---|---|
KIRI_HOST | 0.0.0.0 | Bind address |
KIRI_HTTP_PORT | 4443 | REST / JSON port |
KIRI_GRPC_PORT | 8085 | gRPC port (Pub/Sub, Firestore) |
KIRI_DATA_DIR | unset | Directory for state snapshots. Enables persistence |
KIRI_LOG_LEVEL | info | debug, info, warn, or error |
# persistent run: state survives container restarts docker run -p 4443:4443 -p 8085:8085 \ -e KIRI_DATA_DIR=/data -v kiri-data:/data kiri