Configuration as Code

Configuration as Code

Introduction

Abby aims to have the best Developer Experience possible. This is why Abby is fully configurable via Code. No need to click some buttons in a GUI. You abby.config.ts (or abby.config.js) file is the single source of truth for your Abby project.

Your configuration should be written in a file called abby.config.ts (or abby.config.js) which should be located in the root of your project. Every integration offers a defineConfig helper function which offers a typesafe way to define your configuration.

import { defineConfig } from "@tryabby/core";
// or import { defineConfig } from "@tryabby/<integration>";

The config needs to be the default export of the file so that the CLI can find it.

import { defineConfig } from "@tryabby/core";
// or import { defineConfig } from "@tryabby/<integration>";
 
export default defineConfig(
  {
    // your projectId and other sensitive data here
  },
  {
    // your flags, tests, etc. here
  }
);
💡

The first parameter includes all data that might be configured via environment variables. You should not use environment variables in the second parameter, because the type inference might suffer and the CLI could potentially resolve those environment variables!

Philosophy

This configuration has two purposes:

1. Integrations

Abby has many integrations to other tools and frameworks. Those can import the config and use it to configure themselves. For example the @tryabby/nextjs integration uses the config to configure the Next.js framework. Reading the config makes the integrations fully typesafe

2. CLI

The Abby CLI uses the config to know what to do. It reads from the config and can then be used to create tests or feature flags on the Abby platform without any further configuration.

Example

// abby.config.ts
 
import { defineConfig } from "@tryabby/core";
// or import { defineConfig } from "@tryabby/<integration>";
 
export default defineConfig(
  {
    projectId: "my-project-id",
    currentEnvironment: "development",
  },
  {
    environments: ["development", "production"],
    tests: {
      SignupButton: {
        variants: ["A", "B"],
      },
    },
    flags: ["showFooter"],
    remoteConfig: {
      customButtonText: "String",
      maxUserCount: "Number",
      AdvancedTestStats: "JSON",
    },
    settings: {
      flags: {
        defaultValue: false,
        devOverrides: {
          showFooter: true,
        },
      },
      remoteConfig: {
        defaultValues: {
          JSON: {},
          Number: 0,
          String: "",
        },
        devOverrides: {
          maxUserCount: 40,
          AdvancedTestStats: {},
          customButtonText: "My cool button",
        },
      },
    },
  }
);

Config Reference

The defineConfig function takes two objects as a parameter, that will be merged together when read. The merged object can contain the following properties:

NameTypeRequiredDescriptiondetails
projectIdstringThe ID of your project in Abby-
apiUrlstringThe URL of the Abby API. Defaults to the hosted version-
currentEnvironmentstringThe current environment of your applicationlink
testsobjectAn object containing your defined A/B Tests-
flagsarrayAn array containing your defined Feature Flag names-
remoteConfigobjectAn object containing your Remote Configuration variables-
settingsobjectAn object with additional settings for Abby-
debugbooleanA boolean to show additional debug information-
fetchfetchYou can pass in a custom fetch function. Defaults to globalThis.fetch-

tests

The tests property is an object containing your defined A/B Tests. You probably want to use the Copy Button in your dashboard to copy the tests object. They keys of the object represent the names of your predefined A/B tests. The values are objects containing the following properties:

NameTypeRequiredDescription
variantsArray<string>An array of strings containing the variants of the test
Example
const abby = createAbby({
  // ... your config
  tests: {
    "test-abtest": {
      variants: ["control", "variant-a", "variant-b"],
    },
  },
});

flags

The flags property is an array containing your defined Feature Flags. You probably want to use the Copy Button in your dashboard to copy the flags array.

Example
const abby = createAbby({
  // ... your config
  flags: ["test-flag"],
});

remoteConfig

The remoteConfig property is an object containing your Remote Configuration variables and their respective types.

Example
const abby = createAbby({
  // ... your config
  remoteConfig: {
    myStringVariable: "String",
    myNumberVariable: "Number",
    myJSONVariable: "JSON",
  },
});

settings

The settings property is an object containing additional settings for Abby. The following properties are available:

  • flags.defaultValue: Allows you to set a fallback boolean value for your Feature Flags, in case you forgot to add them in your dashboard or when they could not be fetched correctly.

    flags: {
      defaultValue: true,
    },
  • flags.devOverrides: An object containing the values of feature flags in development mode. The keys of the object represent the names of the flags.

    flags: {
      devOverrides: {
        showHeader: true,
        showFooter: false,
      },
    },
  • remoteConfig.defaultValues: An object containing default values for each Remote Configuration type.

    remoteConfig: {
      defaultValues: {
        String: "Default string value",
        Number: 100,
        JSON: { default: true },
      },
    },
  • remoteConfig.devOverrides: An object containing the values of Remote Configuration variables in development mode. The keys of the object represent the names of the flags. The values need to be of the type of the variable. The value must be of the same type as the variable.

    remoteConfig: {
      devOverrides: {
        myStringVariable: "dev mode string value",
        myNumberVariable: 100,
        JSON: { devMode: true },
      },
    },

debug

A boolean that you can toggle on to get debug information logged to the console. Mostly useful in development to see where something potentially goes wrong.

fetch

You can pass a custom fetch function in here. This defaults to the global fetch function. This is mostly needed for older versions of Node.js which don't have a global fetch function.