Aplicações evoluem com o tempo — seja por melhorias, novas funcionalidades ou adaptações — e isso quase sempre exige modificações no banco de dados. Em projetos Java com Spring Boot, é comum usar Spring Data JPA e configurar para que o schema seja criado ou atualizado automaticamente a partir das entidades definidas. Essa automação é extremamente conveniente durante o desenvolvimento, mas deixá-la ativa em produção pode representar um risco significativo.

A recomendação é que a criação ou atualização do esquema do banco seja feita por meio de scripts SQL incrementais. Sempre que houver uma modificação necessária, deve-se criar um script de migração(migration) que pode ser versionado junto ao código-fonte. Assim, para levantar o banco no estado atual, basta executar todos os scripts em sua ordem cronológica original. Se for preciso migrar um banco de uma versão mais antiga para uma versão mais recente, identifica-se qual foi o último script já aplicado e, a partir dele, executam-se todos os scripts subsequentes até alcançar o estado desejado.

Você pode pensar que executar manualmente os scripts SQL em ordem, além de controlar quais já foram aplicados, seja algo complicado e sujeito a erros — e, de fato, você está certo. É exatamente para resolver isso que surgem ferramentas como o Flyway.

O que é o Flyway?

Flyway é uma ferramenta de versionamento de banco de dados baseada em scripts de migrações(migrations) que controla automaticamente quais migrações já foram aplicadas por meio de uma tabela de histórico. Quando novas migrations aparecem, o Flyway compara os scripts existentes com o histórico registrado e executa apenas os scripts ainda pendentes, de modo rápido, seguro e ordenado.

Para começar, precisamos configurar o DataSource no Spring Boot e desativar (ou comentar) as propriedades como spring.jpa.generate-ddl e spring.jpa.hibernate.ddl-auto caso estejam definidas, para evitar conflitos.

spring.datasource.url=jdbc:mysql://localhost/teste_flyway
spring.datasource.username=root
spring.datasource.password=123456
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect

Depois, adicionamos a dependência principal do Flyway no pom.xml do projeto. Dependendo do banco de dados que você vai usar, também será necessário incluir a dependência específica do banco de dados, podemos ver na página de referência dos drivers.

<dependency>
	<groupId>org.flywaydb</groupId>
    <artifactId>flyway-core</artifactId>
</dependency> 
<dependency>
    <groupId>org.flywaydb</groupId>
	<artifactId>flyway-mysql</artifactId>
</dependency>

A partir deste ponto, o Flyway já está totalmente integrado à aplicação. Ao executar o projeto, você poderá observar nos logs do Spring Boot as mensagens indicando a inicialização do Flyway, a detecção dos scripts de migração e a execução de cada um deles.

2025-10-15T09:10:02.972-03:00  INFO 1440 --- [flyway] [           main] org.flywaydb.core.FlywayExecutor         : Database: jdbc:mysql://localhost/teste_flyway (MySQL 8.0)
2025-10-15T09:10:04.276-03:00  INFO 1440 --- [flyway] [           main] o.f.c.i.s.JdbcTableSchemaHistory         : Schema history table `teste_flyway`.`flyway_schema_history` does not exist yet
2025-10-15T09:10:04.405-03:00  INFO 1440 --- [flyway] [           main] o.f.core.internal.command.DbValidate     : Successfully validated 0 migrations (execution time 00:00.672s)
2025-10-15T09:10:04.405-03:00  WARN 1440 --- [flyway] [           main] o.f.core.internal.command.DbValidate     : No migrations found. Are your locations set up correctly?
2025-10-15T09:10:05.049-03:00  INFO 1440 --- [flyway] [           main] o.f.c.i.s.JdbcTableSchemaHistory         : Creating Schema History table `teste_flyway`.`flyway_schema_history` ...

Como vimos nos logs, o Flyway criou automaticamente a tabela flyway_schema_history. É nessa tabela que ele registra todas as migrações aplicadas, mantendo o controle de versão do banco de dados. Vamos dar uma olhada no conteúdo dessa tabela.

Tabela criada pelo flyway para gerenciar as migrations

Podemos observar que a tabela flyway_schema_history contém colunas importantes como versão, descrição, nome do script e checksum. Cada vez que o Flyway executa uma migration, ele registra automaticamente uma nova linha nessa tabela, garantindo o controle preciso de quais alterações já foram aplicadas ao banco de dados.

No log também aparece a mensagem “No migrations found. Are your locations set up correctly?”, indicando que o Flyway não encontrou nenhuma migration para executar. Isso acontece porque, por padrão, ele procura os scripts dentro do diretório src/main/resources/db/migration. Se essa pasta não existir ou estiver vazia, o Flyway emitirá esse aviso ao iniciar a aplicação.

Pasta src/main/resources/db/migration onde o flayway busca as migrations por padrão

Caso prefira utilizar outro diretório para armazenar suas migrations, é possível alterar o caminho padrão diretamente no arquivo application.properties, usando a propriedade spring.flyway.locations.

spring.flyway.locations=filesystem:db/migration

Depois de criada a pasta de migrations, o próximo passo é adicionar o primeiro script. Mas antes disso, é importante entender a nomenclatura padrão que ele utiliza para identificar e organizar as migrações.

Nomenclatura de arquivo de migration do Flyway
  • Prefixo: sempre inicia com a letra V maiúscula, indicando que o arquivo representa uma migration versionada.
  • Versão: número que identifica a ordem de execução. Deve ser incremental e pode incluir pontos ou sublinhados — por exemplo: 1, 1.1, 1_1, 2.2. Uma prática comum em equipes grandes é usar timestamps (como 202510151021) para evitar conflitos quando vários desenvolvedores criam migrations ao mesmo tempo.
  • Separador: são dois underlines (__), obrigatórios entre a versão e a descrição.
  • Descrição: define brevemente o que o script faz, como create_table_usuarios ou add_column_email_cliente.

Com base nesse padrão de nomenclatura, podemos criar diferentes exemplos de arquivos de migration válidos:

  • V001__create_table_usuario.sql
  • V1.1__create_table_usuario.sql
  • V1_2__add_username_to_usuario.sql
  • V202510151021__create_table_produtos.sql

Agora que entendemos o padrão de nomenclatura, podemos criar nossa primeira migration no diretório src/main/resources/db/migration, com o nome V1__create_table_usuario.sql e com o seguinte conteúdo:

CREATE TABLE usuarios(
    id int not null primary key auto_increment,
    nome varchar(255) not null,
    email varchar(100) not null,
    password varchar(100) not null
);

Com o script criado, basta iniciar a aplicação. O Flyway será executado automaticamente durante o processo de inicialização do Spring Boot e aplicará a migration ao banco de dados.

2025-10-15T11:19:54.059-03:00  INFO 13844 --- [flyway] [           main] o.f.core.internal.command.DbMigrate      : Current version of schema `teste_flyway`: &lt;&lt; Empty Schema >>
2025-10-15T11:19:54.078-03:00  INFO 13844 --- [flyway] [           main] o.f.core.internal.command.DbMigrate      : Migrating schema `teste_flyway` to version "1 - create table usuario"
2025-10-15T11:19:55.008-03:00  INFO 13844 --- [flyway] [           main] o.f.core.internal.command.DbMigrate      : Successfully applied 1 migration to schema `teste_flyway`, now at version v1 (execution time 00:00.835s)

Como podemos ver no log, o Flyway detectou e aplicou nossa migration com sucesso, criando a tabela usuarios. Após a execução, ele também registrou essa alteração na tabela de controle flyway_schema_history. Vamos conferir como ela ficou.

Dados da tabela flyway_schema_history após ser executado uma migration

Agora podemos criar uma nova migration chamada V2__add_column_username.sql. Esse arquivo será responsável por adicionar uma nova coluna à tabela usuarios.

ALTER TABLE usuarios ADD COLUMN username VARCHAR(100) NOT NULL;

Após criar a nova migration, basta reiniciar a aplicação. Nos logs, o Flyway exibirá informações detalhando a detecção e execução do script V2__add_column_username.sql

2025-10-15T15:59:48.104-03:00  INFO 13592 --- [flyway] [           main] com.zaxxer.hikari.pool.HikariPool        : HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@19fec3d6
2025-10-15T15:59:48.107-03:00  INFO 13592 --- [flyway] [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2025-10-15T15:59:48.413-03:00  INFO 13592 --- [flyway] [           main] org.flywaydb.core.FlywayExecutor         : Database: jdbc:mysql://localhost/teste_flyway (MySQL 8.0)
2025-10-15T15:59:48.851-03:00  INFO 13592 --- [flyway] [           main] o.f.core.internal.command.DbValidate     : Successfully validated 2 migrations (execution time 00:00.139s)
2025-10-15T15:59:48.864-03:00  INFO 13592 --- [flyway] [           main] o.f.core.internal.command.DbMigrate      : Current version of schema `teste_flyway`: 1
2025-10-15T15:59:48.914-03:00  INFO 13592 --- [flyway] [           main] o.f.core.internal.command.DbMigrate      : Migrating schema `teste_flyway` to version "2 - add column username"
2025-10-15T15:59:49.631-03:00  INFO 13592 --- [flyway] [           main] o.f.core.internal.command.DbMigrate      : Successfully applied 1 migration to schema `teste_flyway`, now at version v2 (execution time 00:00.531s)
2025-10-15T15:59:51.143-03:00  INFO 13592 --- [flyway] [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [name: default]
2025-10-15T15:59:51.459-03:00  INFO 13592 --- [flyway] [           main] org.hibernate.Version                    : HHH000412: Hibernate ORM core version 6.6.29.Final

Como podemos observar no log, o banco estava na versão 1 antes da execução. O Flyway detectou a nova migration e aplicou apenas a alteração pendente (V2__add_column_username.sql). Agora, podemos conferir como a tabela flyway_schema_history foi atualizada com o registro dessa segunda migration.

Dados da tabela flyway_schema_history após a execução da segunda migration

É importante destacar que o Flyway realiza a validação das migrations baseado no checksum. Caso um arquivo de migration já executado no banco seja alterado posteriormente, o Flyway detectará a divergência e lançará uma exception na inicialização da aplicação, impedindo que alterações inconsistentes sejam aplicadas sem controle. Veja um exemplo de log.

2025-10-15T16:10:01.392-03:00  INFO 4116 --- [flyway] [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2025-10-15T16:10:01.462-03:00  INFO 4116 --- [flyway] [           main] org.flywaydb.core.FlywayExecutor         : Database: jdbc:mysql://localhost/teste_flyway (MySQL 8.0)
2025-10-15T16:10:01.595-03:00  WARN 4116 --- [flyway] [           main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Failed to initialize dependency 'flywayInitializer' of LoadTimeWeaverAware bean 'entityManagerFactory': Error creating bean with name 'flywayInitializer' defined in class path resource [org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration$FlywayConfiguration.class]: Validate failed: Migrations have failed validation
Migration checksum mismatch for migration version 1
-> Applied to database : 1417542612
-> Resolved locally    : -599750728
Either revert the changes to the migration, or run repair to update the schema history.

Portanto, sempre que for necessário realizar alterações após uma migration já ter sido aplicada em produção, a abordagem correta é criar uma nova migration. Isso mantém o histórico de alterações consistente, evita conflitos de versão e garante que todas as modificações sejam rastreáveis e seguras.

O Flyway é uma ferramenta extremamente útil para gerenciar o versionamento de bancos de dados, tornando a evolução do schema das aplicações muito mais organizada e segura. Com ele, é possível aplicar alterações de forma incremental, rastrear todas as mudanças através da tabela flyway_schema_history e evitar conflitos ou inconsistências, especialmente em ambientes com múltiplos desenvolvedores ou em produção.

Além disso, o Flyway oferece validação automática das migrations, garantindo que scripts antigos não sejam modificados inadvertidamente, e permitindo criar novas migrations sempre que houver necessidade de evoluir o banco. Isso promove maior confiabilidade, facilita auditorias e reduz drasticamente o risco de erros durante atualizações de schema.

Bom era isso uma pequena introdução ao Flyway. T++