Skip to main content

Change Anatomy & Structure

Every Change is configured through key components that work together, following the natural development workflow:

Understanding this anatomy is essential for creating reliable changes that execute predictably and safely.

Complete example

Here's what a complete Change looks like with minimal configuration - we'll explain each component in detail below:

@TargetSystem("user-database")
@Change(id = "add-user-status", author = "backend-team")
public class _0001__AddUserStatus {

@Apply
public void apply(MongoDatabase database) {
database.getCollection("users")
.updateMany(
new Document("status", new Document("$exists", false)),
new Document("$set", new Document("status", "active"))
);
}

@Rollback
public void rollback(MongoDatabase database) {
database.getCollection("users")
.updateMany(
new Document(),
new Document("$unset", new Document("status", ""))
);
}
}

Now let's break down each component:

File name and order

The execution order of Changes is determined by the filename pattern. Every Change file must follow the _ORDER__CHANGE-NAME format.

File naming pattern

Pattern: _ORDER__CHANGE-NAME.[java|yaml]

  • ORDER: Alphanumeric string (required: at least 4 characters, left-padded zeros)
  • Double underscore __: Separates order from change name
  • CHANGE-NAME: PascalCase descriptive name

Examples:

_0001__CreateInvoiceCollection.java
_0002__AddUserStatusColumn.yaml
_0003__MigrateUserData.java
_0010__OptimizeQueries.java

How Flamingock extracts order

Flamingock uses a simple rule to determine execution order:

  1. Filename must start with underscore _
  2. Everything between the first _ and __ (double underscore) becomes the order
  3. Everything after __ is the descriptive name

Name examples:

FilenameExtracted OrderChange Name
_0001__CreateUsers.java0001CreateUsers
_0010__SimpleChange.yaml0010SimpleChange
_V1_2__DatabaseUpgrade.javaV1_2DatabaseUpgrade

Order rules:

  • Required: Orders must be at least 4 characters (compilation requirement)
  • Recommended format: NNNN with left-padding zeros (e.g., 0001, 0002, 0010)
  • Flexibility: Can contain any characters valid for OS filenames and Java class names
  • Evaluation: Orders are compared alphanumerically for execution sequence
  • Immutability: Cannot be changed once deployed

Change annotation properties

The @Change annotation must define these two properties, with optional properties available (covered later):

id - Unique identifier

The id must be unique across all Changes in your application.

@Change(id = "add-user-status", author = "dev-team")

Rules:

  • Must be unique application-wide
  • Use descriptive names (e.g., add-user-status, not change1)
  • Cannot be modified once deployed

author - Responsibility tracking

Identifies who is responsible for this change.

@Change(id = "update-schema", author = "database-team")
@Change(id = "migrate-users", author = "john.doe@company.com")

Best practices:

  • Use team names for shared responsibility: database-team, api-team
  • Use individual emails for personal changes: john.doe@company.com
  • Keep consistent within your organization

Target system annotation

@TargetSystem - System specification

Declares which target system this Change affects.

@TargetSystem("user-database")
@Change(id = "add-user-fields", author = "api-team")
public class _0001__AddUserFields {
// Implementation
}

Apply and rollback methods

Both methods implement your change logic and automatically receive the dependencies they need through parameters.

@Apply - Change logic

Contains the actual change implementation.

@Apply
public void apply(S3Client s3) {
// Your change logic here
s3.putBucketPolicy(/* configure bucket */);
}

@Rollback - Undo logic

Provides logic to reverse the change, essential for safety and CLI undo operations.

@Rollback
public void rollback(S3Client s3) {
// Undo the change
s3.deleteBucketPolicy(/* remove configuration */);
}

Why rollback is required:

  • Executed automatically on failure for non-transactional systems
  • Required for CLI/UI undo operations
  • Ensures every change can be reversed

For detailed information about method parameters, dependency injection, and advanced parameter features, see Apply and rollback methods.

Optional properties

The @Change annotation supports additional optional properties to control behavior:

transactional - Transaction behavior

Controls whether the change runs within a transaction (default: true).

@Change(
id = "create-large-index",
author = "db-team",
transactional = false // DDL operations may require this
)

Important: For non-transactional target systems (S3, Kafka, etc.), this flag has no effect.

recovery - Failure handling strategy

Controls how Flamingock handles execution failures (default: MANUAL_INTERVENTION).

// Default behavior (manual intervention)
@Change(id = "critical-change", author = "team")
public class _0001__CriticalChange {
// Execution stops on failure, requires manual resolution
}

// Automatic retry
@Recovery(strategy = RecoveryStrategy.ALWAYS_RETRY)
@Change(id = "idempotent-change", author = "team")
public class _0002__IdempotentChange {
// Automatically retries on failure until successful
}

Recovery strategies:

  • MANUAL_INTERVENTION (default): Stops execution on failure, requires CLI resolution
  • ALWAYS_RETRY: Automatically retries on subsequent executions until successful

For detailed information on recovery strategies, see Safety and Recovery.

Next steps