> ## Documentation Index
> Fetch the complete documentation index at: https://forest-chore-open-api.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Deploy

> Move your Forest back-end to production and set up your development workflow

So far you've been working locally. This step covers deploying your Forest back-end to production and understanding how Forest's development workflow keeps your environments in sync.

## Understand environments and branches

Forest distinguishes between **environments** (your local dev, staging, production) and **branches** (layout and configuration changes in progress).

* Your **production environment** is the live back-office your team uses
* Your **development environment** is your local Forest back-end
* **Branches** let you make layout changes without affecting production until you're ready to deploy

This means you can iterate on your back-office configuration safely, then push changes to production when they're ready.

<img src="https://mintcdn.com/forest-chore-open-api/DwOJ-XBdKEod-4Pc/images/diagrams/environments.svg?fit=max&auto=format&n=DwOJ-XBdKEod-4Pc&q=85&s=a24e2d8d854439192cdb3212dbaf54e3" alt="In development you work on a local back-end and a layout branch; the branch is pushed, reviewed, and deployed to the live back-office, while your back-end code is deployed to the production back-end in your infrastructure" width="100%" data-path="images/diagrams/environments.svg" />

## Deploy your back-end

<Steps>
  <Step title="Deploy your back-end to your infrastructure">
    Host your Forest back-end on any platform that can run a Node.js application (AWS, Heroku, GCP, your own servers, etc.).

    Make sure to set the environment variables (`FOREST_ENV_SECRET`, `FOREST_AUTH_SECRET`, `DATABASE_URL`) in your hosting platform.
  </Step>

  <Step title="Create a production environment in Forest">
    In Forest, go to **Project Settings** → **Environments** → **Add environment**.

    Give it a name (e.g. "Production") and enter the URL where your back-end is running.
  </Step>

  <Step title="Deploy your layout">
    In the Forest UI, go to **Environments** and click **Deploy to production** to push your layout configuration (segments, UI customizations, workspaces) to production.
  </Step>
</Steps>

Your team can now access the production back-office.

<Info>
  For a full explanation of the development workflow, branches, schema updates, environment management, see [Developer Workflow](/product/process/advanced-concepts/developer-workflow/environments-and-branches).
</Info>

## Keep the production schema up to date

[`.forestadmin-schema.json`](/reference/schema/forestadmin-schema) describes your data model to Forest. In development it's regenerated every time your agent boots.

**We recommend committing it** with your code: schema changes then show up in pull-request diffs, can be reviewed, and can be reverted in Git.

### Fail CI when the committed schema drifts

Because the file is generated locally, someone can change a data source or customization and forget to commit the regenerated schema, shipping a stale one. Add a CI step that regenerates it and fails when it differs from what's committed, so a forgotten commit turns the build red:

<Tabs>
  <Tab title="Node.js">
    Call [`agent.generateSchemaOnly()`](/reference/agent-api/nodejs) (available since `@forestadmin/agent` 1.83.0) from a one-shot script that reuses your agent setup, then diff the result. Extract your agent into a shared factory that does **not** call `.start()`:

    ```typescript theme={null}
    // generate-schema.ts
    import makeAgent from './agent'; // export default () => createAgent({...}).addDataSource(...), without .start()

    await makeAgent().generateSchemaOnly(); // writes to the schemaPath set in createAgent
    process.exit(0); // an open connection pool would otherwise keep the process alive
    ```

    ```bash theme={null}
    # the database must be reachable and migrated: generation introspects your tables
    npx tsx generate-schema.ts
    git diff --exit-code .forestadmin-schema.json
    ```

    Your CI job needs the same environment variables as your back-end (`FOREST_ENV_SECRET`, `FOREST_AUTH_SECRET`, `DATABASE_URL`): `createAgent` requires the secrets even though generation is offline by default. Experimental no-code customizations also fetch their configuration from Forest, which requires connectivity.
  </Tab>

  <Tab title="Ruby">
    The `forest_admin:schema:generate` rake task writes the file without booting the server or sending it to Forest. Regenerate, then diff:

    ```bash theme={null}
    # the database must be reachable and migrated: generation introspects your tables
    rails db:migrate
    rails forest_admin:schema:generate
    git diff --exit-code .forestadmin-schema.json
    ```
  </Tab>
</Tabs>

### Generate the schema at build time

Alternatively, you can generate the schema in your CI/CD pipeline and bake it into your build artifact instead of committing it. This isn't the default, but some teams prefer it when merge conflicts on `.forestadmin-schema.json` or forgotten regenerations are a recurring pain: you trade the reviewable Git diff for a conflict-free, always-fresh file, and no longer commit it.

Run the same generation command, then bake the file into your image instead of diffing it:

<Tabs>
  <Tab title="Node.js">
    ```bash theme={null}
    npx tsx generate-schema.ts
    # bake the generated .forestadmin-schema.json into your image, then deploy/promote it
    ```
  </Tab>

  <Tab title="Ruby">
    ```bash theme={null}
    rails db:migrate
    rails forest_admin:schema:generate
    # bake the generated .forestadmin-schema.json into your image, then deploy/promote it
    ```
  </Tab>
</Tabs>

<Warning>
  Generate the schema against a database whose structure matches production. If your build database is behind or ahead of production (a pending migration), the shipped schema can diverge from what production expects — the same risk as deploying an out-of-date committed file.
</Warning>

## What's next

Production is live. Time to invite your team.

<Card title="Next: Invite your team →" icon="arrow-right" href="/get-started/invite-your-team">
  Add users, create teams, and set up permissions
</Card>
