Local Google Cloud emulator

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
108 services 7 ways to connect 0 cloud spend REST :4443 · gRPC :8085
01The gap kiri fills AWS developers got one local endpoint for everything. GCP developers never did.
Real GCP

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.

Official emulators

Five binaries, five services

Google ships emulators for Pub/Sub, Firestore, Bigtable, Datastore, and Spanner. Separate processes, separate flags, and no view of cost.

kiri

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.

02Quickstart Running, and talking to it from your language, in under a minute.
01

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
02

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}
03

Connect your client

Pick your tool. Nothing in your app changes but the endpoint. See the full client guide below.

03Point any tool at kiri Same emulator, seven front doors. Every Google Cloud client takes a custom endpoint.
# 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"}'
Cost Explorer, for GCP

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.

04108 services, 13 categories Each one persists to disk and survives a restart.
13 categories
05Configuration Set via environment variables. Unset means in-memory only.
VariableDefaultPurpose
KIRI_HOST0.0.0.0Bind address
KIRI_HTTP_PORT4443REST / JSON port
KIRI_GRPC_PORT8085gRPC port (Pub/Sub, Firestore)
KIRI_DATA_DIRunsetDirectory for state snapshots. Enables persistence
KIRI_LOG_LEVELinfodebug, 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