Skip to main content
Version: 0.7 (Latest)

CLI Reference

Complete reference for every MigratorXpress command-line argument. This page describes MigratorXpress v0.7.3.

Basic Usage​

./MigratorXpress [OPTIONS]

MigratorXpress runs as a single command. On Windows, use .\MigratorXpress.exe.

Every migration command needs:

  • --auth -- the credentials file
  • --source_db_auth_id
  • --target_db_auth_id
  • --migration_db_auth_id
  • exactly one of --task_list (new run) or --resume RUN_ID (resume a run)

The source and target database names are taken from the auth entries: --source_db_name and --target_db_name are optional since 0.7.2 (see Database names).

A missing required argument is rejected by the argument parser before anything else runs (exit code 2). The only exception is --upgrade_migdb, which needs --auth and --migration_db_auth_id only (see Upgrading the tracking database).

Authentication​

OptionTypeRequiredDescription
-a, --auth PATHPathYesPath to the JSON credentials file

The credentials file contains connection details for every database involved in the migration. Each entry has a unique ID that you reference with other flags. See Credentials File Format below.

Source Database​

OptionTypeRequiredDescription
--source_db_auth_id IDStringYesSource database identifier in the credentials file
--source_db_name NAMEStringNoDeprecated and ignored. The source database is the one of the source auth entry. See Database names
--source_schema_name PATTERNStringNoSource schema name, SQL LIKE pattern(s), or comma-separated list. All schemas if omitted

Schema selection​

The --source_schema_name flag supports four modes:

Single schema:

--source_schema_name SALES

SQL LIKE patterns (any value containing %):

# All schemas starting with "app_"
--source_schema_name "app_%"

# Multiple patterns
--source_schema_name "APP_%, TENANT_%"

Exact comma-separated list:

# Multiple specific schemas without wildcards
--source_schema_name "tpch_1, tpch_2, tpch_3"

Omitted: MigratorXpress discovers and migrates all user schemas in the source database.

Target schema naming​

How target schemas are named depends on --target_schema_name:

Source schema selection--target_schema_name omitted--target_schema_name NAME given
Single schemaTarget schema = source schema nameTarget schema = NAME
Pattern, list, or omittedEach source schema keeps its own name on the targetAll matched source schemas are loaded into the single target schema NAME

--target_schema_name is a plain name, never a pattern. To keep one target schema per source schema in a multi-schema run, omit it. Target schemas are created automatically if they do not exist.

Target Database​

OptionTypeRequiredDescription
--target_db_auth_id IDStringYesTarget database identifier in the credentials file
--target_db_name NAMEStringNoTarget database name. Defaults to the database of the target auth entry; when given, it must match it. See Database names
--target_schema_name NAMEStringNoTarget schema name. See Target schema naming

Supported targets: SQL Server and PostgreSQL. A PostgreSQL target can be loaded from SQL Server, Oracle and PostgreSQL sources (not from Netezza). See the compatibility matrix.

With a PostgreSQL target:

  • the target schema, table and column names are created in lower case (a source table Sales.Orders lands in sales.orders), and they are recorded in lower case in the tracking database;
  • copy_fk (and therefore --task_list all) is not supported: the run stops at startup with exit code 10. Use an explicit task list such as translate create transfer diff copy_pk copy_ak;
  • --cci_threshold and --aci_threshold are ignored (logged as such);
  • columns that cannot be migrated -- SQL Server GEOGRAPHY / GEOMETRY and PostgreSQL ARRAY / user-defined types -- make translate fail for their table, which is then not created.

Database names​

MigratorXpress takes the database names from the auth file:

  • Source: the database is always the one of the source auth entry (info.database, or the Database of a connection string). --source_db_name is deprecated and ignored; passing it logs a warning.
  • Target: the database defaults to the one of the target auth entry. When --target_db_name is given, it must match that entry (case-insensitively for SQL Server, exactly for PostgreSQL), otherwise the run stops with TARGET_DB_NAME_MISMATCH (exit code 20) before connecting to any database.

Omit both options unless you have a reason to pass them.

Migration Tracking Database​

OptionTypeRequiredDescription
--migration_db_auth_id IDStringYesIdentifier of the migration tracking database in the credentials file
--migration_db_mode MODEStringNopreserve (default), truncate, or drop. See below
--upgrade_migdbFlagNoUpgrade the tracking database to the 0.7 schema, then exit

The tracking database can be SQL Server (ds_type: "mssql") or PostgreSQL (ds_type: "postgres"). The backend is detected from the ds_type of the referenced auth entry. MigratorXpress creates its tracking tables automatically on first use.

--migration_db_modeBehavior at startup
preserve (default)Keep all tracking data. Required to --resume later
truncateDelete the content of all tracking tables (every run), keep the tables
dropDrop and recreate all tracking tables

Upgrading the tracking database​

Since 0.7.0 the catalog tables (sources, sourcecolumns, sourceconstraints, targets, targetcolumns) include run_id in their primary keys, so each run keeps its own metadata snapshot. A tracking database created by 0.6.x must be upgraded in place. Two options:

  • Automatic: on the first 0.7 run against an old tracking database, MigratorXpress detects the old schema and upgrades it before continuing.
  • Manual: run the upgrade on its own. Only --auth and --migration_db_auth_id are needed:
./MigratorXpress --auth ./credentials.json \
--migration_db_auth_id ms_mig_log \
--upgrade_migdb

The upgrade is idempotent (a second run does nothing) and resumable (an interrupted upgrade completes on the next attempt). Existing catalog rows are backfilled with run_id = 'legacy'. Back up the tracking database first. On large SQL Server tracking databases the slowest step is the rebuild of the clustered primary keys.

Task Control​

OptionTypeDescription
--task_list TASKS...String(s)Space-separated list of tasks for a new run
-r, --resume RUN_IDStringResume an existing run (see Resume Operations)

Give exactly one of --task_list or --resume.

Available tasks: translate, create, transfer, diff, copy_pk, copy_ak, copy_fk, or all (shortcut for all seven).

Execution order is fixed. Whatever order you type, tasks are re-sorted into the canonical order translate → create → transfer → diff → copy_pk → copy_ak → copy_fk (the sorted list is logged as sorted task list). Duplicates are rejected.

Only some combinations are accepted. The task set must be one of the sequences below, otherwise the run stops with incorrect task sequence (exit code 20):

TasksAccepted combinations
1 taskany single task
2 taskstranslate create, create transfer, transfer diff, transfer copy_pk, diff copy_pk, copy_pk copy_ak, copy_pk copy_fk, copy_ak copy_fk
3 taskstranslate create transfer, translate create copy_pk, create transfer diff, transfer diff copy_pk, transfer copy_pk copy_ak, diff copy_pk copy_ak, transfer copy_pk copy_fk, diff copy_pk copy_fk, copy_pk copy_ak copy_fk
4 taskstranslate create transfer diff, translate create transfer copy_pk, translate create transfer copy_ak, create transfer diff copy_pk, create transfer copy_pk copy_ak, transfer diff copy_pk copy_ak, create transfer copy_pk copy_fk, transfer diff copy_pk copy_fk, diff copy_pk copy_ak copy_fk
5 taskstranslate create transfer diff copy_pk, translate create transfer copy_pk copy_ak, translate create transfer copy_pk copy_fk, translate create transfer copy_ak copy_fk, create transfer diff copy_pk copy_ak, create transfer diff copy_pk copy_fk, create transfer diff copy_ak copy_fk
6 taskstranslate create transfer diff copy_pk copy_ak, translate create transfer diff copy_pk copy_fk, translate create transfer copy_pk copy_ak copy_fk, create transfer diff copy_pk copy_ak copy_fk
7 tasksall (or the seven tasks listed explicitly)

For example translate transfer (skipping create) is rejected.

# Schema, data and validation
--task_list translate create transfer diff

# Schema only
--task_list translate create

# Data only (tables already exist)
--task_list transfer

# Constraints only (after data is loaded)
--task_list copy_pk copy_ak copy_fk

# Everything
--task_list all

A missing --task_list/--resume, both given together, a duplicated or unknown task, or an invalid task sequence is logged (CRITICAL) and stops the run with exit code 20 (VALIDATION_ERROR) before any database is opened. See Exit Codes.

Constraint copying limitations

copy_pk and copy_ak are supported for Oracle, PostgreSQL and SQL Server sources, with a SQL Server or PostgreSQL target. copy_fk is supported for the same sources with a SQL Server target only. A Netezza source with a copy_* task, or copy_fk with a PostgreSQL target, is rejected at startup with exit code 10. Foreign keys that reference a table in another schema are logged as a warning and not copied. For the unsupported paths, create the constraints manually on the target database.

Resume Operations​

OptionTypeDescription
-r RUN_ID, --resume RUN_IDStringResume a previous run using its run ID (required value)

When a migration is interrupted or some tables failed, use --resume with the run ID to finish it. MigratorXpress replays the steps of that run and only processes the table jobs that are not yet DONE in the tracking database.

On resume:

  • --task_list must not be given, and --source_schema_name / --target_schema_name are not needed: the jobs (tables, schemas, tasks) are read from the tracking database.
  • The other required arguments (--auth, --source_db_auth_id, --target_db_auth_id, --migration_db_auth_id) are still mandatory.
  • Performance and logging options (--n_jobs, --fasttransfer_p, --log_dir, ...) are taken from the resume command line.
  • Keep the default --migration_db_mode preserve: truncate or drop would delete the run you are trying to resume.
  • With a PostgreSQL target, do not resume a run started with a version older than 0.7.2 (target names were not lower-cased then): start a new run.

A run that ends with failed tables logs the --resume <run_id> command to use and exits with code 40 or 41.

./MigratorXpress --auth ./credentials.json \
--source_db_auth_id mssql_source \
--target_db_auth_id mssql_target \
--migration_db_auth_id ms_mig_log \
--resume 20260203-cf5be0ac-159f-4dad-861e-8b2b6f3868d7

The run ID has the format YYYYMMDD-<uuid4>. It appears in the log file name and in the console output (run_id : ...), and is stored in the tracking database (sourcetargetloads.run_id, eventlog.eventrunid).

Run Tagging​

OptionTypeDescription
--project NAMEStringOptional project tag attached to every row this run writes in the migration tracking DB

A user-supplied --project tag groups runs that belong to the same engagement. The tag is stored alongside run_id on sourcetargetloads, eventlog, and sourcetargetdiff, so all runs for a given project can be retrieved with a single SQL filter.

./MigratorXpress --auth ./credentials.json \
--source_db_auth_id oracle_prod \
--target_db_auth_id mssql_target \
--migration_db_auth_id ms_mig_log \
--source_schema_name SALES \
--task_list all \
--project bob_bods_oracle

Then, to find every run tagged with that project:

SELECT DISTINCT eventrunid
FROM eventlog
WHERE project = 'bob_bods_oracle';

Validation: 1–64 characters, letters, digits, underscore, or hyphen only (e.g. bob_bods_oracle, cust-2026-q2). Invalid values are rejected at CLI parse time (exit code 2), before any database write.

Optional: Runs without --project store NULL. Older tracking databases get the project columns added automatically on startup.

Immutable per run_id

On --resume, any --project value on the command line is ignored with a warning, and the original run's tag is inherited from the migration DB. This keeps every row for a given run_id tagged consistently, even across multiple resumes.

FastTransfer​

OptionTypeDefaultDescription
--fasttransfer_dir_path PATHPathAuto-detectedDirectory containing the FastTransfer binary. Optional
-p, --fasttransfer_p INTInteger1Parallel streams per large table (Ctid/Rowid/NZDataSlice)
--ft_large_table_th INTInteger250,000,000Row count threshold for parallel transfer methods

MigratorXpress delegates all data movement to FastTransfer. FastTransfer >= 0.15.0 is required; the version is checked at startup and an error is logged if it is older.

If --fasttransfer_dir_path is omitted, MigratorXpress looks for a bundled FastTransfer in the engine/ subdirectory next to the MigratorXpress binary. Distributions that ship FastTransfer in engine/ need no flag.

# Explicit path
--fasttransfer_dir_path ./FastTransfer_linux-x64_v0.15.0/

# Or omit to use the bundled engine/ directory

Parallel transfer methods​

Tables whose estimated row count is greater than or equal to --ft_large_table_th, with --fasttransfer_p > 1, use a database-specific parallel method:

Source DatabaseMethodDescription
PostgreSQLCtidSplits by physical tuple ID
OracleRowidSplits by physical ROWID (requires SELECT_CATALOG_ROLE)
NetezzaNZDataSliceSplits by internal data slice distribution
SQL ServerNoneNo intra-table parallelism; parallelism via --n_jobs only

Below the threshold, or with --fasttransfer_p 1, each table is transferred as a single stream.

Performance​

OptionTypeDefaultDescription
--n_jobs INTInteger1Number of tables to process in parallel
--compute_nbrows BOOLBooleanfalseUse COUNT(*) for exact row counts instead of database estimates (true/false)
--without_xidFlagfalseDisable transaction ID / ROWID watermark usage for Netezza and Oracle

--n_jobs controls table-level parallelism (how many tables transfer simultaneously). Combined with --fasttransfer_p, this gives dual-level parallelism:

# 4 tables at once, each large table split into 2 parallel streams
--n_jobs 4 --fasttransfer_p 2

Table Filtering​

OptionTypeDefaultDescription
-i, --include_tables PATTERNString% (all)Include only tables matching SQL LIKE patterns (comma-separated)
-e, --exclude_tables PATTERNStringNoneExclude tables matching SQL LIKE patterns (comma-separated)
-min, --min_rows NROWSInteger-1 (disabled)Exclude tables with strictly fewer rows than this value
-max, --max_rows NROWSInteger-1 (disabled)Exclude tables with row count >= this value

Exclude patterns are applied after include patterns.

# Include only tables starting with "fact_" or "dim_"
--include_tables "fact_%,dim_%"

# Spaces after commas are trimmed automatically
--include_tables "fact_%, dim_%"

# Exclude temporary and test tables
--exclude_tables "tmp_%,test_%"

# Combine filters
--include_tables "%" --exclude_tables "tmp_%,log_%" --min_rows 100 --max_rows 10000000
Shell quoting

Quote the entire comma-separated string as one argument. Do not quote each pattern separately:

# CORRECT
--include_tables "fact_%,dim_%"

# WRONG — shell interprets as multiple arguments
--include_tables 'fact_%','dim_%'

Migration Options​

OptionTypeDefaultDescription
--drop_tables_if_exists [BOOL]BooleanfalseDrop existing target tables in the create task before recreating them
--load_mode MODEStringtruncatetruncate: clear target tables before loading. append: add rows without clearing
--basic_diffFlagfalsediff compares row and column counts only (skips per-column statistics)
-f, --forceFlagfalseDelete existing tracking rows for the source database/schema before the run

--drop_tables_if_exists​

Without this flag, the create task keeps tables that already exist on the target (it only creates missing ones); transfer then loads into them according to --load_mode.

With the flag enabled, existing target tables (and the foreign keys that reference them) are dropped and recreated. Enabling it also forces --without_xid. A table whose translate step failed is neither dropped nor created.

ValueEffect
true, yes, 1, or the bare flag --drop_tables_if_existsEnabled
false, no, 0, or the flag omittedDisabled
Any other valueRejected by the argument parser (exit code 2)
Changed in 0.7.2

Up to 0.7.1, any value enabled the option, including false. Since 0.7.2, --drop_tables_if_exists false keeps the existing tables.

Diff​

The diff task compares source and target row counts and column counts. When both match and the table is not empty, it also compares per-column statistics: minimum, maximum, distinct count, number of missing values and, for numeric columns, the mean (with a numeric tolerance). --basic_diff restricts the comparison to row and column counts. Results are stored in sourcetargetdiff (and the v_sourcetargetdiff view).

Columns are matched by name, case-insensitively when the exact name is absent (a PostgreSQL target lower-cases column names). Differences found by diff are reported but do not fail the table, and do not change the exit code.

SQL Server Target Options​

These options apply only when the target database is SQL Server. With a PostgreSQL target, --cci_threshold and --aci_threshold are ignored, and copy_fk (the only task that uses --fk_mode) is not supported.

OptionTypeDefaultDescription
--cci_threshold INTInteger1,000,000Create a Clustered Columnstore Index for tables above this row count
--aci_threshold INTInteger100,000,000Use archive compression (COLUMNSTORE_ARCHIVE) above this row count
--fk_mode MODEStringdisabledForeign key enforcement for copy_fk: disabled, untrusted, or trusted. Any other value stops the run with exit code 20

Columnstore behavior:

  • Tables >= cci_threshold but < aci_threshold: Standard Clustered Columnstore Index
  • Tables >= aci_threshold: CCI with DATA_COMPRESSION = COLUMNSTORE_ARCHIVE
  • Tables < cci_threshold: Standard rowstore

Foreign key modes:

  • disabled (default): FK constraints created WITH NOCHECK and then disabled. Fastest for loading.
  • untrusted: FK constraints created WITH NOCHECK but left enabled. Enforced for new data only.
  • trusted: Standard FK constraints with full validation of existing data.

Oracle Source Options​

These options apply only when the source database is Oracle.

OptionTypeDefaultDescription
--forced_int_id_prefixes S...String(s)NoneSpace-separated column name prefixes to force as integer type
--forced_int_id_suffixes S...String(s)NoneSpace-separated column name suffixes to force as integer type
--profiling_sample_pc NUMBERInteger10Percentage of rows to sample for Oracle DATE/NUMBER profiling
--min_sample_pc_profile NUMBERInteger100,000Row count threshold below which tables are profiled in full (no sampling)
--p_query NUMBERInteger6Inner level of query parallelism for Oracle profiling queries (PARALLEL hint degree)

Oracle stores many integer values in NUMBER columns without precision. MigratorXpress profiles DATE and NUMBER columns to select optimal target types. Use --forced_int_id_prefixes and --forced_int_id_suffixes to skip profiling for known ID columns:

# Space-separated, case-insensitive matching
--forced_int_id_prefixes ID_ PK_ KEY_ \
--forced_int_id_suffixes _ID _KEY _PK

Sampling behavior:

  • Tables >= min_sample_pc_profile rows: sampled at profiling_sample_pc% using Oracle SAMPLE(n)
  • Tables < min_sample_pc_profile rows: profiled in full
  • Set --profiling_sample_pc 100 to disable sampling

Logging Options​

OptionTypeDefaultDescription
--log_level LEVELStringINFOLog verbosity: DEBUG, INFO, WARNING, ERROR, CRITICAL (case-insensitive)
--log_dir PATHPathCurrent directoryDirectory for log files (created if missing)
--no_bannerFlagfalseSuppress the startup banner
--no_progressFlagfalseDisable the progress display
--quiet_ftFlagfalseSuppress FastTransfer subprocess output from console (still logged to file)

See Logging and Monitoring for details on log format and database logging.

License Management​

OptionTypeDescription
--license TEXTStringLicense text
--license_file PATHPathPath to a license file

License lookup order (the first source found is used):

  1. MIGRATORXPRESS_LICENSE environment variable
  2. --license command-line argument
  3. --license_file command-line argument
  4. Default license file: ~/.migratorxpress/license.lic (Linux/macOS) or %APPDATA%\MigratorXpress\license.lic (Windows)
  5. license.lic in the current working directory
  6. Trial mode: 30 days from the build date of the binary

A license that is found but invalid or expired stops the run (exit code 13); MigratorXpress does not fall back to trial mode in that case. Trial mode provides all features without restrictions.

Exit Codes​

CodeNameMeaning
0SUCCESSEvery table of the run succeeded every task. Differences found by diff do not fail a table
1GENERAL_ERROROther error: migration error, invalid --migration_db_mode, unexpected exception
2--Command-line parsing error: missing required argument, invalid --load_mode/--log_level/--project, invalid boolean value (--compute_nbrows, --drop_tables_if_exists), non-integer value
10CONFIG_ERRORConfiguration error detected at startup, before any connection: invalid auth entry (unknown ds_type, auth_mode not supported for the database type, missing or unexpected info key, unparsable connection string), auth ID not found in the credentials file, odbc used for the target or ODBC prerequisites missing, target or tracking database type not supported, unsupported source/target pair (e.g. Netezza to PostgreSQL), copy_* task with a Netezza source, copy_fk with a PostgreSQL target
12CONNECTION_ERRORConnection to the source, target, or tracking database failed
13LICENSE_ERRORLicense invalid, expired, not yet active, or trial expired
20VALIDATION_ERRORInvalid task options (--task_list/--resume missing or both given, duplicated or unknown task, invalid task sequence), invalid --fk_mode, --target_db_name not matching the target auth entry, database name that cannot be determined
40PARTIAL_FAILURESome tables failed a task. Retry them with --resume <run_id>
41ALL_JOBS_FAILEDEvery table of the run failed a task

When tables failed, the RUN SUMMARY: n/m tables succeeded block at the end of the log lists them, and the log ends with the --resume <run_id> command that retries them.

For schedulers: codes 10 to 29 need a fix before the run is started again; codes 40 and 41 can be retried with --resume.

Changed in 0.7.2 and 0.7.3

Up to 0.7.1, a run with failed tables and an invalid task list both exited with code 0, and invalid auth entries failed later with code 1 or 12. Scripts and schedulers that relied on those codes must be updated.

Utility​

OptionDescription
--versionDisplay MigratorXpress version and exit
-h, --helpShow help message and exit

Database Parameters​

Connection parameters by database type​

classic entries:

ParameterOraclePostgreSQLSQL ServerNetezza
ds_typeoraclepostgresmssqlnetezza
auth_modeclassicclassicclassicclassic
usernameRequiredRequiredRequiredRequired
passwordRequiredRequiredRequiredRequired
serverRequiredRequiredRequiredRequired
portRequired (usually 1521)Required (usually 5432)Required (usually 1433)Required (usually 5480)
databaseService nameDatabase nameDatabase nameDatabase name
lib_dirOptional, thick mode only------

Authentication modes by database type​

ds_typeclassicconnection_stringtrustedodbc
oracle✅❌❌❌
postgres✅✅❌❌
mssql✅✅✅✅ source and tracking database only
netezza✅❌❌❌

See Authentication modes for the info keys of each mode.

Credentials File Format​

The credentials file is a JSON object where each key is an identifier you reference on the command line. Each entry has:

  • ds_type: oracle, postgres, mssql, or netezza
  • auth_mode: classic, connection_string, trusted or odbc (see Authentication modes by database type)
  • info: for classic, username, password, server, port (a JSON integer between 1 and 65535), database, and for Oracle optionally lib_dir

For classic, all info fields except lib_dir are required and must be non-empty. No other key is accepted, in the entry or in info. Every entry referenced on the command line is validated at startup, before any connection is opened: an invalid entry stops the run with exit code 10 and a message naming the entry and the key (never the value). Values are used as written: there is no environment variable substitution, so protect the file with file-system permissions.

{
"oracle_prod": {
"ds_type": "oracle",
"auth_mode": "classic",
"info": {
"username": "migrator",
"password": "********",
"server": "oracle-host.example.com",
"port": 1521,
"database": "ORCLPDB1"
}
},
"mssql_target": {
"ds_type": "mssql",
"auth_mode": "classic",
"info": {
"username": "migrator",
"password": "********",
"server": "sql-host.example.com",
"port": 1433,
"database": "target_db"
}
},
"ms_mig_log": {
"ds_type": "mssql",
"auth_mode": "classic",
"info": {
"username": "migrator",
"password": "********",
"server": "sql-host.example.com",
"port": 1433,
"database": "migration_log"
}
},
"netezza_source": {
"ds_type": "netezza",
"auth_mode": "classic",
"info": {
"username": "migrator",
"password": "********",
"server": "nz-host.example.com",
"port": 5480,
"database": "PROD_DB"
}
}
}

Oracle Thick Mode​

For Oracle 11.2 and earlier, set lib_dir to the Oracle Instant Client directory. Later versions use thin mode by default (omit lib_dir).

{
"oracle_thick": {
"ds_type": "oracle",
"auth_mode": "classic",
"info": {
"username": "user",
"password": "pass",
"server": "host",
"port": 1521,
"database": "LEGACY",
"lib_dir": "/opt/oracle/instantclient_19_8"
}
}
}

Supported Database Types​

Databaseds_type valueUsual PortAs SourceAs TargetAs Migration DB
Oracleoracle1521YesNoNo
PostgreSQLpostgres5432YesYes (from Oracle, PostgreSQL, SQL Server)Yes
SQL Servermssql1433YesYesYes
Netezzanetezza5480Yes (to SQL Server only)NoNo

See Also​

Copyright © 2026 Architecture & Performance.