Skip to main content

Setup & Stages

The Flamingock setup organizes and executes your changes using stages. By default, you'll use a single stage that groups all your changes and executes them sequentially.

Changes within a stage are executed sequentially with order guaranteed. However, execution order between stages is not guaranteed - Flamingock handles system and legacy stages appropriately to ensure correctness.

Setup configuration

Flamingock is configured using the @EnableFlamingock annotation on any class in your application. This annotation is required for all environments — whether you're using the standalone runner or Spring Boot integration.

The annotation is only used for defining the setup (stages and their sources). No runtime configuration should be placed here.

Defining the setup

Here's the default single-stage configuration:

@EnableFlamingock(
stages = { @Stage(location = "com.yourcompany.changes") }
)
public class FlamingockConfig {
// Configuration class
}

Alternatively, using a YAML file:

@EnableFlamingock( pipelineFile = "config/setup.yaml" )
public class FlamingockConfig {}

Where config/setup.yaml contains:

pipeline:
stages:
- name: main
location: com.yourcompany.changes
Advanced options:
  • Multiple stages: For complex scenarios requiring independent change sets go to the stage section below
  • File-based configuration: Use pipelineFile parameter for YAML configuration
  • Explicit naming: Use @Stage(name = "custom", location = "com.yourcompany.changes")

Multiple Stages (Advanced)

Most applications will naturally fit into a single stage, which keeps things simple and ensures a clear, deterministic execution order. However, if you prefer to organize changes into multiple stages—for example, to separate concerns or enforce isolated execution flows—Flamingock fully supports that as well. We’ll explain how it works and what to consider when taking that approach.

Default approach:

Most applications use a single stage: @Stage(location = "com.yourcompany.changes"). The name is auto-derived ("changes") and this is the recommended default setup.

When to Use Multiple Stages

Multiple stages are beneficial in specific scenarios:

Multi-module Applications

In monolithic applications with well-defined module boundaries, you can give each module its own stage for full autonomy:

@EnableFlamingock(
stages = {
@Stage(name = "user-module", location = "com.yourapp.users.changes"),
@Stage(name = "billing-module", location = "com.yourapp.billing.changes"),
@Stage(name = "notification-module", location = "com.yourapp.notifications.changes")
}
)

This approach allows:

  • Independent change management across modules
  • Different release cycles for different modules
  • Clear separation of concerns and responsibilities

Functional Separation

You might want to separate changes by function or lifecycle:

@EnableFlamingock(
stages = {
@Stage(name = "core-setup", location = "com.yourapp.setup.changes"),
@Stage(name = "business-logic", location = "com.yourapp.business.changes"),
@Stage(name = "monitoring-setup", location = "com.yourapp.monitoring.changes")
}
)

Restrictions and Important Considerations

No Execution Order Guarantees

Critical limitation: Flamingock does not guarantee execution order between stages. This means:

  • Stage A might execute before, after, or concurrently with Stage B
  • You cannot rely on changes in one stage being applied before another stage starts
  • Each stage should be completely independent from others

Why This Matters

Consider this problematic scenario:

// ❌ PROBLEMATIC: Relies on execution order
@EnableFlamingock(
stages = {
@Stage(name = "create-tables", location = "com.yourapp.schema"), // Creates tables
@Stage(name = "seed-data", location = "com.yourapp.data") // Inserts data - DEPENDS on tables existing!
}
)

The seed-data stage might execute before create-tables, causing failures.

Correct Approach

Instead, group dependent changes in the same stage:

// ✅ CORRECT: All related changes in one stage
@EnableFlamingock(
stages = {
@Stage(location = "com.yourapp.changes") // Contains both table creation AND data seeding in order
}
)

When NOT to Use Multiple Stages

Avoid multiple stages when:

  • You need execution order across different change types - Use a single stage instead
  • Changes are logically related - Keep them together for easier maintenance
  • Simple applications - The complexity isn't worth the overhead
  • Cross-cutting concerns - Changes that affect multiple areas should be in one stage
Future Enhancements

Conditional stage execution based on dependencies or conditions is planned for future releases, which would allow:

  • Running stages based on success/failure of other stages
  • Defining explicit dependencies between stages
  • More sophisticated stage orchestration patterns

Required fields

Each stage must define:

  • name (optional): A unique identifier - if not provided, it will be auto-derived from the location
  • location: The package or directory where changes are located

Stage fields

FieldRequiredDescription
locationPackage or directory scanned for both code-based and template-based changes
nameUnique identifier for the stage (auto-derived from location if not provided)
descriptionOptional text explaining the stage's purpose

Where Changes are located

  • location refers to a source package (e.g., com.company.changes), a relative(e.g., my/path/changes) or absolute(e.g., /my/path/changes) resources directory.

    • Template-based and code-based changes can co-exist if location is a source package.
    • If location references a resource directory, it only accepts template-based changes.
    • Default source roots: src/main/java, src/main/kotlin, src/main/scala, src/main/groovy.
    • Source root can be customized via the sources compiler option.
    • Resource root can be customized via the resources compiler option.
  • Customizing Source and Resource Root Paths

tasks.withType<JavaCompile> {
options.compilerArgs.addAll(listOf(
"-Asources=custom/src",
"-Aresources=custom/resources"
))
}

Example Pipeline

pipeline:
stages:
- name: user-setup
description: User-related DB setup
location: com.yourapp.flamingock.users

Folder view:

src/
main/
java/
com/
yourapp/
flamingock/
users/
_0001__CreateUsersTable.java
_0002__AddIndex.yaml

Best Practices

In most applications, changes that require a specific, deterministic execution order should be grouped into a single stage. This ensures they are applied sequentially and in the exact order they are defined.

@EnableFlamingock(
stages = {
@Stage(location = "com.yourcompany.changes")
}
)

Grouping related changes into a single stage:

  • Ensures predictable, sequential execution
  • Avoids ambiguity from cross-stage execution timing
  • Eliminates the need to manage inter-stage dependencies
  • Keeps setup simple and easier to maintain
  • Supports mixing all types of changes (Kafka, MongoDB, SQL, S3, etc.) in a well-defined order
Advanced scenarios

If your application benefits from separating changes—for example, by module or lifecycle—you can define Multiple Stages (Advanced). Just remember: deterministic execution is guaranteed only within a stage, not across them.

Placing your changes

We strongly recommend placing all your changes — code-based and template-based — in a single location defined by the @Stage annotation.

  • Ensures changes are always scanned, regardless of type
  • Avoids needing two locations if one template-based change requires fallback to code
  • Keeps everything in one logical location

Naming Convention for Changes

To ensure clarity and enforce ordering, we recommend naming changes using the following format:

_0001__CreateClientsTable.java
_0002__AddIndexToEmail.yaml
_0003__MigrateData.java
_0004__ComplexChange.yaml
  • ORDER: The execution order extracted between the first _ and last _
    • Recommended format: NNNN with left-padding zeros (e.g., 0001, 0002, 0010)
  • CHANGE_NAME: Descriptive name of what the change does

This convention:

  • Eliminates the need for order in annotations/YAML - the order is extracted from the filename
  • Natural sequential sorting - files automatically sort numerically
  • Clear execution order - instantly see the sequence of changes
  • Works across both code-based and template-based formats
  • Sufficient capacity - supports up to 99 changes with two-digit format
  • Ensures consistent naming and project hygiene
tip

While Java typically avoids underscores and leading digits, change units are not traditional classes. Prioritizing readability and order is more valuable in this context.

Complete Order Field Rules

For detailed rules about order and file naming, see Change Anatomy - File name and order.

🛠 Troubleshooting

My stage isn't picked up

  • Make sure the stage has a location field defined
  • Check the file path is correct and uses / as a separator, not . in YAML
  • If using resource directory paths, make sure the file is placed under src/main/resources/your-dir

No changes found in stage

  • Verify that the class or YAML file is located in the expected package/directory
  • For code-based changes, ensure the class is annotated with @Change or @Change
  • For template-based changes, check file names and YAML formatting