Check out v4 of the Fauna CLI

v4 of the Fauna CLI is now in beta.

The new version introduces enhancements to the developer experience, including an improved authentication workflow. To get started, check out the CLI v4 quick start.

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 can manage schemas as .fsl files using the Fauna CLI.

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

To manage .fsl files programmatically, use the Fauna Core HTTP API’s Schema endpoints.

Set up a schema directory

You typically store .fsl files in a schema directory alongside your application code. The directory can use any name. schema is a common choice.

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

Create FSL schema files

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

Valid FSL filenames must use the .fsl extension and can’t start with *.

FSL schema syntax

The following table links to FSL syntax to use when creating .fsl files:

Resource FSL Syntax

Collections, including:

  • Check constraints

  • Computed field definitions

  • Field definitions

  • Index definitions

  • Migrations

  • Unique constraints

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 .fsl files to Fauna, Fauna retains the filenames and directory organization. This lets you later pull the same files.

Filenames for generated FSL schema

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

Limits

A database can have up to 1,024 .fsl files, including main.fsl. This limit does not include .fsl files for child databases.

Push schema to Fauna

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

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, you must use the Fauna CLI or the Fauna Core HTTP API’s Schema endpoints.

You can’t run a staged schema change using FQL schema methods or the Fauna Dashboard.

This procedure uses v4 of the Fauna CLI, which is in beta. For the latest GA version, see v3 of the Fauna CLI.

To run a staged schema change using the Fauna CLI:

  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:

    # Replace 'us' with your preferred Region Group:
    # 'us' (United States), 'eu' (Europe), or `global`.
    # Replace 'my_db' with your database's name.
    fauna schema push \
      --database us/my_db \
      --dir /path/to/schema/dir

    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 \
      --database us/my_db

    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 \
      --database us/my_db

    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 \
      --database us/my_db

Run an unstaged schema change

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

fauna schema push \
  --database us/my_db \
  --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 \
  --database us/my_db

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 \
  --database us/my_db \
  --active

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

fauna schema diff \
  --database us/my_db \
  --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 \
  --database us/my_db \
  --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 \
  --database us/my_db

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 \
  --database us/my_db \
  --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 \
  --database us/my_db \
  --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 stage and commit schema changes using a CI/CD pipeline:

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.

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: ${{ secrets.FAUNA_SECRET }}

    strategy:
      matrix:
        node-version: [20.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 Fauna CLI
      run: npm install -g fauna-shell@">=4.0.0-beta"

    - name: Stage schema
      run: fauna schema push --secret $FAUNA_SECRET --no-input --dir ./path/to/schema/dir

    - 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 | grep -oP '(?<=Staged changes: )\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: Commit or abandon schema
      if: always()
      run: |
        if [[ "${{ steps.schema-check.outputs.schema_status }}" == "ready" ]]; then
          fauna schema commit --secret $FAUNA_SECRET --no-input
        else
          fauna schema abandon --secret $FAUNA_SECRET --no-input
        fi

GitLab

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

stages:
  - stage_schema
  - commit_or_abandon_schema

variables:
  FAUNA_SECRET: $FAUNA_SECRET

default:
  image: node:20

stage_schema:
  stage: stage_schema
  script:
    - npm install -g fauna-shell@">=4.0.0-beta"
    - fauna schema push --secret $FAUNA_SECRET --no-input --dir ./path/to-schema/dir
    - |
      attempts=0
      max_attempts=60
      while [ $attempts -lt $max_attempts ]; do
        STATUS=$(fauna schema status --secret $FAUNA_SECRET | grep -oP '(?<=Staged changes: )\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

commit_or_abandon_schema:
  stage: commit_or_abandon_schema
  script:
    - npm install -g fauna-shell@">=4.0.0-beta"
    - |
      if [ $? -eq 0 ]; then
        fauna schema commit --secret $FAUNA_SECRET --no-input
      else
        fauna schema abandon --secret $FAUNA_SECRET --no-input
        exit 1
      fi
  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 with the CLI

This procedure uses v4 of the Fauna CLI, which is in beta. For the latest GA version, see v3 of the Fauna CLI.

The Fauna CLI’s fauna schema commands let you specify a --database when you use interactive login or an account key for authentication. You can use --database to interact with any child database the related account key has access to.

# Stage schema changes for the
# 'us/parent_db/child_db' database.
fauna schema push \
  --database us/parent_db/child_db \
  --dir /path/to/schema/dir

Alternatively, you can use --secret to provide a scoped key. A scoped key lets 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, you can access a child database by appending the child database name and role:

# Use a scoped key from a parent database
# to stage schema in the 'child_db' child database.
# The scoped key has `admin` privileges.
fauna schema push \
  --secret fn123:child_db:admin \
  --dir /path/to/schema/dir

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. Use a scoped key to manage a child database’s schema using queries in a parent database.

FSL schema FQL system collection

Use Schema HTTP API endpoints

You can use the Fauna Core HTTP API’s Schema endpoints to perform programmatically perform schema changes, including staged schema changes. Use a scoped key to manage a child database’s schema using a parent database’s key secret.

For example, the following Update schema files request uses a scoped key that impersonates a key with the admin role for the childDb child database. The request starts a staged schema change for the childDb child database:

curl -X POST "https://db.fauna.com/schema/1/update?staged=true" \
  -H "Authorization: Bearer <FAUNA_SECRET>:childDb:admin" \
  -H "Content-Type: multipart/form-data" \
  -F "collections.fsl=@./schema/collections.fsl" \
  -F "functions.fsl=@./schema/functions.fsl"

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!