Automate Start and Stop of Neo4j AuraDB Instances Using GitHub Actions

Technical Support Engineer at Neo4j
5 min read

Overview
Learn how to set up GitHub Actions to automate the start and stop of Neo4j Aura instances. This automation is useful for cutting costs by stopping unused databases during off-hours or weekends. For details about Aura billing, please refer to the Neo4j Aura Consumption Report Documentation.
This article applies to AuraDB Virtual Dedicated Cloud and AuraDS Enterprise.
Prerequisites
Before creating the GitHub Action, ensure that you have:
- GitHub repository: Repo where you will store your workflows and Python script
- Neo4j Aura account: An account with API access and the necessary credentials
- GitHub secrets: Store API credentials securely
Repository Structure
The script is in the GitHub Repository. Below is an example of the repository structure for this project:
your-repo/
├── .github/
│ └── workflows/
│ ├── resume_instances.yaml # Workflow to start instances
│ └── stop_instance.yaml # Workflow to stop instances
├── manage_instances.py # Python script for managing instances
├── requirements.txt # Python dependencies (e.g., requests)
└── README.md # Project documentation
Steps
Step 1: Add Repository Secrets
To securely provide your API credentials, add the following secrets to your GitHub repository:
- CLIENT_ID: Your Neo4j Aura API client ID
- CLIENT_PWD: Your Neo4j Aura API client password
- TENANT_ID: Your Neo4j Aura project ID
How to Add Secrets
- Navigate to your repository on GitHub.
- Click Settings.
- In the left sidebar, select Secrets and variables > Actions.
- Click New repository secret and add each secret as specified.
- For detailed instructions about creating API credentials to populate the CLIENT_ID and CLIENT_PWD, refer to the Neo4j Aura API Authentication documentation.
- Find the value for the TENANT_ID from the main Neo4j Aura Console page by clicking Projects.

Step 2: Prepare Your Python Script
Create a Python script named manage_instances.py that performs the start and stop operations based on a provided argument. This script retrieves the API credentials from the repository secrets, fetches the list of instances for the specified tenant, and resumes or pauses the instance if its name matches a defined list:
import os
import requests
import json
import sys
def get_access_token(user, pwd):
response = requests.post(
'https://api.neo4j.io/oauth/token',
auth=(user, pwd),
headers={'Content-Type': 'application/x-www-form-urlencoded'},
data={'grant_type': 'client_credentials'}
)
response.raise_for_status()
return response.json()['access_token']
def get_instances(access_token, tenant_id):
response = requests.get(
f"https://api.neo4j.io/v1/instances?tenantId={tenant_id}",
headers={"Authorization": f"Bearer {access_token}", 'Content-Type': 'application/json'}
)
response.raise_for_status()
return response.json()['data']
def pause_instance(access_token, dbid):
response = requests.post(
f"https://api.neo4j.io/v1/instances/{dbid}/pause",
headers={"Authorization": f"Bearer {access_token}", 'Content-Type': 'application/json'}
)
if response.status_code == 200:
print(f"Paused instance {dbid}")
else:
response.raise_for_status()
def resume_instance(access_token, dbid):
response = requests.post(
f"https://api.neo4j.io/v1/instances/{dbid}/resume",
headers={"Authorization": f"Bearer {access_token}", 'Content-Type': 'application/json'}
)
if response.status_code == 200:
print(f"Resumed instance {dbid}")
else:
response.raise_for_status()
def main(action):
user = os.getenv('CLIENT_ID')
pwd = os.getenv('CLIENT_PWD')
tenant_id = os.getenv('TENANT_ID')
if action not in ['start', 'stop']:
print("Invalid action. Use 'start' or 'stop'.")
sys.exit(1)
access_token = get_access_token(user, pwd)
instances = get_instances(access_token, tenant_id)
instance_names_to_manage = ['github-action-cron'] # Add your instance name here
for instance in instances:
if instance['name'] in instance_names_to_manage:
dbid = instance['id']
if action == 'stop':
pause_instance(access_token, dbid)
elif action == 'start':
resume_instance(access_token, dbid)
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python manage_instances.py [start|stop]")
sys.exit(1)
action = sys.argv[1].lower()
main(action)
Step 3: Create a requirements.txt File
Create a file named requirements.txt and add the following line:
requests
Step 4: Create GitHub Actions and Workflow Files
Create a directory named .github/workflows/ in your repository and add two YAML files: one for starting instances and another for stopping them.
resume_instances.yaml:
name: Resume Instances
on:
schedule:
- cron: '0 12 * * 1-5'
workflow_dispatch:
jobs:
start-instances:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5.1.1
with:
python-version: '3.x'
- name: Install dependencies
run: |
pip install -r requirements.txt
- name: Run start instances script
env:
CLIENT_ID: ${{ secrets.CLIENT_ID }}
CLIENT_PWD: ${{ secrets.CLIENT_PWD }}
TENANT_ID: ${{ secrets.TENANT_ID }}
run: |
python manage_instances.py start
stop_instance.yaml:
name: Stop Instances
on:
schedule:
- cron: '0 21 * * 1-5'
workflow_dispatch:
jobs:
stop-instances:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5.1.1
with:
python-version: '3.x'
- name: Install dependencies
run: |
pip install -r requirements.txt
- name: Run stop instances script
env:
CLIENT_ID: ${{ secrets.CLIENT_ID }}
CLIENT_PWD: ${{ secrets.CLIENT_PWD }}
TENANT_ID: ${{ secrets.TENANT_ID }}
run: |
python manage_instances.py stop
Step 5: Test the Workflows
Manual trigger:
- Navigate to the Actions tab in your GitHub repository.
- Select either the “Resume Instances” or “Stop Instances” workflow.
- Click Run workflow to manually trigger a run.
Monitor logs:
- Check the workflow logs to verify that the script executes correctly.
- Confirm that the targeted instances are started or stopped as expected.
Step 6: Troubleshooting
- Missing environment variables:
Verify that CLIENT_ID, CLIENT_PWD, and TENANT_ID are correctly set in your repository secrets. - CRON schedule issues:
Ensure that the CRON expressions match your desired execution times (remember that GitHub Actions uses UTC). - Script execution errors:
Review the logs in the GitHub Actions tab to identify and resolve any issues. - Instance matching:
Ensure that the list instance_names_to_manage in your Python script accurately reflects the instances you want to control.
Summary
Automating the start and stop of Neo4j AuraDB instances using GitHub Actions helps optimize costs by ensuring databases are only running when needed. This guide walks through setting up GitHub Actions workflows, integrating API credentials securely, and using a Python script to control database states. This way, you can efficiently manage your Aura instances with scheduled or manual triggers, reducing operational overhead and improving cost-efficiency.
Automate Start and Stop of Neo4j AuraDB Instances Using GitHub Actions was originally published in Neo4j Developer Blog on Medium, where people are continuing the conversation by highlighting and responding to this story.