Infrastructure
This page lists what an Evolve project needs to run, and which cloud services provide it. Set it up before your first deploy. How a release reaches it is in Deploying.
Two repositories
Section titled “Two repositories”Your infrastructure lives in two places. You get both from the Evolve team:
| Repository | Holds | Changes |
|---|---|---|
| The infra repository for your cloud | What every project in an environment shares: the network, Redis, the load balancer or Front Door for the API, the DNS zone, the container environment and registry, and the log workspace. | Rarely, and once per environment. |
configuration/ in your project |
What belongs to your project: a service per subgraph, its event handlers, jobs, buckets, config store, and secrets, the CDN routes for your site, and your commercetools and CMS setup. | With your project. |
Your project’s Terraform reads the infra repository’s outputs, as remote state or as data sources, so apply the infra repository first.
What Evolve needs
Section titled “What Evolve needs”| Building block | What runs on it |
|---|---|
| Containers | One image per service, each serving on port 4000: discover and purchase (the subgraphs), and notify (email). The same image also runs the service’s event handler and its jobs, with another command. The site (Next.js, standalone output) and the graphql-gateway (the Evolve gateway image, with a small proxy beside it for compression) run as containers too. |
| Event handlers | The events command of a service, started per message. It can scale to zero. |
| Scheduled jobs | The sync commands of discover (products, categories, sitemaps), and sweep in purchase. |
| Redis | The Next.js cache of the site, the cache of the services, and the rate limiter. Sessions are not in Redis: they are cookies that only the gateway can read. |
| A message bus | Two flows: one internal topic that every service publishes to, with a filtered subscription per handler, and one commercetools subscription per service for the engine’s own messages. |
| Object storage | The site’s static files, which the site uploads on start, and the product sitemaps that discover writes. |
| A config store and a secret store | Every service reads its settings from the config store at startup, with secrets as references into the secret store. The site gets its settings as environment variables. |
| A CDN | In front of the site only. Its cache key includes the session cookies, so a signed-in shopper never gets another shopper’s page. The gateway has no CDN. |
| Two hostnames | www. for the site and api. for the gateway, under one parent domain, because they share the session cookies. |
| An OpenTelemetry endpoint | Where the services send traces. See Observability. |
Outside your cloud, the project uses:
- the Evolve npm registry at build time, and the Evolve gateway image on
ghcr.io; - your commercetools project, CMS, and payment providers;
- Sentry for errors, and the Hive schema registry, which the gateway reads the supergraph from.
Per cloud
Section titled “Per cloud”| Building block | Service |
|---|---|
| Containers | Cloud Run services |
| Event handlers | A Cloud Run service per handler, which Pub/Sub pushes to with an OIDC token, with a dead-letter topic after five attempts |
| Scheduled jobs | Cloud Run jobs, started by Cloud Scheduler |
| Redis | Memorystore |
| Message bus | Pub/Sub: one topic for internal events, one per service for commercetools |
| Object storage | Cloud Storage |
| Config and secrets | Parameter Manager, with Secret Manager references |
| CDN and hosts | A global external HTTPS load balancer with Cloud CDN, managed certificates, and Cloud DNS |
| Images | Artifact Registry |
The Evolve Terraform module evolve-platform/cloud-run-service/google sets up
a service with its identity, config, and permissions.
On Google Cloud, set OTEL_PROPAGATORS=b3 on every service: the load balancer
rewrites the W3C trace header between Cloud Run services. See
Use one propagator everywhere.
| Building block | Service |
|---|---|
| Containers | Container Apps, in multiple-revision mode for blue-green releases |
| Event handlers | A Function App with a Service Bus trigger |
| Scheduled jobs | Container App jobs |
| Redis | Azure Managed Redis. Services sign in with Entra ID (?connector=azure in the Redis URL), the site with an access key. |
| Message bus | Event Grid for internal events, in the CloudEvents format. A Service Bus namespace per service for commercetools. |
| Object storage | Blob Storage |
| Config and secrets | App Configuration, with Key Vault references |
| CDN and hosts | Front Door |
| Images | Azure Container Registry |
The Evolve Terraform modules evolve-platform/key-vault/azurerm and
evolve-platform/function-app/azurerm set up the Key Vault and the event
handlers.
| Building block | Service |
|---|---|
| Services | Lambda, through the AWS adapter’s HTTP handler |
| Event handlers | Lambda with an SQS trigger, through the adapter’s SQS and EventBridge handlers |
| Redis | ElastiCache |
| Message bus | EventBridge or SQS |
| Object storage | S3 |
| Config and secrets | Systems Manager Parameter Store, with Secrets Manager references |
| CDN and hosts | CloudFront |
The packager builds a Lambda bundle per service. See Run behind AWS Lambda.
Each service picks its cloud through the adapters it composes. See Run on your cloud.
Size it
Section titled “Size it”The reference sites start every service on one instance and scale it to five. Use their sizes as a starting point, and adjust them to your traffic:
| Service | B2C on Google Cloud | B2B on Azure |
|---|---|---|
| site | 1 CPU, 1 GiB | 0.5 CPU, 1 GiB |
| graphql-gateway | 1 CPU, 512 MiB | 0.25 CPU, 0.5 GiB |
| purchase | 1 CPU, 1 GiB | 0.25 CPU, 0.5 GiB |
| discover | 1 CPU, 512 MiB | 0.25 CPU, 0.5 GiB |
| Event handlers | 1 CPU, 1 GiB, from zero to two | A Function App on the Flex Consumption plan |
| Product sync job | 2 CPU, 2 GiB, up to two hours | A Container App job |
Run test-support on test environments only, never in production.
What is public
Section titled “What is public”| Endpoint | Reachable from | Why |
|---|---|---|
| The site | The internet, through the CDN | Shoppers |
| The gateway | The internet, on the api. host |
The browser calls the API directly |
| purchase, on a path of the API host | The internet | The commercetools API extension, and the payment providers’ webhooks |
| discover | Inside your network only | Only the gateway calls it |
| Event handlers | The message bus only | Only the bus delivers messages to them |
The subgraphs trust the network: they do not check who calls them. The gateway alone holds the keys of the session cookies, and passes the session on to the subgraphs in a header. So keep discover internal, and let the gateway be the only way in to purchase’s GraphQL API.
Each public entry point checks its caller: the API extension a bearer secret, and each payment webhook the provider’s signature.
Set up commercetools and the CMS
Section titled “Set up commercetools and the CMS”configuration/ also sets up the vendors, with their Terraform providers:
configuration/commercetoolssets up your commercetools project: its settings, stores, and product and custom types. Each service gets an API client of its own, with only the scopes it needs, through theevolve-platform/ct-client-secretmodule. The commercetools subscriptions and the API extension are part of each service’s module.configuration/storyblokorconfiguration/contentfulsets up the content model of your CMS. The CMS package can write it for you: seeevolve tf-exportfor Contentful and Storyblok.
Apply them before you deploy the services, because the services read the API clients and subscriptions that Terraform writes into their config.

