neo4j-aura-provisioning-skill

star 82

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.

neo4j-contrib By neo4j-contrib schedule Updated 5/29/2026

name: neo4j-aura-provisioning-skill 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.1 allowed-tools: Bash WebFetch

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: creatingrunning
  • Setting up CI/CD provisioning or teardown pipelines
  • Choosing instance tier (Free vs Professional vs Business Critical vs VDC)

When NOT to Use

  • Cypher queries against running DBneo4j-cypher-skill
  • GDS algorithms on Auraneo4j-gds-skill (Pro with plugin) or neo4j-aura-graph-analytics-skill (serverless)
  • neo4j-admin / cypher-shellneo4j-cli-tools-skill
  • Application driver setup → use a language driver skill (python, javascript, java, go, dotnet)

Instance Tier Decision Table

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

AuraDB Free limits: 200k nodes, 400k rels; auto-pauses after 72 h inactivity; deleted if paused >30 days; no resize.


Auth Setup

CLI (aura-cli v1.7+)

Install (binary, not pip):

# 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

Add credentials (from console.neo4j.io → Account Settings → API Credentials):

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:

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.

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"


Step 1 — List Tenants (Projects)

CLI:

aura-cli tenants list --output table
# Copy TENANT_ID for create operations

REST:

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

aura-cli instance create \
  --name "my-instance" \
  --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)

REST API (full create)

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 8GB384GB
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).

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:

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
  sleep 10
done

Status lifecycle:

creating → running → pausing → paused → resuming → running
                  ↘ destroying → (gone)

Step 4 — Write .env and Verify

CONNECTION_URI="neo4j+s://${INSTANCE_ID}.databases.neo4j.io"

cat > .env <<EOF
NEO4J_URI=${CONNECTION_URI}
NEO4J_USERNAME=neo4j
NEO4J_PASSWORD=${PASSWORD}
NEO4J_DATABASE=neo4j
AURA_INSTANCE_ID=${INSTANCE_ID}
EOF

# 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 — Lifecycle Operations

All operations require instance in the correct state. Wrong-state ops return 4xx error.

Pause

Required state: running

aura-cli instance pause --instance-id "$INSTANCE_ID"
poll_status "$INSTANCE_ID" "paused" 600

Resume

Required state: paused

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.

# 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.

aura-cli instance delete --instance-id "$INSTANCE_ID"
# No poll needed — immediate

REST:

curl -s -X DELETE "https://api.neo4j.io/v1/instances/$INSTANCE_ID" \
  -H "Authorization: Bearer $TOKEN"

Python CI/CD Provisioning Script

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.")

Region Codes

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.


Terraform Provider

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
}

After terraform apply: poll status before marking infra ready — Terraform resource creation returns when API call completes, not when DB is running.


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
Install via CLI
npx skills add https://github.com/neo4j-contrib/neo4j-skills --skill neo4j-aura-provisioning-skill
Repository Details
star Stars 82
call_split Forks 31
navigation Branch main
article Path SKILL.md
More from Creator
neo4j-contrib
neo4j-contrib Explore all skills →