Skip to main content

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 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. 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​

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:

PartWhat it does
SchemaDefines the shape of the values an instance saves. You write it with zod or JSON Schema. See Schema.
VersionNames the current shape of the schema, such as acme-crm-v1. See Configuration versions.
InitSuggests starting values for your instance's configuration. It helps when converting a hosted configuration to headless, or when upgrading versions.
Server functionsFunctions your app calls while a customer configures an instance, such as listing the record types in a customer's CRM. See Server functions.

The configuration can also declare the connections the integration needs.

A minimal headless configuration
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, 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
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​

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
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.

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​

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​

The 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.

Next steps​