Create a database branch with GitHub Actions

Create a GitHub Action that can create a new Turso database when a new GitHub branch is made.

Jamie BartonJamie Barton
Cover image for Create a database branch with GitHub Actions

A database per branch is a common request from developers using Turso. This approach not only streamlines the development process but also isolates changes, preventing conflicts and preserving data integrity.

In this post, we're going to guide you through setting up a GitHub Action that does exactly this. Learn how to automatically create a new Turso database by cloning an existing one each time a new branch is created using the Turso Platform API.

The Turso CLI makes it super easy to create a database from an existing one:

turso db create my-new-db --from-db my-existing-db

We can do the same thing using the Turso Platform API to create a database:

curl -X POST \
  -H "Authorization: Bearer API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "NEW_DATABASE_NAME", "group": "GROUP_NAME", "seed": {"type": "database", "name": "EXISTING_DATABASE_NAME"} }' \
  "https://api.turso.tech/v1/organizations/ORGANIZATION_NAME/databases"

The Platform API is what we'll use to create a GitHub Action that creates a database from an existing one when we create a new branch.

#You will need

  1. A GitHub repository for your new Action workflow
  2. The name of your organization or account
  3. An API token for your account
  4. The name of the database you want to branch from
  5. The name of the group where your database belongs

#Configure Action Secrets

Go to your repository settings and go to Security > Security > Secrets and variables > Actions:

Add a new repository secret:

New repository secret
New repository secret

Follow the convention of prefixing secrets with TURSO_ and uppercase:

  • TURSO_API_TOKEN
  • TURSO_EXISTING_DATABASE_NAME
  • TURSO_GROUP_NAME
  • TURSO_ORGANIZATION_NAME
    GitHub Secrets List
    GitHub Secrets List

We will assign NEW_DATABASE_NAME later inside the Action code.

#Create a new workflow

Create the file .github/workflows/main.yml with the following contents:

name: Create Database for Branch
on: create

jobs:
  create_database:
    name: 'Create Database'
    runs-on: ubuntu-latest

Before we can execute the cURL to create a new database, we need to update it to reference the secrets from the repository:

curl -X POST \
  -H "Authorization: Bearer ${{ secrets.TURSO_API_TOKEN }}" \
  -H "Content-Type: application/json" \
  -d '{"name": "NEW_DATABASE_NAME", "group": "${{ secrets.TURSO_GROUP_NAME }}", "seed": {"type": "database", "name": "${{ secrets.TURSO_EXISTING_DATABASE_NAME }}"} }' \
  "https://api.turso.tech/v1/organizations/${{ secrets.TURSO_ORGANIZATION_NAME }}/databases"

We also assigned NEW_DATABASE_NAME to the branch name by using github.ref_name in the code above.

#Add create database step

We'll now put it all together and add the cURL request as a step inside of the create_database job:

jobs:
  create_database:
    name: 'Create Database'
    runs-on: ubuntu-latest
    steps:
      - name: Create Database via Turso API
        shell: bash
        run: |
          curl -X POST \
            -H "Authorization: Bearer ${{ secrets.TURSO_API_TOKEN }}" \
            -H "Content-Type: application/json" \
            -d '{"name": "${{ github.ref_name }}", "group": "${{ secrets.TURSO_GROUP_NAME }}", "seed": {"type": "database", "name": "${{ secrets.TURSO_EXISTING_DATABASE_NAME }}"} }' \
            "https://api.turso.tech/v1/organizations/${{ secrets.TURSO_ORGANIZATION_NAME }}/databases"

#Handle API errors

We know as developers that not everything goes to plan, and we should handle errors in our GitHub Action. If the API request fails, GitHub Action will still mark the Action as successful.

We want to throw an exit code if the API request fails or there's no Hostname in our response.

- name: Create Database via Turso API
  shell: bash
  run: |
    RESPONSE=$(curl -s -f -X POST \
      -H "Authorization: Bearer ${{ secrets.TURSO_API_TOKEN }}" \
      -H "Content-Type: application/json" \
      -d '{"name": "${{ github.ref_name }}", "group": "${{ secrets.TURSO_GROUP_NAME }}", "seed": {"type": "database", "name": "${{ secrets.TURSO_EXISTING_DATABASE_NAME }}"} }' \
          "https://api.turso.tech/v1/organizations/${{ secrets.TURSO_ORGANIZATION_NAME }}/databases")

    if [ $? -ne 0 ]; then
      echo "API call failed"
      exit 1
    fi

#Assign the Hostname to a variable

It would be useful to assign the Hostname of the database returned by the API to the GitHub environment so we can use it in further steps. One useful step could be to trigger a deployment for your app with the new Hostname.

We'll use jq to parse RESPONSE and extract the Hostname value:

- name: Create Database via Turso API
  shell: bash
  run: |
    RESPONSE=$(curl -s -f -X POST \
      -H "Authorization: Bearer ${{ secrets.TURSO_API_TOKEN }}" \
      -H "Content-Type: application/json" \
      -d '{"name": "${{ github.ref_name }}", "group": "${{ secrets.TURSO_GROUP_NAME }}", "seed": {"type": "database", "name": "${{ secrets.TURSO_EXISTING_DATABASE_NAME }}"} }' \
          "https://api.turso.tech/v1/organizations/${{ secrets.TURSO_ORGANIZATION_NAME }}/databases")

    if [ $? -ne 0 ]; then
      echo "API call failed"
      exit 1
    fi

    HOSTNAME=$(echo $RESPONSE | jq -r '.database.Hostname')
    if [ -z "$HOSTNAME" ]; then
      echo "Hostname not found in response"
      exit 1
    fi

    echo "hostname=$HOSTNAME" >> $GITHUB_ENV

Now we can access the hostname variable from inside another step:

- name: Echo Hostname
  run: echo "The hostname is ${{ env.hostname }}"

#Create a new branch

You can trigger the workflow by creating a new branch:

Create GitHub Branch
Create GitHub Branch

Once the branch has been created it will automatically trigger the GitHub Action. Go to the Actions tab and view the Create Database job:

GitHub Action Log
GitHub Action Log

If we create a branch with a name that doesn't meet the requirements of what you can name a database with Turso, the Action will handle the failure and return the exit code:

GitHub Action Failed
GitHub Action Failed

#Watch out for invalid branch names

In the current GitHub Action, there's a chance that your branch name will conflict with the database name requirements set by Turso.

Your branch name can only contain lowercase letters, numbers, and hyphens. You can always add a step to the GitHub Action that uses the ref_name to create something more bespoke for your application requirements.

#Simplify things with the official Turso GitHub Action

We've made it even easier to implement the code above by publishing the code to the GitHub Action Marketplace.

Instead of making a cURL request yourself, you can rely on the official GitHub Action to do all the work!

name: Create Database for Branch
on: create

jobs:
  create_database:
    name: 'Create Database'
    runs-on: ubuntu-latest
    steps:
      - name: Create Database
        uses: tursodatabase/create-database-action@v1
        with:
          organization_name: ${{ secrets.TURSO_ORGANIZATION_NAME }}
          api_token: ${{ secrets.TURSO_API_TOKEN }}
          existing_database_name: ${{ secrets.TURSO_DATABASE_NAME }}
          new_database_name: ${{ github.ref_name }}
          # optional
          # group_name: ${{ secrets.TURSO_GROUP_NAME }}

We'd love to hear your feedback, so please join us on Discord to share your ideas. All of the code is available on GitHub too.

scarf