Skip to content

Flavors

Flavors allow you to define different configurations for different environments (development, staging, production) using JSON Patch (RFC 6902). Instead of duplicating configuration, you define a base config and patches that modify it.

  1. EMB loads your base configuration
  2. When you specify a flavor with --flavor, EMB applies the patches
  3. The patched configuration is used for the operation

Define flavors at the project level to affect global settings:

.emb.yml
env:
DOCKER_TAG: ${env:DOCKER_TAG:-latest}
flavors:
production:
patches:
- op: replace
path: /env/DOCKER_TAG
value: ${env:DOCKER_TAG}-production

Define flavors within a component to change its build settings:

frontend/Embfile.yml
resources:
image:
type: docker/image
params:
target: development
flavors:
production:
patches:
- op: replace
path: /resources/image/params/target
value: production

Flavors use JSON Patch RFC 6902. Common operations:

Change an existing value:

patches:
- op: replace
path: /resources/image/params/target
value: production

Add a new property:

patches:
- op: add
path: /resources/image/params/buildArgs/DEBUG
value: "false"

Remove a property:

patches:
- op: remove
path: /resources/image/params/buildArgs/DEBUG
Terminal window
emb up --flavor production
Terminal window
emb run test --flavor production

A common pattern is using flavors for multi-stage Docker builds:

# Dockerfile
FROM node:20 AS base
WORKDIR /app
COPY package*.json ./
FROM base AS development
RUN npm install
COPY . .
CMD ["npm", "run", "dev"]
FROM base AS production
RUN npm ci --only=production
COPY . .
CMD ["npm", "start"]
Embfile.yml
resources:
image:
type: docker/image
params:
target: development
flavors:
production:
patches:
- op: replace
path: /resources/image/params/target
value: production

Now:

  • emb up builds and runs the development stage
  • emb up --flavor production builds and runs the production stage

You can also build resources explicitly with emb resources build --flavor production.

When both project-level and component-level flavors with the same name exist, both are applied:

  1. Project-level patches are applied first
  2. Component-level patches are applied second

This allows you to:

  • Set global environment changes at project level
  • Set component-specific build changes at component level

To see what configuration a flavor produces:

Terminal window
emb config print --flavor production

This shows the fully resolved configuration after applying flavor patches.

Beyond JSON Patch, flavors can set a defaults.rebuildPolicy that changes how EMB decides whether a resource needs a rebuild. Today this applies to docker/image resources.

The common case: in dev, source is bind-mounted into containers via docker-compose.devel.yml, so rebuilding the image on every source change is pointless — the container already sees the new code. You only want a rebuild when image-shaping files change (Dockerfile, package.json, lockfiles, system-package lists).

Set a flavor-wide policy under defaults.rebuildPolicy['docker/image']:

flavors:
dev:
defaults:
rebuildPolicy:
docker/image:
strategy: watch-paths
paths:
- Dockerfile
- package.json
prod: {} # absent → falls back to the builtin 'auto' strategy

Three strategies are available:

StrategyRebuilds whenTypical use
auto (default)any git-tracked file in the docker context changedCI, production
alwaysevery invocationimages fetching external content at build time
watch-pathsone of the listed paths changeddev with bind-mounted source

A resource’s own rebuildTrigger wins against any flavor-level default:

component/Embfile.yml
resources:
image:
type: docker/image
rebuildTrigger:
strategy: always # wins even when --flavor dev sets watch-paths

See the full precedence and path semantics in the configuration reference. A runnable example lives under examples/rebuild-triggers/.