generate-changelog

Last published July 28, 2025

The generate-changelog command creates a changelog file that has a sequence of changesets which describe how to re-create the current state of the database.

Uses

The generate-changelog command is typically used when you want to capture the current state of a database, then apply those changes to any number of databases. This is typically only done when a project has an existing database, but hasn't used Liquibase before. See How to set up Liquibase with an Existing Project and Multiple Environments for more details.

Note: When using the update command to apply the changes in the changelog, Liquibase will not create a new database or schema. You must create them before applying the changelog to it.

Run the generate-changelog command

In this example, our sample database has the following content:

command-generate-changelog-initial-database

Note: The username and password attributes are not required for connections and systems which use alternate means of authentication. Also, you can specify database credentials as part of the url attribute.

* --include-tablespace only captures the tablespace if it was specified in the create table statement.

Database snapshot example

Database snapshot for jdbc:postgresql://localhost:54322/lbadmindb ----------------------------------------------------------------- Database type: PostgreSQL Database version: 16.0 (Debian 16.0-1.pgdg120+1) Database user: lbadminuser Included types: com.datical.liquibase.ext.appdba.synonym.Synonym com.datical.liquibase.ext.storedlogic.checkconstraint.CheckConstraint com.datical.liquibase.ext.storedlogic.databasepackage.DatabasePackage com.datical.liquibase.ext.storedlogic.databasepackage.DatabasePackageBody com.datical.liquibase.ext.storedlogic.function.Function com.datical.liquibase.ext.storedlogic.trigger.Trigger liquibase.structure.core.Catalog liquibase.structure.core.Column liquibase.structure.core.ForeignKey liquibase.structure.core.Index liquibase.structure.core.PrimaryKey liquibase.structure.core.Schema liquibase.structure.core.Sequence liquibase.structure.core.StoredProcedure liquibase.structure.core.Table liquibase.structure.core.UniqueConstraint liquibase.structure.core.View Catalog & Schema: lbadmindb / public com.datical.liquibase.ext.storedlogic.checkconstraint.CheckConstraint: testtable_check body: ((number > 0)) disabled: false table: testtable com.datical.liquibase.ext.storedlogic.function.Function: customfunction() body: CREATE OR REPLACE FUNCTION public.customfunction() RETURNS trigger LANGUAGE plpgsql AS $function$ BEGIN IF NEW.text <> OLD.text THEN INSERT INTO testtable (text,number,date) VALUES(new.text,new.number,new.date); END IF; RETURN NEW; END; $function$ functionName: customfunction valid: true com.datical.liquibase.ext.storedlogic.trigger.Trigger: customtrigger body: CREATE TRIGGER customtrigger BEFORE UPDATE ON public.testtable FOR EACH ROW EXECUTE FUNCTION customfunction() disabled: false tableName: testtable valid: true liquibase.structure.core.ForeignKey: fk_foreigntable deferrable: false deleteRule: importedKeyNoAction foreignKeyColumns: foreignid foreignKeyTable: foreigntable initiallyDeferred: false primaryKeyColumns: number primaryKeyTable: testtable updateRule: importedKeyNoAction liquibase.structure.core.Index: testtable_un columns: number table: testtable unique: true liquibase.structure.core.StoredProcedure: customProcedure body: CREATE OR REPLACE PROCEDURE public."customProcedure"() LANGUAGE plpgsql AS $procedure$ BEGIN insert into public.testtable (text,date) values ('first',CURRENT_DATE); END; $procedure$ type: plpgsql liquibase.structure.core.Table: foreigntable columns: foreignid nullable: false order: 2 type: int4 id autoIncrementInformation: GENERATED null AUTO INCREMENT START WITH 1 INCREMENT BY 1 nullable: false order: 1 type: int4 default_tablespace: false outgoingForeignKeys: fk_foreigntable deferrable: false deleteRule: importedKeyNoAction foreignKeyColumns: foreignid initiallyDeferred: false primaryKeyColumns: number primaryKeyTable: testtable updateRule: importedKeyNoAction testtable checkConstraints: testtable_check body: ((number > 0)) disabled: false columns: date nullable: false order: 3 type: date number autoIncrementInformation: GENERATED null AUTO INCREMENT START WITH 1 INCREMENT BY 1 nullable: false order: 2 type: int4 text defaultValue: My text value nullable: true order: 1 type: varchar default_tablespace: false indexes: testtable_un columns: number unique: true uniqueConstraints: testtable_un backingIndex: testtable_un clustered: false columns: number deferrable: false disabled: false initiallyDeferred: false validate: true liquibase.structure.core.UniqueConstraint: testtable_un backingIndex: testtable_un clustered: false columns: number deferrable: false disabled: false initiallyDeferred: false table: testtable validate: true liquibase.structure.core.View: customview columns: foreignid nullable: true order: 2 type: int4 id nullable: true order: 1 type: int4 definition: SELECT id, foreignid FROM foreigntable;

Output changelogs

The generate-changelog command generates a changelog that contains all your objects (represented as changesets) and places the file in the same directory where the command was ran.

The extension you provide determines the format of the changelog, so if you specify the filename as changelog.xml, you will get an XML formatted changelog. However, if you specify the filename as changelog.yaml, changelog.json, or changelog.sql, you will get changelogs formatted in YAML, JSON, or SQL, respectively.

Note: By default, Liquibase does not split statements for formatted SQL changelogs because splitStatements is set to false in the changelog. If the generatedSQL has multiple SQL statements, then Liquibase adds splitStatements:true to the changelog. Learn more about split statements here: sql

Default diff types

<?xml version="1.1" encoding="UTF-8" standalone="no"?> <databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd"> <changeSet author="tfernandez (generated)" id="1704821089427-1"> <createTable tableName="testtable"> <column defaultValue="My text value" name="text" type="VARCHAR" /> <column autoIncrement="true" name="number" type="INTEGER"> <constraints nullable="false" /> </column> <column name="date" type="date"> <constraints nullable="false" /> </column> </createTable> </changeSet> <changeSet author="tfernandez (generated)" id="1704821089427-2"> <pro:createFunction functionName="customfunction" path="objects/function/customfunction-bcd8b0c2.sql" relativeToChangelogFile="true" /> </changeSet> <changeSet author="tfernandez (generated)" id="1704821089427-3"> <createTable tableName="foreigntable"> <column autoIncrement="true" name="id" type="INTEGER"> <constraints nullable="false" /> </column> <column name="foreignid" type="INTEGER"> <constraints nullable="false" /> </column> </createTable> </changeSet> <changeSet author="tfernandez (generated)" id="1704821089427-4"> <pro:createTrigger disabled="false" path="objects/trigger/testtable_customtrigger-41365cf7.sql" relativeToChangelogFile="true" tableName="testtable" triggerName="customtrigger" /> </changeSet> <changeSet author="tfernandez (generated)" id="1704821089427-5"> <addUniqueConstraint columnNames="number" constraintName="testtable_un" tableName="testtable" /> </changeSet> <changeSet author="tfernandez (generated)" id="1704821089427-6"> <createView fullDefinition="false" viewName="customview">SELECT id, foreignid FROM foreigntable; </createView> </changeSet> <changeSet author="tfernandez (generated)" id="1704821089427-7"> <createProcedure path="objects/storedprocedure/customProcedure.sql" procedureName="customProcedure" relativeToChangelogFile="true" /> </changeSet> <changeSet author="tfernandez (generated)" id="1704821089427-8"> <addForeignKeyConstraint baseColumnNames="foreignid" baseTableName="foreigntable" constraintName="fk_foreigntable" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="number" referencedTableName="testtable" validate="true" /> </changeSet> </databaseChangeLog>

Specific diff types

<?xml version="1.1" encoding="UTF-8" standalone="no"?> <databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd"> <changeSet author="tfernandez (generated)" id="1704821340603-1"> <createTable tableName="testtable"> <column defaultValue="My text value" name="text" type="VARCHAR" /> <column autoIncrement="true" name="number" type="INTEGER"> <constraints nullable="false" /> </column> <column name="date" type="date"> <constraints nullable="false" /> </column> </createTable> </changeSet> <changeSet author="tfernandez (generated)" id="1704821340603-2"> <insert tableName="testtable"> <column name="text" value="one" /> <column name="number" valueNumeric="1" /> <column name="date" valueDate="2024-01-09" /> </insert> <insert tableName="testtable"> <column name="text" value="three" /> <column name="number" valueNumeric="2" /> <column name="date" valueDate="2024-01-09" /> </insert> </changeSet> <changeSet author="tfernandez (generated)" id="1704821340603-3"> <pro:createFunction functionName="customfunction" path="objects/function/customfunction-bcd8b0c2.sql" relativeToChangelogFile="true" /> </changeSet> <changeSet author="tfernandez (generated)" id="1704821340603-4"> <createTable tableName="foreigntable"> <column autoIncrement="true" name="id" type="INTEGER"> <constraints nullable="false" /> </column> <column name="foreignid" type="INTEGER"> <constraints nullable="false" /> </column> </createTable> </changeSet> <changeSet author="tfernandez (generated)" id="1704822563807-1"> <pro:addCheckConstraint constraintName="testtable_check" disabled="false" tableName="testtable"> ((number > 0)) </pro:addCheckConstraint> </changeSet> <changeSet author="tfernandez (generated)" id="1704821340603-5"> <pro:createTrigger disabled="false" path="objects/trigger/testtable_customtrigger-41365cf7.sql" relativeToChangelogFile="true" tableName="testtable" triggerName="customtrigger" /> </changeSet> <changeSet author="tfernandez (generated)" id="1704821340603-6"> <addUniqueConstraint columnNames="number" constraintName="testtable_un" tableName="testtable" /> </changeSet> <changeSet author="tfernandez (generated)" id="1704821340603-7"> <createView fullDefinition="false" viewName="customview">SELECT id, foreignid FROM foreigntable; </createView> </changeSet> <changeSet author="tfernandez (generated)" id="1704821340603-8"> <addForeignKeyConstraint baseColumnNames="foreignid" baseTableName="foreigntable" constraintName="fk_foreigntable" deferrable="false" initiallyDeferred="false" onDelete="NO ACTION" onUpdate="NO ACTION" referencedColumnNames="number" referencedTableName="testtable" validate="true" /> </changeSet> <changeSet author="tfernandez (generated)" id="1704821340603-9"> <createProcedure path="objects/storedprocedure/customProcedure.sql" procedureName="customProcedure" relativeToChangelogFile="true" /> </changeSet> </databaseChangeLog>

Parameters

Global parameters

Attribute

Definition

Requirement

--license-key=<string>

Your Liquibase Pro license key

Required

Command parameters

Attribute

Definition

Requirement

--url=<string>

The JDBC database connection URL.

Required

--author=<string>

Specifies the author for changesets in the generated changelog.

Optional

--changelog-file=<string>

Changelog file to write results

Optional

--context-filter=<string>

Specifies the context filter to generate and apply to all changesets in your changelog. Useful to set many contexts quickly. Similar to the set-contexts command. Available in Liquibase 4.24.0 and later.

Contexts are tags you can add to changesets to control which changesets will be executed in any particular migration run.

After generating changesets with contexts, to deploy specific changes according to these contexts, you must run a command that specifies a context filter. For example, update --context-filter=<xyz>.

Optional

--data-output-directory=<string>

Specifies a directory to send the loadData output to a CSV file which is generated by running the diff-changelog or generate-changelog command.

Optional

--default-catalog-name=<string>

Name of the default catalog to use for the database connection

Optional

--default-schema-name=<string>

Name of the default schema to use for the database connection. If defaultSchemaName is set, then objects do not have to be fully qualified. This means you can refer to just mytable instead of myschema.mytable.

Note: In the properties file and JAVA_OPTS only: in 4.18.0 and earlier, specify this parameter using the syntax defaultSchemaName. In 4.19.0 and later, use the syntax liquibase.command.defaultSchemaName.

Note: In Liquibase 4.12.0 and later, you can use mixed-case schema names if you set --preserve-schema-case to true. However, in Liquibase 4.12.0–4.22.0, the Liquibase validator still throws a DatabaseException error if you specify a mixed-case value of defaultSchemaName. In 4.23.0 and later, the Liquibase validator accepts any casing.

Optional

--diff-types=<string>

Specifies the types of objects to compare. Specify multiple values as a comma-separated list (without spaces). Valid values are: catalogs, checkconstraints, columns, data, databasepackage, databasepackagebody, foreignkeys, functions, indexes, primarykeys, sequences, storedprocedures, tables, triggers, uniqueconstraints, views.

If null, default types are columns, foreignkeys, indexes, primarykeys, tables, uniqueconstraints, views.

Note: The diff types checkconstraints, databasepackage, databasepackagebody, functions, storedprocedures, and triggers require a valid Liquibase Pro license key to use.

Optional

--driver=<string>

The JDBC driver class

Optional

--driver-properties-file=<string>

The JDBC driver properties file

Optional

--exclude-objects=<string>

Objects to exclude from diff

Optional

--include-catalog=<true|false>

If true, the catalog will be included in generated changesets. Default: false

Optional

--include-objects=<string>

Objects to include in diff

Optional

--include-schema=<true|false>

If true, the schema will be included in generated changesets. Default: false

Optional

--include-tablespace=<true|false>

Includes the tablespace of tables and indexes in a generated changesets if the value is true. The default value is false.

Optional *

--label-filter=<string>

Specifies the label filter to generate and apply to all changesets in your changelog. Useful to set many labels quickly. Similar to the set-labels command. Available in Liquibase 4.24.0 and later.

Labels are tags you can add to changesets to control which changeset will be executed in any migration run.

After generating changesets with labels, to deploy specific changes according to these labels, you must run a command that specifies a label filter. For example, update --label-filter=<xyz>.

Optional

--output-schemas=<string>

Lets you replace the schemas in the output changelog. This is a CSV list. The parameter size must match --schemas. If you have three items names in --schemas, you must also have three items in --output-schemas.

Example: liquibase generate-changelog --schemas=a,b,c --output-schemas=d,e,f

Optional

--overwrite-output-file=<true|false>

Determines whether generate-changelog can overwrite an existing changelog, including one specified in --changelog-file. Default: false.

Optional

--password=<string>

Password to connect to the target database.

Tip: It is a best practice to store sensitive data in a Secrets Management tool with Liquibase Pro.

Optional

--preserve-null-values=<string>

If true, column nodes will be created with null values. For example:

<insert schemaName="public" tableName="liquibase_rules">

<column name="a" value="AA" />

<column name="b" value="null" />

<column name="c" value="null" />

</insert>

If false, null values will be ignored. For example:

<insert schemaName="public" tableName="liquibase_rules">

<column name="a" value="AA" />

</insert>

Optional

--replace-if-exists-types=<string>

Specify Change Types you want to target. Liquibase sets replaceIfExists="true" on these Change Types: createFunction, createPackage, createPackageBody, createProcedure, createTrigger, and createView. Liquibase 4.26.0+. Default: <none>.

Optional

--run-on-change-types=<string>

Specify Change Types you want to target. Liquibase sets runOnChange="true" on changesets containing solely these Change Types: createFunction, createPackage, createPackageBody, createProcedure, createTrigger, and createView. Liquibase 4.26.0+. Default: <none>.

Optional

--schemas=<string>

Specifies database schemas you want to include

Optional

--skip-object-sorting=<true|false>

Liquibase 4.27.0+. Specifies how Liquibase sorts a list of objects in your database to generate a changelog. When true, Liquibase skips object sorting, so your objects are sorted according to the order returned by your database. This can be useful on databases that have a lot of packages or procedures that are linked to each other. When false, Liquibase sorts objects by dependency. This may avoid dependency errors. Default: false.

Note: If you set this parameter to true, Liquibase may create objects in the wrong order (such as a view on a table before the table itself), so you may have to manually reorganize the generated changelog file.

Optional

--username=<string>

Username to connect to the target database.

Tip: It is a best practice to store sensitive data in a Secrets Management tool with Liquibase Pro.

Optional

Database objects supported by Liquibase

You can use the following object types in Liquibase:

Object type

--diff-types

syntax

Liquibase edition

Catalog

catalogs

Liquibase Open Source

Column

columns

Liquibase Open Source

Data

data

Liquibase Open Source

Foreign key

foreignkeys

Liquibase Open Source

Index

indexes

Liquibase Open Source

NOT NULL constraint

N/A

Liquibase Open Source

Primary key

primarykeys

Liquibase Open Source

Schema

N/A

Liquibase Open Source

Sequence

sequences

Liquibase Open Source

Table

tables

Liquibase Open Source

Unique constraint

uniqueconstraints

Liquibase Open Source

View

views

Liquibase Open Source

Check constraint

checkconstraints

Liquibase Pro

Function

functions

Liquibase Pro

Package

databasepackage

Liquibase Pro

Package body

databasepackagebody

Liquibase Pro

Stored procedure

storedprocedures

Liquibase Pro

Trigger

triggers

Liquibase Pro

Liquibase Pro stored logic behavior

While Liquibase Open Source stores all changesets in a changelog, Liquibase Pro creates a directory called Objects and places the directory at the same level as your changelog.

The Objects directory contains subdirectories for each of the stored logic types:

  • package

  • packagebody

  • function

  • stored procedure

  • trigger

Note: Some database platforms may not support all of these stored logic types.

The generate-changelog command will not create the Objects directory if:

  • You don't have a valid Liquibase Pro license key.

  • Stored logic is not present in the database.

  • The target database does not support the generate-changelog command and stored logic objects.

  • The changelog file is written in formatted SQL. The Objects folder can only be created when generating XML, JSON, or YAML changelogs.

  • There is a pre-existing directory called Objects that was created outside Liquibase.

If your database contains Stored Logic objects, you may have issues attempting to run the generate-changelog command more than once, even with a new changelog name, because the stored logic files already exist in the Objects directory.

To generate a newer version of the changelog file with stored logic objects based on the current database state, you need to delete, rename, or move the Objects directory that was created by running the generate-changelog command previously. Then, you can run the generate-changelog command again.

Note: If there is a pre-existing Objects directory that is not related to Liquibase, you need to delete, rename, or move it to run the generate-changelog command.

If you want to track the history of stored logic objects, use the diff-changelog command. The diff-changelog command structures stored logic files into timestamped directories every time you run the command.