neo4j-aura-provisioning-skill · diff

v0.1.0 to v1.0.0

418 added, 78 removed. Audit B to B.

---
name: neo4j-aura-provisioning-skill
- description: >
- Use when programmatically creating, pausing, resuming, resizing, or deleting Neo4j
- Aura instances: Aura CLI (aura-cli), Aura REST API, or scripted provisioning in
- CI/CD pipelines. Also covers downloading credentials, listing tenants, and managing
- instance lifecycles. Does NOT cover Cypher queries or application code — use
- neo4j-cypher-skill or driver skills. Does NOT cover general CLI tools
- (neo4j-admin, cypher-shell) — use neo4j-cli-tools-skill.
- status: draft
- version: 0.1.0
- allowed-tools: Bash, WebFetch
+ description: Provisions and manages Neo4j Aura instances via CLI (aura-cli v1.7+) or REST API.
+ Use when creating, pausing, resuming, resizing, or deleting AuraDB Free/Professional/Business Critical/VDC
+ instances; downloading credentials; scripting CI/CD pipelines; polling async status; or using the
+ Terraform neo4j/neo4j-aura provider. Covers auth setup (client credentials OAuth2), credential
+ lifecycle (download once — never recoverable), instance type selection, region codes, and Python
+ provisioning scripts. Does NOT handle Cypher queries — use neo4j-cypher-skill.
+ Does NOT cover Graph Data Science algorithms — use neo4j-gds-skill or neo4j-aura-graph-analytics-skill.
+ Does NOT cover neo4j-admin/cypher-shell — use neo4j-cli-tools-skill.
+ version: 1.0.0
+ allowed-tools: Bash WebFetch
---
- # Neo4j Aura Provisioning Skill
+ ## When to Use
+ - Creating an Aura instance (CLI, REST API, Python, Terraform)
+ - Pausing, resuming, resizing, or deleting an instance
+ - Downloading initial credentials from creation response
+ - Polling instance status: `creating` → `running`
+ - Setting up CI/CD provisioning or teardown pipelines
+ - Choosing instance tier (Free vs Professional vs Business Critical vs VDC)
- > **Status: Draft / WIP** — Content is a placeholder. Reference files and Aura API details to be added.
- > Fetch current API reference: https://neo4j.com/docs/aura/platform/api/specification/
+ ## When NOT to Use
+ - **Cypher queries against running DB** → `neo4j-cypher-skill`
+ - **GDS algorithms on Aura** → `neo4j-gds-skill` (Pro with plugin) or `neo4j-aura-graph-analytics-skill` (serverless)
+ - **neo4j-admin / cypher-shell** → `neo4j-cli-tools-skill`
+ - **Application driver setup** → use a language driver skill (python, javascript, java, go, dotnet)
- ## When to Use
+ ---
- - Creating a Neo4j Aura instance programmatically (CLI, API, Python script)
- - Managing instance lifecycle: pause, resume, resize, delete
- - Downloading credentials and `.env` files from the Aura Console or API
- - Listing tenants and instances in a CI/CD pipeline
- - Provisioning Aura for automated testing environments
+ ## Instance Tier Decision Table
- ## When NOT to Use
+ | Tier | API type code | Memory | GDS | Replicas | Use when |
+ |---|---|---|---|---|---|
+ | AuraDB Free | `free-db` | 1 GB | ❌ | ❌ | Dev/demo; ≤200k nodes/400k rels |
+ | AuraDB Professional | `professional-db` | 2–64 GB | plugin available | ❌ | Production workloads |
+ | AuraDB Business Critical | `business-critical` | 4–384 GB | plugin available | ✅ | HA, multi-AZ, SLA |
+ | AuraDB VDC | `enterprise-db` | custom | ✅ | ✅ | Dedicated infra, compliance |
+ | AuraDS Professional | `professional-ds` | 2–64 GB | ✅ built-in | ❌ | Data science / GDS |
+ | AuraDS Enterprise | `enterprise-ds` | custom | ✅ | ✅ | Enterprise GDS |
- - **Cypher queries against a running database** → use `neo4j-cypher-skill`
- - **Application driver setup** → use a driver skill (python, javascript, java, etc.)
- - **neo4j-admin / cypher-shell / CLI tools** → use `neo4j-cli-tools-skill`
+ **AuraDB Free limits**: 200k nodes, 400k rels; auto-pauses after 72 h inactivity; deleted if paused >30 days; no resize.
---
- ## Setup
+ ## Auth Setup
+ ### CLI (aura-cli v1.7+)
+
+ Install (binary, not pip):
```bash
- pip install aura-cli # Python CLI
- aura-cli auth login # opens browser for OAuth; saves token to ~/.aura/credentials
+ # macOS
+ curl -L https://github.com/neo4j/aura-cli/releases/latest/download/aura-cli-darwin-amd64.tar.gz | tar xz
+ sudo mv aura-cli /usr/local/bin/
+ aura-cli -v # verify
```
- Or use environment variables for headless/CI:
+ Add credentials (from console.neo4j.io → Account Settings → API Credentials):
```bash
- export AURA_CLIENT_ID=<client-id>
- export AURA_CLIENT_SECRET=<client-secret>
+ aura-cli credential add \
+ --name "my-creds" \
+ --client-id "$AURA_CLIENT_ID" \
+ --client-secret "$AURA_CLIENT_SECRET"
+ aura-cli credential use --name "my-creds"
```
+ Verify:
+ ```bash
+ aura-cli instance list --output table
+ ```
+
+ ### REST API — Get Bearer Token
+
+ Token endpoint: `POST https://api.neo4j.io/oauth/token`
+ Token expires: **3600 s (1 h)**. On 403 → refresh token.
+
+ ```bash
+ TOKEN=$(curl -s --request POST 'https://api.neo4j.io/oauth/token' \
+ --user "${AURA_CLIENT_ID}:${AURA_CLIENT_SECRET}" \
+ --header 'Content-Type: application/x-www-form-urlencoded' \
+ --data-urlencode 'grant_type=client_credentials' \
+ | jq -r '.access_token')
+ echo "Token: ${TOKEN:0:20}..."
+ ```
+
+ Use in all subsequent calls: `--header "Authorization: Bearer $TOKEN"`
+
---
- ## Core CLI Commands (Step-by-Step)
+ ## Step 1 — List Tenants (Projects)
- **Step 1 — List tenants:**
+ CLI:
```bash
- aura-cli tenants list
+ aura-cli tenants list --output table
+ # Copy TENANT_ID for create operations
```
- **Step 2 — Create instance (capture output immediately):**
+ REST:
```bash
- # Add --format json to capture credentials programmatically
- aura-cli instances create \
+ curl -s https://api.neo4j.io/v1/tenants \
+ -H "Authorization: Bearer $TOKEN" | jq '.data[] | {id, name}'
+ ```
+
+ ---
+
+ ## Step 2 — Create Instance
+
+ CRITICAL: **Capture output immediately.** Initial password shown ONCE — never retrievable again.
+ If lost: delete and recreate. Store `aura-creds.json` before doing anything else.
+
+ ### CLI
+
+ ```bash
+ aura-cli instance create \
--name "my-instance" \
- --region us-east-1 \
- --cloud-provider aws \
- --type free-db \
- --tenant-id <tenant-id> \
- --format json | tee aura-creds.json
- # Initial password is shown ONCE here. Save aura-creds.json immediately.
- # If lost: you must delete and recreate the instance — there is no password reset.
+ --cloud-provider gcp \
+ --region europe-west1 \
+ --type professional-db \
+ --tenant-id "$TENANT_ID" \
+ --output json | tee aura-creds.json
+
+ # Extract for .env
+ INSTANCE_ID=$(jq -r '.id' aura-creds.json)
+ PASSWORD=$(jq -r '.password' aura-creds.json)
```
- **Step 3 — Wait for RUNNING status (with timeout):**
+ ### REST API (full create)
+
```bash
- for i in $(seq 1 60); do
- STATUS=$(aura-cli instances get --instance-id <id> --format json | jq -r '.status')
- echo "Attempt $i: $STATUS"
+ RESPONSE=$(curl -s -X POST https://api.neo4j.io/v1/instances \
+ -H "Authorization: Bearer $TOKEN" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "name": "my-instance",
+ "cloud_provider": "gcp",
+ "region": "europe-west1",
+ "type": "professional-db",
+ "tenant_id": "'"$TENANT_ID"'",
+ "memory": "4GB",
+ "version": "5"
+ }')
+ echo "$RESPONSE" | tee aura-creds.json
+ INSTANCE_ID=$(echo "$RESPONSE" | jq -r '.data.id')
+ PASSWORD=$(echo "$RESPONSE" | jq -r '.data.password')
+ ```
+
+ Instance create request body fields:
+
+ | Field | Required | Values |
+ |---|---|---|
+ | `name` | ✅ | any string |
+ | `cloud_provider` | ✅ | `gcp` `aws` `azure` |
+ | `region` | ✅ | see region table |
+ | `type` | ✅ | see tier table |
+ | `tenant_id` | ✅ | from tenant list |
+ | `memory` | ✗ | `1GB` `2GB` `4GB` `8GB` … `384GB` |
+ | `version` | ✗ | `5` (default) |
+
+ ---
+
+ ## Step 3 — Poll Until RUNNING (CRITICAL — All Ops Are Async)
+
+ ALL lifecycle operations (create, pause, resume, resize) are async. Do NOT attempt connection or next operation until status = `running` (or `paused` for pause op).
+
+ ```bash
+ poll_status() {
+ local INSTANCE_ID=$1 TARGET=$2 MAX_WAIT=${3:-600}
+ local ELAPSED=0 STATUS
+ echo "Polling for status=$TARGET (max ${MAX_WAIT}s)..."
+ while [ $ELAPSED -lt $MAX_WAIT ]; do
+ STATUS=$(aura-cli instance get --instance-id "$INSTANCE_ID" --output json \
+ | jq -r '.status' 2>/dev/null)
+ echo " [${ELAPSED}s] status=$STATUS"
+ [ "$STATUS" = "$TARGET" ] && echo "Ready." && return 0
+ [ "$STATUS" = "destroying" ] && echo "ERROR: instance is being destroyed" && return 1
+ sleep 10; ELAPSED=$((ELAPSED + 10))
+ done
+ echo "TIMEOUT after ${MAX_WAIT}s — last status: $STATUS" && return 1
+ }
+
+ poll_status "$INSTANCE_ID" "running" 600
+ ```
+
+ REST equivalent:
+ ```bash
+ while true; do
+ STATUS=$(curl -s "https://api.neo4j.io/v1/instances/$INSTANCE_ID" \
+ -H "Authorization: Bearer $TOKEN" | jq -r '.data.status')
[ "$STATUS" = "running" ] && break
- [ $i -eq 60 ] && echo "TIMEOUT: instance did not start after 10 min" && exit 1
sleep 10
done
```
- **Step 4 — Write .env:**
+ Status lifecycle:
+ ```
+ creating → running → pausing → paused → resuming → running
+ ↘ destroying → (gone)
+ ```
+
+ ---
+
+ ## Step 4 — Write .env and Verify
+
```bash
- cat <<EOF > .env
- NEO4J_URI=neo4j+s://<instance-id>.databases.neo4j.io
+ CONNECTION_URI="neo4j+s://${INSTANCE_ID}.databases.neo4j.io"
+
+ cat > .env <<EOF
+ NEO4J_URI=${CONNECTION_URI}
NEO4J_USERNAME=neo4j
- NEO4J_PASSWORD=<password>
+ NEO4J_PASSWORD=${PASSWORD}
NEO4J_DATABASE=neo4j
+ AURA_INSTANCE_ID=${INSTANCE_ID}
EOF
- grep -q '.env' .gitignore || echo '.env' >> .gitignore
+
+ # Ensure .env never committed
+ grep -q '^\.env$' .gitignore 2>/dev/null || echo '.env' >> .gitignore
+
+ # Verify connectivity
+ cypher-shell -a "$CONNECTION_URI" -u neo4j -p "$PASSWORD" "RETURN 'connected' AS status"
```
- **Step 5 — Verify connectivity:**
+ ---
+
+ ## Step 5 — Lifecycle Operations
+
+ All operations require instance in the correct state. Wrong-state ops return 4xx error.
+
+ ### Pause
+ Required state: `running`
```bash
- source .env
- cypher-shell -a "$NEO4J_URI" -u "$NEO4J_USERNAME" -p "$NEO4J_PASSWORD" \
- "RETURN 'connected' AS status"
+ aura-cli instance pause --instance-id "$INSTANCE_ID"
+ poll_status "$INSTANCE_ID" "paused" 600
```
+ ### Resume
+ Required state: `paused`
+ ```bash
+ aura-cli instance resume --instance-id "$INSTANCE_ID"
+ poll_status "$INSTANCE_ID" "running" 900 # resume can take longer
+ ```
+
+ ### Resize (Professional+ only — NOT Free)
+ Required state: `running`; instance remains available during resize.
+ ```bash
+ # REST only — CLI resize not available in v1.7
+ curl -s -X PATCH "https://api.neo4j.io/v1/instances/$INSTANCE_ID" \
+ -H "Authorization: Bearer $TOKEN" \
+ -H "Content-Type: application/json" \
+ -d '{"memory": "8GB"}'
+ poll_status "$INSTANCE_ID" "running" 600
+ # Cannot reduce below current usage level
+ ```
+
+ ### Delete
+ IRREVERSIBLE. Export snapshots first if data needed.
+ ```bash
+ aura-cli instance delete --instance-id "$INSTANCE_ID"
+ # No poll needed — immediate
+ ```
+
+ REST:
+ ```bash
+ curl -s -X DELETE "https://api.neo4j.io/v1/instances/$INSTANCE_ID" \
+ -H "Authorization: Bearer $TOKEN"
+ ```
+
---
- ## Aura Free Limitations
+ ## Python CI/CD Provisioning Script
- If provisioning a `free-db` instance, be aware:
- - Max 200,000 nodes and 400,000 relationships
- - No GDS (Graph Data Science) — suggest `neo4j-gds-skill` only for Pro/Enterprise
- - No read replicas or clustering
- - Instance pauses after 3 days of inactivity (auto-resumes on connection)
+ ```python
+ import os, time, requests
+ CLIENT_ID = os.environ["AURA_CLIENT_ID"]
+ CLIENT_SECRET = os.environ["AURA_CLIENT_SECRET"]
+ BASE = "https://api.neo4j.io/v1"
+
+ def get_token() -> str:
+ r = requests.post(
+ "https://api.neo4j.io/oauth/token",
+ auth=(CLIENT_ID, CLIENT_SECRET),
+ data={"grant_type": "client_credentials"},
+ )
+ r.raise_for_status()
+ return r.json()["access_token"]
+
+ def auth_headers(token: str) -> dict:
+ return {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
+
+ def create_instance(token: str, tenant_id: str, **kwargs) -> dict:
+ payload = {"tenant_id": tenant_id, "version": "5", **kwargs}
+ r = requests.post(f"{BASE}/instances", headers=auth_headers(token), json=payload)
+ r.raise_for_status()
+ return r.json()["data"] # contains id, password, connection_url
+
+ def poll_status(token: str, instance_id: str, target: str, timeout: int = 600) -> None:
+ deadline = time.time() + timeout
+ while time.time() < deadline:
+ r = requests.get(f"{BASE}/instances/{instance_id}", headers=auth_headers(token))
+ r.raise_for_status()
+ status = r.json()["data"]["status"]
+ print(f" status={status}")
+ if status == target:
+ return
+ if status == "destroying":
+ raise RuntimeError("Instance destroyed unexpectedly")
+ time.sleep(10)
+ raise TimeoutError(f"Instance {instance_id} did not reach '{target}' in {timeout}s")
+
+ # --- usage ---
+ token = get_token()
+ instance = create_instance(
+ token,
+ tenant_id = os.environ["AURA_TENANT_ID"],
+ name = "ci-test-instance",
+ cloud_provider = "aws",
+ region = "us-east-1",
+ type = "professional-db",
+ memory = "2GB",
+ )
+ # SAVE CREDENTIALS IMMEDIATELY — password never retrievable again
+ print(f"ID: {instance['id']}")
+ print(f"URI: neo4j+s://{instance['id']}.databases.neo4j.io")
+ print(f"Password: {instance['password']}") # log to secure vault NOW
+
+ poll_status(token, instance["id"], "running", timeout=600)
+ print("Instance ready.")
+ ```
+
---
- ## Checklist
+ ## Region Codes
- - [ ] `.env` created with credentials and added to `.gitignore`
- - [ ] Instance status is `running` before attempting connection
- - [ ] Credentials printed/displayed only once at creation — save them immediately
- - [ ] `aura-cli auth login` or `AURA_CLIENT_ID`/`AURA_CLIENT_SECRET` env vars configured
- - [ ] Tenant ID specified for all operations (required in multi-tenant accounts)
+ ### AWS
+ | Region code | Location |
+ |---|---|
+ | `us-east-1` | N. Virginia |
+ | `us-east-2` | Ohio |
+ | `us-west-2` | Oregon |
+ | `eu-west-1` | Ireland |
+ | `eu-west-3` | Paris |
+ | `eu-central-1` | Frankfurt |
+ | `ap-southeast-1` | Singapore |
+ | `ap-southeast-2` | Sydney |
+ | `ap-south-1` | Mumbai |
+ | `sa-east-1` | São Paulo |
+ ### GCP
+ | Region code | Location |
+ |---|---|
+ | `europe-west1` | Belgium |
+ | `europe-west3` | Frankfurt |
+ | `europe-west4` | Netherlands |
+ | `us-central1` | Iowa |
+ | `us-east1` | S. Carolina |
+ | `us-east4` | N. Virginia |
+ | `asia-east1` | Taiwan |
+ | `asia-northeast1` | Tokyo |
+ | `asia-southeast1` | Singapore |
+ | `australia-southeast1` | Sydney |
+
+ ### Azure
+ | Region code | Location |
+ |---|---|
+ | `eastus` | E. US |
+ | `eastus2` | E. US 2 |
+ | `westeurope` | Netherlands |
+ | `northeurope` | Ireland |
+ | `uksouth` | London |
+ | `southeastasia` | Singapore |
+ | `brazilsouth` | Brazil |
+ | `koreacentral` | Korea |
+
+ Enterprise tiers (Business Critical, VDC) add 20+ additional regions per provider. Check console for full list.
+ Free tier: GCP only; limited subset of regions.
+
---
- ## Fetching Current Docs
+ ## Terraform Provider
- ```
- https://neo4j.com/docs/llms.txt ← full documentation index (includes Aura API spec)
- https://neo4j.com/docs/aura/platform/api/specification/ ← live Aura REST API spec
+ ```hcl
+ terraform {
+ required_providers {
+ aura = {
+ source = "neo4j/neo4j-aura"
+ }
+ }
+ }
+
+ provider "aura" {
+ client_id = var.aura_client_id # or AURA_CLIENT_ID env var
+ client_secret = var.aura_client_secret # or AURA_CLIENT_SECRET env var
+ }
+
+ resource "aura_instance" "db" {
+ name = "prod-db"
+ type = "professional-db"
+ cloud_provider = "gcp"
+ region = "europe-west1"
+ memory = "4GB"
+ tenant_id = var.aura_tenant_id
+ }
+
+ output "neo4j_uri" {
+ value = "neo4j+s://${aura_instance.db.id}.databases.neo4j.io"
+ sensitive = false
+ }
+ output "neo4j_password" {
+ value = aura_instance.db.password
+ sensitive = true
+ }
```
- ## References
+ After `terraform apply`: poll status before marking infra ready — Terraform resource creation returns when API call completes, not when DB is `running`.
- - [Aura Docs](https://neo4j.com/docs/aura/)
- - [Aura CLI Docs](https://neo4j.com/docs/aura/aura-cli/)
- - [Aura REST API Specification](https://neo4j.com/docs/aura/platform/api/specification/)
- - [Aura CLI GitHub](https://github.com/neo4j/aura-cli)
- - [GraphAcademy: AuraDB Fundamentals](https://graphacademy.neo4j.com/courses/aura-fundamentals/)
+ ---
+
+ ## Common Errors
+
+ | Error | Cause | Fix |
+ |---|---|---|
+ | `403 Forbidden` after working | Token expired (1 h TTL) | Re-run `get_token()` |
+ | `409 Conflict` on create | Name already exists in tenant | Change name or delete existing |
+ | `422` on pause | Instance not `running` | Check status; wait for ongoing op to finish |
+ | `422` on resume | Instance not `paused` | Check status |
+ | `422` on resize | Below current usage | Reduce data first; can't shrink below usage |
+ | Region not found | Tier doesn't support that region | Use `Free` tier on GCP only; Pro/BC on all 3 clouds |
+ | Credentials lost after create | Password only returned at create time | Delete + recreate — no reset exists |
+ | `429 Too Many Requests` | Rate limit hit (25 req/min Free, 125 req/min Pro+) | Add `time.sleep(2)` between polling calls |
+ | `instance list` returns empty | Wrong credential active | `aura-cli credential use --name <name>` |
+
+ ---
+
+ ## API Rate Limits
+
+ | Tier | Requests/minute |
+ |---|---|
+ | Free / Pro Trial (no billing) | 25 |
+ | Pro with billing, BC, VDC | 125 |
+
+ Poll interval: ≥10 s to stay within limits on Free; 5 s safe on Pro+.
+ On `Retry-After` header in 5xx response: wait that many seconds before retry.
+
+ ---
+
+ ## Security Rules
+
+ - Write initial credentials to `.env`; verify `.env` in `.gitignore` before proceeding
+ - Never print `PASSWORD` in CI logs — write to secrets vault (AWS Secrets Manager, GitHub secret, Vault)
+ - Use `from_env()` / `os.environ` — never hardcode credentials
+ - If `.env` absent: `python-dotenv` `load_dotenv()` auto-loads; do NOT prompt user unless loading fails
+
+ ---
+
+ ## WebFetch — Current Docs
+
+ | Need | URL |
+ |---|---|
+ | REST API spec (OpenAPI) | `https://neo4j.com/docs/aura/platform/api/specification/` |
+ | CLI reference | `https://neo4j.com/docs/aura/aura-cli/` |
+ | Region list | `https://neo4j.com/docs/aura/managing-instances/regions/` |
+ | Auth details | `https://neo4j.com/docs/aura/api/authentication/` |
+ | Instance actions | `https://neo4j.com/docs/aura/managing-instances/instance-actions/` |
+
+ ---
+
+ ## Checklist
+ - [ ] `.env` created with URI/user/password; `.env` in `.gitignore`
+ - [ ] Initial credentials saved to secure storage immediately after create
+ - [ ] `poll_status` called after create — do NOT connect before status = `running`
+ - [ ] `poll_status` called after pause/resume
+ - [ ] Correct tier selected (Free for dev, Pro+ for production, BC for HA)
+ - [ ] Region confirmed available for chosen tier and cloud provider
+ - [ ] Tenant ID provided for all create/list operations (required in multi-tenant orgs)
+ - [ ] Token refreshed if > 1 h old (or 403 received)
+ - [ ] Delete confirmed by user — data loss is permanent, no recovery