Manage schema as .fsl files using the Fauna CLI

A schema controls a database’s structure and behavior. In Fauna, you define schema the using Fauna Schema Language (FSL). You use FSL to create and update schema for:

You can manage FSL schemas using the Fauna Dashboard or as .fsl files using the Fauna CLI.

This page covers how to manage .fsl files using the CLI. The CLI lets you version control, review, and automate schema changes.

Set up a schema directory

You typically store .fsl files in a schema directory alongside your application code. You set up this directory when you initialize a project:

fauna project init

For more information about setting up a project using the CLI, see Set up a project using FSL and the Fauna CLI.

Organize schema files

An .fsl file can contain schema for multiple resources. You can use multiple .fsl files to organize your schema. There is no performance benefit to splitting .fsl files or storing larger, individual files.

Common conventions

A common convention is to organize your .fsl files by resource type to maintain a clear and maintainable schema structure:

schema/
├── collections.fsl         # Collection schema
├── functions.fsl           # User-defined functions
├── roles.fsl               # Role definitions
└── access-providers.fsl    # Access provider definitions

When you push local .fsl files to Fauna, Fauna retains .fsl filenames and organization. This lets you later pull the same files.

Filenames for Dashboard-created schema

Schema created using the Dashboard are stored in a main.fsl file. After pulling the file locally, you can reorganize the schema into separate files as desired.

Push and pull schema

A project directory includes .fsl files for the project’s database. You can use the Fauna CLI to push and pull a project’s .fsl files from Fauna.

You can use these commands to manage .fsl files using a CI/CD pipeline. See Manage schema with a CI/CD pipeline.

Run a staged schema change

A staged schema change lets you change one or more collection schema without index downtime due to index builds.

To run a staged schema change:

  1. Make the desired changes to .fsl files in your schema directory.

    You can’t use a staged schema change to delete or rename schema. Instead, delete or rename the schema in a separate unstaged schema change.

  2. Use fauna schema push to stage the schema changes. fauna schema push stages schema changes by default:

    fauna schema push

    This allows Fauna to build indexes for the updated schema before applying the schema to the database.

    A database can have one staged schema change at a time. You can update staged schema using fauna schema push.

    When a database has staged schema, any access or updates done using FQL’s schema commands on related system collections interact with the staged schema, not the database’s active schema.

    For example, when schema changes are staged, Collection.all() returns Collection documents for the staged collection schema, not the database’s Collection documents.

    If a database has staged schema, you can’t edit the database’s active schema using FQL, the Dashboard, or an unstaged schema change. You must first abandon the staged schema change.

  3. Use fauna schema status to check the status of the staged schema:

    fauna schema status

    Possible statuses:

    Staged status Description

    pending

    Changes are being processed. New indexes are still being built.

    ready

    All indexes have been built. Changes are ready to commit.

    failed

    There was an error during the staging process.

  4. When the status is ready, use fauna schema commit to apply the staged schema to the database:

    fauna schema commit

    You can only commit staged schema with a status of ready.

    If you no longer wish to apply the staged schema or if the status is failed, use fauna schema abandon to unstage the schema:

    fauna schema abandon

Run an unstaged schema change

To immediately commit schema changes without staging, use the --active option:

fauna schema push --active

Schema changes that trigger an index build may result in downtime where the index is not queryable.

You can’t run an unstaged schema change if a database has staged schema. You must abandon the staged schema changes first.

Create and delete schema

Committing a schema to Fauna creates the related resource. For example, committing a collection schema to Fauna creates the collection.

Similarly, you can delete the resource by removing the schema from the FSL files in a project’s schema directory then pushing the changes to Fauna.

Compare local, staged, and active schema

Use fauna schema diff to compare a project’s local, staged, and active schema.

For example, to compare the local schema to the remote staged schema:

fauna schema diff

If there is no staged schema, fauna schema diff compares the local schema to the remote active schema instead.

To compare the local schema to the remote active schema:

fauna schema diff --active

To compare the remote active schema to the remote staged schema:

fauna schema diff --staged

By default, fauna schema diff prints a semantic summary of the changes. To get a textual diff, use the --text option. For example:

fauna schema diff --text

Pull remote schema from Fauna

Use fauna schema pull to pull a database’s remote .fsl schema files into a project’s local schema directory:

fauna schema pull

If the database has staged schema, the command pulls the database’s remote staged schema by default.

If the database has no staged schema, the command pulls the database’s remote active schema.

Pull active schema files

Use the fauna schema pull command’s --active option to pull the database’s remote active schema regardless of whether the database has staged schema:

fauna schema pull --active

Delete local files

The fauna schema pull command overwrites existing schema files in the local directory.

If wanted, you can use the --delete option to delete local .fsl files that aren’t part of the remote schema:

fauna schema pull --delete

Manage schema with a CI/CD pipeline

You can use schema-related Fauna CLI commands to manage schema as .fsl files. The following examples show how you can manage schema using a CI/CD pipeline:

GitHub

In your project, create a .github/workflows/main.yml file with the following contents:

name: Main CI

on:
  push:
    branches: [ main ]

jobs:
  ci:
    runs-on: ubuntu-latest
    env:
      FAUNA_SECRET_KEY: ${{ secrets.FAUNA_SECRET_KEY }}

    strategy:
      matrix:
        node-version: [18.x]

    steps:
    - uses: actions/checkout@v3

    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v3
      with:
        node-version: ${{ matrix.node-version }}

    - name: Install dependencies
      run: npm install

    - name: Install Fauna CLI
      run: npm install -g fauna-shell

    - name: Stage schema change
      run: fauna schema push --no-input --secret $FAUNA_SECRET_KEY

    - name: Check schema status
      id: schema-check
      run: |
        attempts=0
        max_attempts=60  # 30 minutes with 30-second intervals
        while [ $attempts -lt $max_attempts ]; do
          STATUS=$(fauna schema status --secret $FAUNA_SECRET_KEY | grep -oP '(?<=Staged status: )\w+')
          echo "Current status: $STATUS"
          if [ "$STATUS" = "ready" ]; then
            echo "Schema is ready"
            echo "schema_status=ready" >> $GITHUB_OUTPUT
            exit 0
          elif [ "$STATUS" = "failed" ]; then
            echo "Schema staging failed"
            echo "schema_status=failed" >> $GITHUB_OUTPUT
            exit 1
          fi
          echo "Waiting for schema to be ready..."
          sleep 30
          attempts=$((attempts + 1))
        done
        echo "Timeout waiting for schema status"
        echo "schema_status=timeout" >> $GITHUB_OUTPUT
        exit 1

    - name: Run tests
      run: npm test

    - name: Handle schema changes
      if: always()
      run: |
        if [[ "${{ steps.schema-check.outputs.schema_status }}" == "ready" ]]; then
          fauna schema commit --no-input --secret $FAUNA_SECRET_KEY
        else
          fauna schema abandon --no-input --secret $FAUNA_SECRET_KEY
        fi

    - name: Reset Test Database
      if: always()
      run: |
        fauna schema push --dir=./cleanup/ --no-input --active --secret $FAUNA_SECRET_KEY
        fauna schema commit --no-input --secret $FAUNA_SECRET_KEY
      env:
        FAUNA_SECRET_KEY: ${{ secrets.FAUNA_SECRET_KEY }}

GitLab

In your project, create a .gitlab-ci.yml file with the following contents:

stages:
  - build
  - stage_schema
  - test
  - cleanup

variables:
  FAUNA_SECRET_KEY: $FAUNA_SECRET_KEY

default:
  image: node:18

build:
  stage: build
  script:
    - npm install
    - npm install -g fauna-shell
  only:
    - main

stage_schema:
  stage: stage_schema
  script:
    - fauna schema push --no-input --secret $FAUNA_SECRET_KEY
    - |
      attempts=0
      max_attempts=60
      while [ $attempts -lt $max_attempts ]; do
        STATUS=$(fauna schema status --secret $FAUNA_SECRET_KEY | grep -oP '(?<=Staged status: )\w+')
        echo "Current status: $STATUS"
        if [ "$STATUS" = "ready" ]; then
          echo "Schema is ready"
          exit 0
        elif [ "$STATUS" = "failed" ]; then
          echo "Schema staging failed"
          exit 1
        fi
        echo "Waiting for schema to be ready..."
        sleep 30
        attempts=$((attempts + 1))
      done
      echo "Timeout waiting for schema status"
      exit 1
  only:
    - main

test:
  stage: test
  script:
    - npm install  # Need to install dependencies again in this stage
    - npm install -g fauna-shell
    - npm test
    - |
      if [ $? -eq 0 ]; then
        fauna schema commit --no-input --secret $FAUNA_SECRET_KEY
      else
        fauna schema abandon --no-input --secret $FAUNA_SECRET_KEY
        exit 1
      fi
  only:
    - main

cleanup:
  stage: cleanup
  script:
    - npm install -g fauna-shell
    - fauna schema push --dir=./cleanup/ --no-input --active --secret $FAUNA_SECRET_KEY
    - fauna schema commit --no-input --secret $FAUNA_SECRET_KEY
  when: always
  only:
    - main

Manage schema for child databases

Fauna databases support a hierarchical database structure with top-level and child databases. You can manage schema for child databases using scoped keys with the CLI or using FQL schema methods.

Use scoped keys

Most schema-related Fauna CLI commands support a --secret option. Use this option to provide a scoped key, letting you interact with a child database’s schema using a parent database’s admin key.

For example, with a parent database’s admin key secret of fn123, you can access a child database by appending the child database name and role:

# Uses a scoped key from a parent database
# to stage schema in the `childDb` child database.
# The scope key has `admin` privileges in the
# `childDb` database.
fauna schema push --secret:fn123:childDb:admin

Use FQL schema methods

Fauna stores each schema for a database as an FQL document in a related system collection.

You can use methods for these system collections to programmatically manage the schema of child databases using FQL queries.

FSL schema FQL system collection

Is this article helpful? 

Tell Fauna how the article can be improved:
Visit Fauna's forums or email docs@fauna.com

Thank you for your feedback!