SAAS configuration
Evolve manages SAAS service configuration through Terraform, the same infrastructure-as-code tool used for cloud resources. This means commercetools projects, CMS content models, search indices, and observability tools are all defined declaratively, version-controlled, and reproducible across environments.
This approach may be unfamiliar if you're used to configuring SAAS
services through their web interfaces. The benefit is significant:
spinning up a new environment (staging, demo, new client) is a single
terraform apply that provisions everything, from cloud infrastructure
to SAAS configurations, in one go. No manual clicking through admin
panels, no forgotten settings, no configuration drift between
environments.
What gets configured
Evolve includes Terraform configurations for all integrated SAAS services:
backend/configuration/
├── commercetools/ # Project settings, stores, channels,
│ # product types, tax categories
├── contentful/ # Locales, content types, editor interfaces
├── storyblok/ # Components, component groups
└── algolia/ # Indices, virtual indices, facet config
Each directory contains a self-contained Terraform module that can be applied independently or orchestrated through MACH Composer.
Commerce configuration
The commercetools Terraform provider manages the commerce backend: project settings, stores, channels, product types, and tax categories.
resource "commercetools_project_settings" "project" {
name = "my-project"
countries = ["NL", "DE", "GB"]
currencies = ["EUR", "GBP"]
languages = ["nl-NL", "en-GB", "de-DE"]
messages {
enabled = true
}
carts {
country_tax_rate_fallback_enabled = true
delete_days_after_last_modification = 90
}
}
resource "commercetools_store" "primary" {
key = "my-store"
name = { nl-NL = "My Store" }
languages = commercetools_project_settings.project.languages
countries = commercetools_project_settings.project.countries
distribution_channels = [
commercetools_channel.store.key
]
}
Product types, which define the attributes available on products, are also managed through Terraform. This ensures the data model is consistent across environments:
resource "commercetools_product_type" "fashion" {
key = "fashion"
name = "Fashion"
description = "Fashion product type"
attribute {
name = "brand"
label = { en-GB = "Brand", nl-NL = "Merk" }
constraint = "None"
type = { name = "text" }
searchable = true
}
}
CMS configuration
Both Contentful and Storyblok content models are defined in Terraform. This means the content types and components that content editors work with are version-controlled and consistent across environments.
Contentful
resource "contentful_contenttype" "hero" {
space_id = var.contentful_space_id
environment = var.contentful_environment
id = "hero"
name = "Hero"
display_field = "title"
fields = [
{
id = "title"
name = "Title"
type = "Text"
},
{
id = "image"
name = "Image"
type = "Link"
link_type = "Asset"
},
]
}
Storyblok
resource "storyblok_component" "hero" {
name = "hero"
space_id = var.storyblok_space_id
is_root = false
is_nestable = true
schema = {
title = {
position = 0
translatable = true
display_name = "Title"
required = true
type = "text"
}
image = {
position = 5
translatable = true
display_name = "Image"
required = true
type = "asset"
filetypes = ["images"]
}
}
}
Search configuration
Algolia indices, including facet configuration, searchable attributes, and sort order replicas, are managed through Terraform:
resource "algolia_index" "default" {
for_each = local.store_keys
name = "${each.value}_default"
attributes_config {
searchable_attributes = [
"name",
"description",
"variants.sku",
]
attributes_for_faceting = [
"startingPrice.centAmount",
"hierarchicalCategories.lvl0",
"variants.attributes.brand",
"variants.attributes.color.nl-NL",
"variants.attributes.size",
]
}
}
resource "algolia_virtual_index" "price_asc" {
for_each = local.store_keys
name = "${each.value}_price_asc"
primary_index_name = algolia_index.default[each.key].name
ranking_config {
custom_ranking = ["asc(startingPrice.centAmount)"]
}
}
Terraform providers
Evolve uses community-maintained Terraform providers for each SAAS service:
| Service | Provider | Source |
|---|---|---|
| commercetools | labd/commercetools | Registry |
| Contentful | labd/contentful | Registry |
| Storyblok | labd/storyblok | Registry |
| Algolia | k-yomo/algolia | Registry |
MACH Composer integration
MACH Composer ties SAAS configuration into the deployment pipeline. Each SAAS service is registered as a plugin, and components declare which integrations they need:
mach_composer:
plugins:
commercetools:
source: mach-composer/commercetools
version: 0.2.1
storyblok:
source: mach-composer/storyblok
version: 0.0.3
algolia:
source: mach-composer/algolia
version: 0.1.0
sentry:
source: mach-composer/sentry
version: 0.1.3
SAAS credentials and project-specific settings are defined per environment. MACH Composer injects these as Terraform variables when applying configurations:
sites:
- identifier: my-project
commercetools:
project_key: my-project
client_id: ${var.secrets.commercetools.client_id}
client_secret: ${var.secrets.commercetools.client_secret}
storyblok:
space_id: 233248
token: ${var.secrets.storyblok.management_token}
algolia:
app_id: YWHL59LKQC
api_key: ${var.secrets.algolia.write_api_key}
Components reference their SAAS integrations, and MACH Composer ensures the right credentials and configurations are passed to each Terraform module:
components:
- name: commercetools-config
source: ../../backend/configuration/commercetools/
integrations:
- commercetools
- name: storyblok-config
source: ../../backend/configuration/storyblok/
integrations:
- commercetools
- storyblok
- name: algolia-config
source: ../../backend/configuration/algolia/
integrations:
- algolia
This means adding a new environment is a matter of creating a new MACH Composer configuration file with the right credentials. The Terraform modules handle the rest.