# Manage FusionAuth Configuration Across Environments

Learn how to keep FusionAuth configuration in code and promote changes from one environment to another.

> For the index of this section of the site, see [llms.txt](https://fusionauth.io/docs/llms.txt)

Most teams run more than one FusionAuth instance, such as development, staging, and production instances. Each instance needs the same Tenants, Applications, and settings. A few values differ between environments.

Keep the configuration in code. Code lets a team review each change before the change reaches production. The same code then applies the change to every instance.

```mermaid
graph LR
    repo[Configuration repository] -->|Development values| dev[Development]
    repo -->|Staging values| staging[Staging]
    repo -->|Production values, after review| prod[Production]
```

One configuration, applied to each instance with values for that instance.

## Configuration and Data

FusionAuth holds two kinds of objects:

*   Configuration defines how the system behaves. A team sets up configuration once and changes the configuration rarely.
*   Data changes as people use your applications.

Keep configuration in code. Let applications manage data through the [APIs](https://fusionauth.io/docs/apis.md).

| Configuration | Data |
| --- | --- |
| Tenants, Applications, and roles | Users and registrations |
| Signing keys and API keys | Group memberships |
| Themes, email templates, and lambdas | Refresh tokens and sessions |
| Identity providers, webhooks, and connectors that your team sets up | Identity providers that your customers set up themselves |

To add users, turn on [self-service registration](https://fusionauth.io/docs/users/register/basic-registration-forms.md), create users with the [User API](https://fusionauth.io/docs/apis/users.md), or [migrate users](https://fusionauth.io/docs/migrate.md) from another system.

## Choose a Tool

### Terraform

The [FusionAuth Terraform provider](https://registry.terraform.io/providers/fusionauth/fusionauth/latest) manages most configuration objects. Terraform shows each change before applying the change. Terraform also tracks which objects the configuration owns. Terraform fits most teams, and the provider works with [OpenTofu](https://opentofu.org/) too. See [Manage FusionAuth With Terraform](https://fusionauth.io/docs/deploy/production/terraform.md).

### Scripts

Scripts call the API directly or through a [client library](https://fusionauth.io/docs/sdks.md). Run scripts the way you run database migrations. Scripts can call every API, including APIs that the Terraform provider doesn't support yet. However, scripts don't track which changes ran on which instance. Keep a record of the scripts that ran on each instance.

### The FusionAuth CLI

The [FusionAuth CLI](https://fusionauth.io/docs/deploy/production/cli.md) downloads and uploads themes, email templates, lambdas, and messages as files. Keep the files in version control and edit the files with any editor. Use the CLI alongside Terraform or scripts.

### The Admin UI

The Admin UI is the quickest way to try a setting on a development instance. After the setting works, copy the change into code.

Avoid changing production through the Admin UI. A change made in the Admin UI reaches only one instance. The [Audit Log](https://fusionauth.io/docs/apis/audit-logs.md) at System -> Audit Log records who changed what.

## Default Resources

Every instance starts with objects that FusionAuth creates, such as the default Tenant, the FusionAuth Application, and the default theme. The FusionAuth Application runs the Admin UI. See [Default Configuration](https://fusionauth.io/docs/concepts/plans-and-limits/limitations.md#default-configuration) for the full list and the Ids.

Code can't create or delete default resources. To change the settings of a default resource, import the resource into your tool. To use a default resource without changing the resource, look up the resource by name or Id.

The FusionAuth Application has the same Id on every instance. The default Tenant has a different Id on each instance. To set the default Tenant Id, use [Kickstart](https://fusionauth.io/docs/get-started/develop/kickstart.md).

To keep default resources out of your code, leave the default Tenant to the Admin UI. Create separate Tenants for your applications. Most of the configuration then consists of objects that your code creates.

## Changes Made Outside Your Tool

A change made outside your tool, such as an edit in the Admin UI, makes the instance drift from the code. The next run of the tool reverts the change. To prevent drift:

*   Limit who can change configuration on production with [Admin UI roles](https://fusionauth.io/docs/concepts/types/roles.md#admin-ui-roles).
*   Configure the tool to ignore fields that applications write on purpose, such as the **data** field of an Application.

## Secrets

The tool needs an API key for each instance. Store the keys in the secret store of your CI system, not in the repository. On a new instance, [Kickstart](https://fusionauth.io/docs/get-started/develop/kickstart.md) can create the first key.

Terraform state contains secrets, such as OAuth client secrets. Store state in a backend that encrypts the state and restricts access. See [Sensitive Data in State](https://developer.hashicorp.com/terraform/language/state/sensitive-data).

## Environment Differences

Some values differ between instances, such as hostnames, redirect URLs, and email server settings. Pass these values in as variables, such as Terraform [input variables](https://developer.hashicorp.com/terraform/language/values/variables). Don't keep a separate copy of the configuration for each environment.

### Theme Assets

When you move a theme from one environment to another, the templates and styles usually stay the same. The asset locations often differ, such as the hostname that serves images and CSS.

Theme templates can only read [the documented template variables](https://fusionauth.io/docs/theme/advanced-themes/template-variables.md). FusionAuth doesn't resolve environment variables in theme templates. To use different asset locations in each environment, choose one of these options:

*   Set variables when you build the theme. In the [Helpers](https://fusionauth.io/docs/theme/advanced-themes/helpers.md) template, set each variable with the [assign](https://freemarker.apache.org/docs/ref_directive_assign.html) directive. Other templates can then use the variables. To generate the Helpers template for each environment, use a templating language such as Jinja.
*   Store the locations in the **tenant.data** field. Every template can read the `tenant` object, so every template can read the locations.

Note

You can't edit **tenant.data** in the Admin UI. Set **tenant.data** with the [API](https://fusionauth.io/docs/apis.md), a [client library](https://fusionauth.io/docs/sdks.md), or the `data` argument of the Terraform `fusionauth_tenant` resource.

For example, suppose development assets live at `dev.example.com/assets` and production assets live at `prod.example.com/assets`. To serve each environment's assets with the same theme:

1.  In the development Tenant, set the asset locations in **tenant.data**:
    
    Development Tenant data
    
    ```json
    {
      "tenant" : {
        "data" : {
          "themes": {
             "asset_base_url" : "dev.example.com/assets",
             "css_base_url" : "cdn-dev.example.com"
          }
        }
      }
    }
    ```
    
2.  In the production Tenant, set the production locations:
    
    Production Tenant data
    
    ```json
    {
      "tenant" : {
        "data" : {
          "themes": {
             "asset_base_url" : "prod.example.com/assets",
             "css_base_url" : "cdn-prod.example.com"
          }
        }
      }
    }
    ```
    
3.  In the theme templates, reference images with `${tenant.data.themes.asset_base_url}` and CSS files with `${tenant.data.themes.css_base_url}`:
    
    Template that uses the asset locations
    
    ```ftl
    <html>
      <head>
        <link rel="stylesheet" href="${tenant.data.themes.css_base_url}/css/font-awesome.min.css"/>
        <link rel="stylesheet" href="${tenant.data.themes.css_base_url}/css/app.css"/>
      </head>
      <body>
        <img src="${tenant.data.themes.asset_base_url}/logo.png" />
        ...
        <img src="${tenant.data.themes.asset_base_url}/other_image.png" />
      </body>
    </html>
    ```
    

## What to Avoid

### Copying the Database

On a self-hosted instance, copying the database between environments or changing settings with SQL might seem like a shortcut. FusionAuth doesn't support either approach. The database schema is internal and can change in any release. The database also holds passwords and other personal data that shouldn't move between environments.

### Using Kickstart for Ongoing Changes

[Kickstart](https://fusionauth.io/docs/get-started/develop/kickstart.md) configures a new instance on the first start. Kickstart suits continuous integration and creating the first API key. Kickstart doesn't run on an instance that already has configuration, so Kickstart can't apply later changes. To follow progress on Kickstart for existing instances, upvote the [Kickstart migrations issue](https://github.com/FusionAuth/fusionauth-issues/issues/560).

## Test

[Test Against FusionAuth Learn how to run end-to-end tests against a real FusionAuth instance, reset the instance between runs, and run the same tests in CI.](https://fusionauth.io/docs/deploy/test/test-against-fusionauth.md)

[Test and Deploy with GitHub Actions How to use CI/CD with FusionAuth in GitHub.](https://fusionauth.io/docs/deploy/test/ci-workflow.md)

[GitHub Actions Learn how to use FusionAuth with the GitHub Actions Marketplace.](https://fusionauth.io/docs/deploy/test/github-actions.md)

## Production

[System Requirements Learn the minimum system requirements required to install and run FusionAuth.](https://fusionauth.io/docs/deploy/production/system-requirements.md)

[Server Layout Learn about the different server layouts that FusionAuth can be installed with to optimize performance and security.](https://fusionauth.io/docs/deploy/production/server-layout.md)

[Cluster Learn how to set up a multi-node FusionAuth cluster.](https://fusionauth.io/docs/deploy/production/cluster.md)

[Proxy Learn more about HTTP proxies and FusionAuth.](https://fusionauth.io/docs/deploy/production/proxy-setup.md)

[Configuration Reference Learn about the configuration options for FusionAuth.](https://fusionauth.io/docs/deploy/production/configuration.md)

[Start and Stop a Production Instance Learn how to start and stop the FusionAuth services on a production server, in Docker, and in Kubernetes.](https://fusionauth.io/docs/deploy/production/start-and-stop.md)

[Terraform Learn how to create and change FusionAuth configuration with the FusionAuth Terraform provider.](https://fusionauth.io/docs/deploy/production/terraform.md)

[FusionAuth CLI Learn about the FusionAuth CLI tool.](https://fusionauth.io/docs/deploy/production/cli.md)

## Harden

[Harden a Production Instance Learn which settings to change to secure a FusionAuth instance before it goes into production.](https://fusionauth.io/docs/deploy/harden/harden-a-production-instance.md)

[Networking Configuration Learn about FusionAuth networking configuration, especially IP resolution.](https://fusionauth.io/docs/deploy/harden/networking.md)

[Required Network Hostname Access Learn which hostnames you must allow access to for FusionAuth to work.](https://fusionauth.io/docs/deploy/harden/network-hostnames.md)

## Monitor

[CloudWatch Learn how to monitor FusionAuth with CloudWatch.](https://fusionauth.io/docs/deploy/monitor/cloudwatch.md)

[Datadog Learn how to monitor FusionAuth with Datadog.](https://fusionauth.io/docs/deploy/monitor/datadog.md)

[Elastic Learn how to monitor FusionAuth with Elastic.](https://fusionauth.io/docs/deploy/monitor/elastic.md)

[OpenTelemetry Learn how to monitor FusionAuth with OpenTelemetry.](https://fusionauth.io/docs/deploy/monitor/opentelemetry.md)

[Prometheus, Loki, And Grafana Learn how to monitor FusionAuth with Prometheus, Loki Grafana, and ntfy.](https://fusionauth.io/docs/deploy/monitor/prometheus.md)

[Slack Learn how to monitor FusionAuth with Slack.](https://fusionauth.io/docs/deploy/monitor/slack.md)

[Splunk Learn how to monitor FusionAuth with Splunk.](https://fusionauth.io/docs/deploy/monitor/splunk.md)

## Troubleshoot

[Troubleshooting Learn how to troubleshoot issues that might arise while install or running FusionAuth.](https://fusionauth.io/docs/deploy/troubleshoot/troubleshooting.md)

[Technical Support Learn how you can get technical support for FusionAuth.](https://fusionauth.io/docs/deploy/troubleshoot/technical-support.md)

Related

[Deploy Manage FusionAuth With Terraform Learn how to create and change FusionAuth configuration with the FusionAuth Terraform provider. infrastructure as codeconfiguration managementdevops](https://fusionauth.io/docs/deploy/production/terraform.md)

[Update Update a Production Instance of FusionAuth Learn how to plan, perform, and verify an update of a FusionAuth instance in a production environment. productiondeployment](https://fusionauth.io/docs/update/prod-instance.md)

[Cloud Create a Deployment Learn how to create a FusionAuth Cloud deployment. deploy fusionauth](https://fusionauth.io/docs/cloud/create-a-deployment.md)

[Deploy Harden a FusionAuth Production Instance Learn which settings to change to secure a FusionAuth instance before it goes into production. production](https://fusionauth.io/docs/deploy/harden/harden-a-production-instance.md)