Skip to main content

Migrating from Config Pages

If a code-native integration uses config pages, you can publish a new version that uses headless configuration instead. Existing instances keep running on the config pages version until you update them, and your init function converts their config variable values to the new configuration.

What changes​

Config pagesHeadless configuration
configPages with configVar() elementsA configuration() with a schema
Prismatic renders the config wizardYour app renders the form
Values are strings in context.configVarsValues have real types in context.configuration
Data sources supply dynamic optionsServer functions supply dynamic options
Connections are config variables on a pageConnections are declared in the configuration
A flow's schedule can come from a config variableA flow's schedule is fixed, or supplied by the deployer

Migrate the integration​

  1. Write the new schema. Describe the values your flows need with their real types, such as batchSize: z.number() instead of a "Batch Size" string. See Defining a schema with zod.

  2. Describe the old values. Add a configPagesSchema that matches the config variables your config pages collected, keyed by name. Config pages store scalars as strings, so accept either form:

    src/configuration.ts
    export const configPagesSchema = z.object({
    Region: z.string(),
    "Sync Enabled": z.union([z.boolean(), z.string()]),
    "Batch Size": z.union([z.number(), z.string()]),
    });
  3. Replace config pages with a configuration, and convert the old values in init. Remove configPages from your integration, and pass a configuration that includes the configPagesSchema.

    An instance that was configured with config pages has never saved a headless configuration, so in init, context.configurationVersion is null. In that case, context.configuration holds the config page values, keyed by config variable name. Spectral types it from your configPagesSchema, with every field optional. Convert each value, and report anything you can't carry over:

    src/configuration.ts
    const DEFAULTS: Configuration = {
    region: "us-east",
    syncEnabled: true,
    batchSize: 100,
    };

    export const integrationConfiguration = configuration({
    instance: {
    schema: configurationSchema,
    version: "order-sync-v1",
    configPagesSchema,
    },
    init: {
    perform: async (context) => {
    if (context.configurationVersion === null) {
    // Typed from configPagesSchema, with every field optional
    const legacy = context.configuration;
    const batchSize = Number(legacy["Batch Size"]);
    const validBatch = Number.isInteger(batchSize) && batchSize > 0;
    return {
    configuration: {
    region: legacy.Region ?? DEFAULTS.region,
    syncEnabled:
    legacy["Sync Enabled"] === undefined
    ? DEFAULTS.syncEnabled
    : String(legacy["Sync Enabled"]) === "true",
    batchSize: validBatch ? batchSize : DEFAULTS.batchSize,
    },
    unresolvedReasons: validBatch
    ? []
    : [
    `Batch size "${String(legacy["Batch Size"])}" isn't valid; using 100.`,
    ],
    };
    }
    // Handle the current version as shown in Configuration versions and init
    const saved = configurationSchema.safeParse(context.configuration);
    return {
    configuration: saved.success ? saved.data : DEFAULTS,
    unresolvedReasons: [],
    };
    },
    },
    });
  4. Read configuration in flows. Replace context.configVars reads with context.configuration, and delete the string parsing your flows no longer need.

  5. Replace data sources with server functions and declare your connections in the configuration.

  6. Replace config variable schedules. A flow whose schedule reads a config variable, schedule: { configVar: "..." }, won't build once the integration has a configuration. Change it to a fixed { value } schedule, or to { fromDeployer: true } so the customer chooses the schedule in your app.

  7. Publish the new version and make it available in your marketplace.

Always migrate through init

An instance on a config pages version has no headless configuration value, and your app can't read its config variables directly. The only way across is the new version's init, followed by save.

note

If an instance's config page values are missing, return sensible defaults and explain them in unresolvedReasons, so the customer can review the values before saving.

Migrate instances​

To your app, the new version appears as an update that requires reconfiguration:

  1. Your app sees update.requiresReconfiguration on the instance.
  2. It opens the update's configuration and runs init, which converts the config variable values.
  3. The customer reviews the suggested values, and any unresolvedReasons, in your form.
  4. Your app saves the configuration, which moves the instance to the new version, and deploys it.

Until you migrate an instance, it stays on a config pages version. Its configuration experience is hosted, so your app can keep opening Prismatic's config wizard for it. See Building configuration UIs with Solis React.