Claude-skill-registry google-app-engine
git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/google-app-engine" ~/.claude/skills/majiayu000-claude-skill-registry-google-app-engine && rm -rf "$T"
skills/data/google-app-engine/SKILL.mdGoogle App Engine
Status: Production Ready Last Updated: 2026-01-24 Dependencies: Google Cloud SDK (gcloud CLI) Skill Version: 1.0.0
Quick Start (10 Minutes)
1. Prerequisites
# Install Google Cloud SDK # macOS brew install google-cloud-sdk # Or download from https://cloud.google.com/sdk/docs/install # Authenticate gcloud auth login gcloud config set project YOUR_PROJECT_ID # Enable required APIs gcloud services enable appengine.googleapis.com gcloud services enable sqladmin.googleapis.com gcloud services enable secretmanager.googleapis.com
2. Create app.yaml
# app.yaml - Standard Environment (Python 3.12) runtime: python312 instance_class: F2 env_variables: DJANGO_SETTINGS_MODULE: "myproject.settings.production" handlers: # Static files (served directly by App Engine) - url: /static static_dir: staticfiles/ secure: always # All other requests go to the app - url: /.* script: auto secure: always automatic_scaling: min_instances: 0 max_instances: 10 target_cpu_utilization: 0.65
3. Deploy
# Deploy to App Engine gcloud app deploy # Deploy with specific version gcloud app deploy --version=v1 --no-promote # View logs gcloud app logs tail -s default
Standard vs Flexible Environment
Standard Environment (Recommended for Most Apps)
Use when: Building typical web apps, APIs, or services that fit within runtime constraints.
| Aspect | Standard |
|---|---|
| Startup | Fast (milliseconds) |
| Scaling | Scale to zero |
| Pricing | Pay per request |
| Runtimes | Python 3.8-3.12 |
| Instance Classes | F1, F2, F4, F4_1G |
| Max Request | 60 seconds |
| Background | Cloud Tasks only |
# app.yaml - Standard runtime: python312 instance_class: F2
Flexible Environment
Use when: Need custom runtimes, Docker, longer request timeouts, or background threads.
| Aspect | Flexible |
|---|---|
| Startup | Slower (minutes) |
| Scaling | Min 1 instance |
| Pricing | Per-hour VM |
| Runtimes | Any (Docker) |
| Max Request | 60 minutes |
| Background | Native threads |
# app.yaml - Flexible runtime: python env: flex runtime_config: runtime_version: "3.12" resources: cpu: 1 memory_gb: 0.5 disk_size_gb: 10 automatic_scaling: min_num_instances: 1 max_num_instances: 5
Cost Warning: Flexible always runs at least 1 instance (~$30-40/month minimum).
Cloud SQL Connection
Standard Environment (Unix Socket)
App Engine Standard connects to Cloud SQL via Unix sockets, not TCP/IP.
# settings.py import os if os.getenv('GAE_APPLICATION'): # Production: Cloud SQL via Unix socket DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': os.environ['DB_NAME'], 'USER': os.environ['DB_USER'], 'PASSWORD': os.environ['DB_PASSWORD'], 'HOST': f"/cloudsql/{os.environ['CLOUD_SQL_CONNECTION_NAME']}", 'PORT': '', # Empty for Unix socket } } else: # Local development: Cloud SQL Proxy or local DB DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': os.environ.get('DB_NAME', 'localdb'), 'USER': os.environ.get('DB_USER', 'postgres'), 'PASSWORD': os.environ.get('DB_PASSWORD', ''), 'HOST': '127.0.0.1', 'PORT': '5432', } }
# app.yaml env_variables: DB_NAME: "mydb" DB_USER: "myuser" CLOUD_SQL_CONNECTION_NAME: "project:region:instance" # CRITICAL: Beta settings for Cloud SQL socket beta_settings: cloud_sql_instances: "project:region:instance"
CRITICAL: The
beta_settings.cloud_sql_instances enables the Unix socket. Without it, connection fails.
Local Development with Cloud SQL Proxy
# Download and run Cloud SQL Proxy cloud-sql-proxy PROJECT:REGION:INSTANCE --port=5432 # Or use Docker docker run -p 5432:5432 \ gcr.io/cloud-sql-connectors/cloud-sql-proxy:2.8.0 \ PROJECT:REGION:INSTANCE
Static Files with Cloud Storage
Option 1: App Engine Static Handlers (Simple)
# app.yaml handlers: - url: /static static_dir: staticfiles/ secure: always expiration: "1d"
# Collect static files before deploy python manage.py collectstatic --noinput gcloud app deploy
Limitation: Files bundled with deploy, limited to 32MB per file.
Option 2: Cloud Storage (Recommended for Production)
# settings.py from google.cloud import storage GS_BUCKET_NAME = os.environ.get('GS_BUCKET_NAME') STATICFILES_STORAGE = 'storages.backends.gcloud.GoogleCloudStorage' DEFAULT_FILE_STORAGE = 'storages.backends.gcloud.GoogleCloudStorage' # Or with django-storages STORAGES = { "default": { "BACKEND": "storages.backends.gcloud.GoogleCloudStorage", "OPTIONS": { "bucket_name": GS_BUCKET_NAME, "location": "media", }, }, "staticfiles": { "BACKEND": "storages.backends.gcloud.GoogleCloudStorage", "OPTIONS": { "bucket_name": GS_BUCKET_NAME, "location": "static", }, }, }
# Install django-storages pip install django-storages[google] # Create bucket with public access for static files gsutil mb -l us-central1 gs://YOUR_BUCKET_NAME gsutil iam ch allUsers:objectViewer gs://YOUR_BUCKET_NAME
Environment Variables and Secrets
Simple: app.yaml env_variables
# app.yaml - NOT for secrets! env_variables: DJANGO_SETTINGS_MODULE: "myproject.settings.production" DEBUG: "False"
Warning:
app.yaml is committed to source control. Never put secrets here.
Production: Secret Manager
# settings.py from google.cloud import secretmanager def get_secret(secret_id, version="latest"): """Fetch secret from Google Secret Manager.""" client = secretmanager.SecretManagerServiceClient() project_id = os.environ.get('GOOGLE_CLOUD_PROJECT') name = f"projects/{project_id}/secrets/{secret_id}/versions/{version}" response = client.access_secret_version(request={"name": name}) return response.payload.data.decode("UTF-8") # Usage if os.getenv('GAE_APPLICATION'): SECRET_KEY = get_secret('django-secret-key') DB_PASSWORD = get_secret('db-password')
# Create secrets echo -n "your-secret-key" | gcloud secrets create django-secret-key --data-file=- echo -n "db-password" | gcloud secrets create db-password --data-file=- # Grant App Engine access gcloud secrets add-iam-policy-binding django-secret-key \ --member="serviceAccount:YOUR_PROJECT@appspot.gserviceaccount.com" \ --role="roles/secretmanager.secretAccessor"
Scaling Configuration
Automatic Scaling (Default)
automatic_scaling: min_instances: 0 # Scale to zero when idle max_instances: 10 # Cap maximum instances target_cpu_utilization: 0.65 target_throughput_utilization: 0.6 max_concurrent_requests: 80 min_pending_latency: 30ms max_pending_latency: automatic
Basic Scaling (Background Tasks)
basic_scaling: max_instances: 5 idle_timeout: 5m
Use for: Services that need to run background work without scaling to zero immediately.
Manual Scaling (Fixed Instances)
manual_scaling: instances: 3
Use for: Predictable workloads, WebSocket connections, or when you need guaranteed capacity.
Instance Classes
| Class | Memory | CPU | Cost/hour |
|---|---|---|---|
| F1 | 256 MB | 600 MHz | $0.05 |
| F2 | 512 MB | 1.2 GHz | $0.10 |
| F4 | 1 GB | 2.4 GHz | $0.20 |
| F4_1G | 2 GB | 2.4 GHz | $0.30 |
# Recommended for Django instance_class: F2 # 512MB usually sufficient
Upgrade to F4 if you see memory errors or slow response times.
Known Issues Prevention
This skill prevents 6 documented issues:
Issue #1: Cloud SQL Connection Refused
Error:
could not connect to server: Connection refused
Why It Happens: Missing beta_settings.cloud_sql_instances in app.yaml
Prevention: Always include:
beta_settings: cloud_sql_instances: "project:region:instance"
Issue #2: Static Files 404
Error: Static files return 404 after deploy Why It Happens:
collectstatic not run, or handler order wrong
Prevention:
python manage.py collectstatic --noinput
And ensure static handler comes before catch-all:
handlers: - url: /static static_dir: staticfiles/ - url: /.* script: auto
Issue #3: 502 Bad Gateway
Error: 502 errors on first request or under load Why It Happens: Cold start timeout, app takes too long to initialize Prevention:
- Optimize app startup (lazy imports, connection pooling)
- Use
to avoid cold startsmin_instances: 1 - Increase
for more CPU/memoryinstance_class
Issue #4: Memory Limit Exceeded
Error:
Exceeded soft memory limit in logs
Why It Happens: F1 class (256MB) too small for Django + dependencies
Prevention: Use instance_class: F2 minimum for Django apps
Issue #5: Request Timeout
Error:
DeadlineExceededError after 60 seconds
Why It Happens: Standard environment has 60s request limit
Prevention:
- Move long tasks to Cloud Tasks
- Use Flexible environment for longer timeouts
- Optimize database queries
Issue #6: Secret Key in Source Control
Error: Django
SECRET_KEY exposed in git history
Why It Happens: Putting secrets in app.yaml env_variables
Prevention: Use Secret Manager (see Environment Variables section)
Deployment Commands
# Deploy default service gcloud app deploy # Deploy specific service gcloud app deploy app.yaml --service=api # Deploy without promoting (for testing) gcloud app deploy --version=v2 --no-promote # Split traffic between versions gcloud app services set-traffic default --splits=v1=0.5,v2=0.5 # Promote version gcloud app versions migrate v2 # View logs gcloud app logs tail -s default # Open app in browser gcloud app browse # List versions gcloud app versions list # Delete old versions gcloud app versions delete v1 v2 --quiet
Multi-Service Architecture
myproject/ ├── app.yaml # Default service ├── api/ │ └── app.yaml # API service ├── worker/ │ └── app.yaml # Background worker └── dispatch.yaml # URL routing
# dispatch.yaml dispatch: - url: "*/api/*" service: api - url: "*/tasks/*" service: worker
# Deploy all services gcloud app deploy app.yaml api/app.yaml worker/app.yaml dispatch.yaml
Common Patterns
Health Check Endpoint
# urls.py urlpatterns = [ path('_ah/health', lambda r: HttpResponse('ok')), # ... other urls ]
# app.yaml liveness_check: path: "/_ah/health" check_interval_sec: 30 timeout_sec: 4 failure_threshold: 2 success_threshold: 2 readiness_check: path: "/_ah/health" check_interval_sec: 5 timeout_sec: 4 failure_threshold: 2 success_threshold: 2
Warmup Requests
# app.yaml inbound_services: - warmup
# urls.py urlpatterns = [ path('_ah/warmup', warmup_view), ] # views.py def warmup_view(request): """Pre-warm caches and connections.""" from django.db import connection connection.ensure_connection() return HttpResponse('ok')
HTTPS Redirect
# app.yaml handlers: - url: /.* script: auto secure: always # Redirects HTTP to HTTPS
Local Development
Using Cloud SQL Proxy
# Terminal 1: Run Cloud SQL Proxy cloud-sql-proxy PROJECT:REGION:INSTANCE --port=5432 # Terminal 2: Run Django export DB_HOST=127.0.0.1 export DB_PORT=5432 python manage.py runserver
Using dev_appserver (Legacy)
# Not recommended - use Django's runserver instead dev_appserver.py app.yaml
Environment Detection
# settings.py import os # Detect App Engine environment IS_GAE = os.getenv('GAE_APPLICATION') is not None IS_GAE_LOCAL = os.getenv('GAE_ENV') == 'localdev' if IS_GAE: DEBUG = False ALLOWED_HOSTS = ['.appspot.com', '.your-domain.com'] else: DEBUG = True ALLOWED_HOSTS = ['localhost', '127.0.0.1']
Bundled Resources
Templates (templates/)
- Standard environment configurationapp.yaml
- Flexible environment configurationapp-flex.yaml
- Common dependencies for App Enginerequirements.txt
References (references/)
- Detailed instance class comparisoninstance-classes.md
- Error messages and solutionscommon-errors.md
Official Documentation
- App Engine Python: https://cloud.google.com/appengine/docs/standard/python3
- app.yaml Reference: https://cloud.google.com/appengine/docs/standard/reference/app-yaml
- Cloud SQL: https://cloud.google.com/sql/docs/postgres/connect-app-engine-standard
- Secret Manager: https://cloud.google.com/secret-manager/docs
- Scaling: https://cloud.google.com/appengine/docs/standard/how-instances-are-managed
Dependencies
# requirements.txt gunicorn>=21.0.0 google-cloud-secret-manager>=2.16.0 google-cloud-storage>=2.10.0 django-storages[google]>=1.14.0 psycopg2-binary>=2.9.9 # For PostgreSQL
Production Checklist
-
in Secret Manager (not app.yaml)SECRET_KEY -
in production settingsDEBUG = False -
configured for your domainALLOWED_HOSTS -
runs before deploycollectstatic -
setbeta_settings.cloud_sql_instances - Instance class appropriate (F2+ for Django)
- HTTPS enforced (
)secure: always - Health check endpoint configured
- Error monitoring set up (Cloud Error Reporting)
Last verified: 2026-01-24 | Skill version: 1.0.0