NDB GAE App on Localhost

NDB GAE App on Localhost

Published: 2-Oct-2025 ⏱ 2 min read

If you want to test a Google Cloud NDB app locally before pushing it to Cloud Run, you can wire it up with the Firestore emulator (in Datastore mode). Here’s a minimal setup.

Project Layout

app/
    main.py
    models.py
    templates/index.html
    requirements.txt
    Makefile

Requirements

# requirements.txt
Flask==3.0.3
google-cloud-ndb==2.2.2

Models

# models.py
from google.cloud import ndb

class Counter(ndb.Model):
    value = ndb.IntegerProperty(default=0)

App

# main.py
import os
from flask import Flask, render_template
from google.cloud import ndb
from models import Counter

app = Flask(__name__)


# NDB client setup
def get_client():
    project_id = os.getenv("DATASTORE_PROJECT_ID", "demo-project")
    return ndb.Client(project=project_id)


@app.route("/")
def index():
    client = get_client()
    with client.context():
        counter = Counter.get_by_id("main")
        if not counter:
            counter = Counter(id="main", value=0)
        counter.value += 1
        counter.put()
        return render_template("index.html", count=counter.value)


if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8081, debug=True)

HTML Template

<!-- templates/index.html -->
<!doctype html>
<html>
  <body>
    <h1>Counter Value: {{ count }}</h1>
  </body>
</html>

Makefile

PROJECT_ID=demo-project
DATASTORE_EMULATOR_HOST_PORT=localhost:8082
PYTHON3=.venv/bin/python3

run_emulator:
	gcloud beta emulators firestore start \
		--host-port=$(DATASTORE_EMULATOR_HOST_PORT) \
		--project=$(PROJECT_ID) \
		--database-mode=datastore-mode


run_app:
	DATASTORE_PROJECT_ID=$(PROJECT_ID) \
	DATASTORE_EMULATOR_HOST=$(DATASTORE_EMULATOR_HOST_PORT) \
	FLASK_ENV=development \
	$(PYTHON3) main.py

install:
    python3 -m venv .venv
    .venv/bin/pip install -r requirements.txt

Running the App

  1. Start the emulator:
make run_emulator
  1. In another terminal, run the app:
make run_app
  1. Visit http://localhost:8081. Each refresh increments the counter.

That’s it: a tiny Flask + NDB app, backed by the Firestore emulator in Datastore mode. Ready to push to Cloud Run later.


End Result

Counter App Screenshot