Placeholders in Flyway are variables that let you parameterize SQL migrations so the same script can run in different environments with different values.
📌 One-liner:
“Placeholders let you write one migration and inject environment-specific values at runtime.”
How placeholders work (mechanics)
In a migration SQL file:
CREATE SCHEMA ${schema_name};
GRANT SELECT ON ALL TABLES IN SCHEMA ${schema_name} TO ${readonly_user};
In configuration:
flyway.placeholders.schema_name=public
flyway.placeholders.readonly_user=app_ro
Flyway:
- Loads the migration
- Replaces
${...}with configured values - Executes the resulting SQL
➡️ Replacement happens before execution, not in the database.
Where placeholders are configured
You can define them in multiple ways:
Application config
flyway.placeholders.env=prod
Command line
-Dflyway.placeholders.env=dev
CI/CD secrets
- DB names
- Users
- Schemas
- Feature flags
Interview phrase:
“Placeholders are resolved by Flyway, not by the database.”
Typical real-world use cases (important)
✅ Environment-specific schema names
CREATE TABLE ${schema}.users (...);
schema=public in prod
schema=test_schema in tests
✅ Different DB users / roles
GRANT INSERT ON users TO ${app_user};
✅ Conditional naming (indexes, partitions)
CREATE INDEX idx_${env}_users_email ON users(email);
✅ Feature toggles in migrations (use carefully)
-- Only enabled in some environments
INSERT INTO config(key, value)
VALUES ('feature_x', '${feature_x_enabled}');
What placeholders should NOT be used for
This is where senior engineers stand out.
❌ Schema logic changes
Don’t do:
${create_users_table_sql}
That makes migrations:
- non-reviewable
- non-deterministic
- dangerous
📌 Strong interview sentence:
“Placeholders should parametrize values, not behavior.”
❌ Hiding incompatible migrations
Using placeholders to avoid running parts of migrations in prod/test is a red flag.
Safety & reproducibility concerns
Because placeholders change the executed SQL:
- The same migration version may run different SQL
- This slightly weakens reproducibility guarantees
Best practice:
- Keep placeholder usage minimal
- Use them only for names and identifiers
- Never for structural logic
Defaults & escaping (small but nice detail)
- Default placeholder prefix:
${ - Default suffix:
} - You can disable placeholders entirely:
flyway.placeholderReplacement=false
You can also escape:
SELECT '${not_a_placeholder}';
Placeholders vs repeatable migrations (nice comparison)
| Feature | Placeholders | Repeatable |
| ------------ | ---------------- | ----------------- |
| Purpose | Parametrize SQL | Re-run on change |
| Re-execution | No | Yes |
| Env-specific | Yes | Sometimes |
| Risk | Divergent schema | Accidental re-run |
Interview-ready answer (perfect)
2–3 sentences:
“Placeholders in Flyway allow parameterizing SQL migrations so the same migration can be reused across environments with different values, like schema names or users. Flyway replaces placeholders before executing the SQL. They should be used sparingly for identifiers and configuration values, not to change migration logic.”
That answer sounds confident and senior.