# Headless Config Overview

When customers activate an instance of your integration, they need to supply the information that makes the integration work for them: which records to sync, how fields map, where to send notifications. Prismatic offers two ways to collect that information:

* **Hosted configuration**: Your app embeds Prismatic's [config wizard](https://prismatic.io/docs/integrations/config-wizard.md) in an iframe. You define config pages and config variables, and Prismatic renders the wizard.
* **Headless configuration**: Your app renders the configuration experience with its own UI components. You define the shape of the configuration in your code-native integration, and Prismatic handles validation, storage, and instance lifecycle.

Both approaches are fully supported. Hosted configuration is the quickest path to a working config wizard. Choose headless configuration when you want the configuration experience to look and feel exactly like the rest of your app.

Headless configuration is in early access

Headless configuration is available for [code-native integrations](https://prismatic.io/docs/integrations/code-native.md). It is not available for low-code integrations. Your organization needs the headless configuration feature enabled before you import or publish a headless integration. Contact your Prismatic representative to enable it.

## How headless configuration works[​](#how-headless-configuration-works "Direct link to How headless configuration works")

A headless integration replaces config pages with a **configuration** definition. You write it in TypeScript with Spectral's `configuration()` function, and it has four parts:

| Part                 | What it does                                                                                                                                                                                                                       |
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Schema**           | Defines the shape of the values an instance saves. You write it with [zod](https://zod.dev) or JSON Schema. See [Schema](https://prismatic.io/docs/integrations/headless-configuration/schema.md).                                 |
| **Version**          | Names the current shape of the schema, such as `acme-crm-v1`. See [Configuration versions](https://prismatic.io/docs/integrations/headless-configuration/configuration-versions.md).                                               |
| **Init**             | Suggests starting values for your instance's configuration. It helps when converting a hosted configuration to headless, or when upgrading versions.                                                                               |
| **Server functions** | Functions your app calls while a customer configures an instance, such as listing the record types in a customer's CRM. See [Server functions](https://prismatic.io/docs/integrations/headless-configuration/server-functions.md). |

The configuration can also declare the [connections](https://prismatic.io/docs/integrations/headless-configuration/connections.md) the integration needs.

A minimal headless configuration

```typescript
import { configuration } from "@prismatic-io/spectral";
import { z } from "zod";

export const integrationConfiguration = configuration({
  instance: {
    schema: z.object({
      recordType: z.string().min(1),
    }),
    version: "fake-crm-v1",
  },
});

```

Your app then uses [Solis](https://prismatic.io/docs/embed/headless.md), Prismatic's custom UI SDK for building rich configuration experiences, to drive the configuration:

1. Your app reads the configuration's schema and the list of server functions the integration defines.
2. Your app calls **init** to get suggested values, and shows them in its own form.
3. As the customer fills in the form, your app calls **server functions** for dynamic data, such as dropdown options or a preview.
4. Your app **saves** the customer's values. Prismatic validates them against the schema and returns any invalid fields.
5. Your app **deploys** the instance, which starts running with the saved values.

When a flow runs, it reads the saved values, already parsed and typed, from `context.configuration`:

Read configuration in a flow

```typescript
export const syncContacts = flow({
  name: "Sync Contacts to Acme",
  stableKey: "sync-contacts-to-acme",
  onExecution: async (context) => {
    // Typed from the schema, and validated when it was saved.
    // To type it, register your configuration as shown in Configuration schema.
    const { configuration } = context;
    if (!configuration) {
      throw new Error("This instance has no saved configuration.");
    }
    context.logger.info(`Syncing ${configuration.recordType} records`);
    return { data: null };
  },
});

```

### Scheduled flows[​](#scheduled-flows "Direct link to Scheduled flows")

A headless integration has no config variables, so a flow's schedule can't come from one. Instead, a scheduled flow uses either a fixed schedule or a schedule that whoever deploys the instance supplies:

src/flows.ts

```typescript
export const nightlySync = flow({
  name: "Nightly Sync",
  stableKey: "nightly-sync",
  // A fixed schedule: { value: "0 2 * * *", timezone: "America/Chicago" }
  // Or let the deploying user choose:
  schedule: { fromDeployer: true },
  onExecution: async (context) => {
    // ...
    return { data: null };
  },
});

```

For a `fromDeployer` schedule, your app collects the schedule in its configuration UI and passes it to Solis when it saves the configuration. See [Flow schedules](https://prismatic.io/docs/embed/headless/react.md#flow-schedules).

## What Prismatic handles for you[​](#what-prismatic-handles-for-you "Direct link to What Prismatic handles for you")

With headless configuration, your app owns the UI and Prismatic owns everything behind it:

* **Validation**: Prismatic validates saved values against your schema and reports errors for each field.
* **Storage**: Prismatic stores values as JSON with their real types, not as strings. A number stays a number, and a list stays a list.
* **Dynamic data**: Server functions run in Prismatic, next to your integration's code and connections, so your app never handles third-party credentials.
* **Versioning**: When a new version of your integration changes the configuration's shape, Prismatic tells your app that the instance needs to be reconfigured, and your `init` function migrates its values.
* **Instance lifecycle**: Creating, deploying, updating, pausing, and removing instances work the same way as they do with hosted configuration.

## Choosing between hosted and headless configuration[​](#choosing-between-hosted-and-headless-configuration "Direct link to Choosing between hosted and headless configuration")

You might choose hosted configuration when:

* You want a working config wizard with the least effort
* Your configuration is a set of connections and simple inputs
* You build low-code integrations

You might choose headless configuration when:

* The configuration experience needs to match your app's design system exactly
* You want complex interactions, such as a field mapper with a live preview, that are easier to build in your own components
* You want saved values with real types that your flows don't need to parse

You can mix both approaches. Each integration version reports its **configuration experience**, `hosted` or `headless`, so your app can render its own form for headless integrations and open Prismatic's wizard for the rest.

## Try the example[​](#try-the-example "Direct link to Try the example")

The [example embedded app](https://github.com/prismatic-io/embedded/tree/main/examples/example-embedded-app) includes a **Headless Configuration** page and the **Fake CRM** integration it configures. A customer chooses a record type in a mock CRM, maps its fields to Acme contact fields, and previews the result before saving. To build and run it step by step, follow [Get started with headless configuration](https://prismatic.io/docs/get-started/build-integrations/headless-configuration.md).

## Next steps[​](#next-steps "Direct link to Next steps")

* [Define your configuration's schema](https://prismatic.io/docs/integrations/headless-configuration/schema.md)
* [Write server functions](https://prismatic.io/docs/integrations/headless-configuration/server-functions.md)
* [Build a configuration UI with Solis React](https://prismatic.io/docs/embed/headless/react.md)
* [Migrate an integration from config pages](https://prismatic.io/docs/integrations/headless-configuration/migrating-from-config-pages.md)
