Anatomy of a lekko

Anatomy of a lekko

Lekko’s powerful features revolve around dynamically configurable functions that we call lekkos. You can think of a lekko as the smallest unit of dynamic configuration - even though you define lekkos in your code, you can change their behavior outside of your code at runtime. What’s more, lekkos can live across multiple projects and/or languages so you can manage shared configuration effectively.

In this page, we explore the anatomy of a lekko through an example and go over terminology that will help you understand some of Lekko’s capabilities.

Feature flag example

For this example, we’ll look at a feature flag (which is a type of dynamic configuration) that controls whether experimental features are enabled in our project. We want the choice to be based on the environment the app is running in (for example, staging vs production).

Let’s take a look at what this flag might look like as a lekko:

// Whether to use experimental features or not
func getExperimentalEnabled(env string) bool {
  if env == "staging" {
    return true
  }
  return false
}

As you can see above, lekkos are just regular functions. If there are multiple places in your project where you need to check whether experimental features are enabled, it’s natural to extract that logic into its own function. Lekkos follow this principle and enhance it by adding dynamic control to the logic without having to write code in an unnatural way.

Lekkos are also cross-language. In a typical SaaS app, it might be necessary to check whether experimental features are enabled on both the frontend and the backend. To ensure cross-language compatibility, lekkos support a limited set of syntax constructs that map to language-agnostic components. The following sections on this page go over these components.

ℹ️

For each supported language, we publish a linter plugin that gives warnings for any unsupported code. We recommend checking out the SDK docs for your languages for specific guides.

Components

Name

Lekkos names start with get and the casing is based on language conventions. Their agnostic names are kebab-cased, so for example, on the web UI, you see experimental-enabled while in Go and TypeScript, you use getExperimentalEnabled.

// Whether to use experimental features or not
func getExperimentalEnabled(env string) bool {
  if env == "staging" {
    return true
  }
  return false
}

Description

Descriptions are meant to be used as simple code documentation.

// Whether to use experimental features or not
func getExperimentalEnabled(env string) bool {
  if env == "staging" {
    return true
  }
  return false
}

Context variables

You can think of context variables as the inputs for lekkos. The purpose of lekkos is to define configuration logic based on the execution context.

In this example, we define env as a string context variable since we want to decide whether to enable experimental features based on staging, production, etc.

// Whether to use experimental features or not
func getExperimentalEnabled(env string) bool {
  if env == "staging" {
    return true
  }
  return false
}

Type

Lekkos are typed functions. To avoid issues caused by misconfigurations, it’s important that the possible values (and therefore types) are known and validated against.

// Whether to use experimental features or not
func getExperimentalEnabled(env string) bool {
  if env == "staging" {
    return true
  }
  return false
}

Overrides

Lekkos define conditional logic based on context variables, and each conditional branch is called an override.

Overrides are composed of rules (the conditions) and return values.

The final/fallthrough return value can be thought of as the default value of the lekko, which is returned when none of the overrides apply. Note that there’s nothing unique about the evaluation logic of lekkos - it’s completely fine to think of overrides as regular if statements.

// Whether to use experimental features or not
func getExperimentalEnabled(env string) bool {
  if env == "staging" {
    return true
  }
  return false
}