npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@vlynk-studios/runway

v0.4.1

Published

Runway — SQL migration CLI for Node.js, PostgreSQL, MySQL and MariaDB

Readme

Runway

npm version License: MIT Coverage Status Build Status Node.js

Runway is a lightweight, reliable, and transactional SQL migration CLI for Node.js, supporting PostgreSQL, MySQL, and MariaDB. Designed for speed and consistency, it ensures your database schema evolves safely alongside your code.


Table of Contents


Features

  • Transactional — every migration runs inside its own transaction. If it fails, it rolls back cleanly.
  • Full Rollback Support — easily revert applied migrations with multi-step support.
  • Integrity Checks — SHA-256 checksums detect if an applied migration file is modified after the fact.
  • Integrity Validationrunway validate cross-checks every applied migration against its recorded checksum without running SQL.
  • Multi-dialect — supports PostgreSQL, MySQL 8.0+, and MariaDB out of the box.
  • Cross-platform Consistent — automatic line ending normalization (CRLF/LF) for team workflows.
  • Dry-run mode — preview what would be applied without touching the database.
  • Version range control--from and --to flags to run only a specific range of migrations.
  • Minimal footprint — only 7 production dependencies: pg, mysql2, commander, dotenv, chalk, ora, and inquirer.
  • Flexible configrunway.config.js with multi-environment support and guided initialization.
  • Pure ASCII UI — 100% terminal-friendly with standardized English ASCII icons (no emojis).

Database Support

| Database | Supported | Driver | Notes | | :------------- | :-------: | :-------: | :---------------------------------------- | | PostgreSQL | Yes | pg | Recommended for full feature support. | | MySQL | Yes | mysql2 | Supports version 8.0+ and MariaDB. | | MariaDB | Yes | mysql2 | Fully compatible. | | SQLite | No | - | Coming in a future release. |


Multi-database Workflows

Runway is designed to seamlessly manage migrations across different database dialects, enabling flexible workflows across environments or parallel support for multiple engines.

Unified Abstraction

At its core, Runway uses a unified database adapter layer (src/core/adapter/) that normalizes behaviors between drivers like pg and mysql2. For example, Runway automatically handles placeholder translation for prepared SQL statements internally, allowing it to interface smoothly with PostgreSQL ($1), MySQL (?), and MariaDB (?).

Target Specificity

A single runway.config.js or standard .env configuration locks the context into the specified engine.

  • You configure the dialect property ('postgres', 'mysql', or 'mariadb').
  • Migrations (.sql files) execute exactly as they are written, running through their respective engines.
  • Tip: If building a service intended to be deployed on both Postgres and MySQL, make sure the specific SQL syntaxes authored in the migration scripts are compliant with both ANSI SQL or maintain separate directories per dialect.

Environment Switching

You can override the engine and connection details quickly by swapping .env files using the --env flag (e.g. runway migrate --env .env.mysql vs runway migrate --env .env.postgres), making it incredibly simple to test deployments on multiple databases.


Installation

Install as a development dependency:

npm install -D @vlynk-studios/runway

Or run directly with npx:

npx @vlynk-studios/runway init

Quick Start

# 1. Initialize Runway in your project
runway init

# 2. Create your first migration
runway create create_users_table

# 3. Run pending migrations
runway migrate

# 4. Check the current state
runway status

# 5. Rollback if needed
runway rollback --steps 1

Database Connection

Runway reads your database credentials from environment variables. You can use a connection string or individual variables.

PostgreSQL Setup

Via DATABASE_URL:

DATABASE_URL=postgresql://user:password@localhost:5432/mydb

Via individual variables:

DB_HOST=localhost
DB_PORT=5432
DB_USER=myuser
DB_PASSWORD=mypassword
DB_NAME=mydb

# Optional
DB_SSL=false

MySQL & MariaDB Setup

Via DATABASE_URL:

DATABASE_URL=mysql://user:password@localhost:3306/mydb

Via individual variables:

DB_HOST=localhost
DB_PORT=3306
DB_USER=myuser
DB_PASSWORD=mypassword
DB_NAME=mydb

[!NOTE] MySQL Schemas: Since MySQL uses database names as schemas, the schema configuration field is ignored for MySQL/MariaDB connections.


Configuration

Run runway init to generate a runway.config.js in your project root:

export default {
  // Database engine: 'postgres' (default), 'mysql', or 'mariadb'
  dialect: 'postgres',

  // Directory where migration files are stored
  migrationsDir: './migrations',

  // Environment file for local development
  envFile: '.env',

  // Environment file used when NODE_ENV=test
  testEnvFile: '.env.test',

  // Optional: database connection overrides
  // (environment variables take precedence)
  database: {
    // url: 'postgresql://...',
    // host: 'localhost',
    // port: 5432,
    // user: 'myuser',
    // password: 'mypassword',
    // database: 'mydb',
    // ssl: false,
  }
};

Priority chain: ENV vars > runway.config.js > defaults

Environment Variables Reference

| Variable | Description | Default | | :--------------------- | :------------------------------------------------------- | :------------ | | DATABASE_URL | Full connection string (overrides individual DB_* vars) | — | | DB_HOST | Database host | — | | DB_PORT | Database port | 5432 / 3306 | | DB_USER | Database user | — | | DB_PASSWORD | Database password | — | | DB_NAME | Database name | — | | DB_SSL | Enable SSL (true / false) | false | | RUNWAY_DIALECT | Database dialect (postgres, mysql, mariadb) | postgres | | RUNWAY_MIGRATIONS_DIR| Path to migrations directory | ./migrations| | RUNWAY_SCHEMA | Database schema (PostgreSQL only) | public | | RUNWAY_ENV | Custom environment file path | — |


Commands

runway init

Interactive guided setup to bootstrap Runway in the current directory.

  • Detects existing DATABASE_URL or DB_* credentials in .env and skips setup prompts accordingly.
  • Collects individual credentials (host, port, user, password, name) and constructs a properly encoded DATABASE_URL.
  • Creates runway.config.js and the ./migrations/ directory.
runway init

runway create <name>

Generate a new numbered migration file pair (NNN_name.sql and NNN_name.down.sql). Spaces in <name> are converted to hyphens automatically.

runway create create_users_table
runway create "add email index"      # spaces are converted to hyphens

Output:

[Runway: success] Migration created:
[Runway: success]   + migrations/001_create_users_table.sql
[Runway: success]   + migrations/001_create_users_table.down.sql

runway migrate / up

Run all pending migrations in order. Each migration runs inside its own transaction. Runway also checks the integrity (checksum) of all previously applied migrations before running new ones.

runway migrate
runway up                           # alias

# Options
runway migrate --dry-run            # preview without touching the DB
runway migrate --from 003           # run from migration 003 (inclusive)
runway migrate --to 007             # run up to migration 007 (inclusive)
runway migrate --from 003 --to 007  # run a specific range
runway migrate --env .env.staging   # use a custom environment file

Output example:

Migrations Execution Summary:

STATUS       | MIGRATION                                     | DURATION
-------------|-----------------------------------------------|---------------
[OK]         | 001_create_users_table.sql                    | 12ms
[OK]         | 002_add_email_index.sql                       | 8ms
--------------------------------------------------
Summary:
  [x] Applied     : 2

runway rollback

Revert the last applied migration (or multiple). Runway executes the corresponding .down.sql file inside a transaction, then marks the migration as rolled back in the history table.

runway rollback                     # revert the last migration
runway rollback --steps 3           # revert the last 3 migrations
runway rollback --dry-run           # preview without touching the DB

[!WARNING] Each migration must have a corresponding .down.sql file. Runway will halt if the rollback file is missing.


runway status

Show all migrations with their current state and timestamps.

runway status

Output example:

Database Migration Status:

STATUS       | MIGRATION                                     | INFORMATION
-------------|-----------------------------------------------|------------------------------
[APPLIED]    | 001_create_users_table.sql                    | applied at 2026-04-07 10:22:01
[APPLIED]    | 002_add_email_index.sql                       | applied at 2026-04-07 10:22:01
[REVERTED]   | 003_add_roles_table.sql                       | rolled back (pending re-run)
[PENDING]    | 004_add_permissions_table.sql                 | ready to apply
--------------------------------------------------
Summary:
  [x] Applied     : 2
  [r] Rolled back : 1
  [ ] Pending     : 2  (Run 'runway up' to sync)

runway validate

Verify the SHA-256 checksum of every applied migration against its file on disk — without executing any SQL. Detects accidental or unauthorized modifications to migration files.

runway validate

If a mismatch is detected, Runway exits with a clear error showing both the expected and actual checksums.


runway baseline [version]

Mark existing migrations as applied without executing their SQL content. This is a one-time operation for onboarding existing databases that already have the schema applied.

runway baseline          # baseline all migrations
runway baseline 005      # baseline only up to migration 005

[!CAUTION] This command is intended for onboarding existing databases only. Do not use it on migrations that have not yet been applied to your database.


Migration Files

Migration files follow the naming convention NNN_description.sql (UP) and NNN_description.down.sql (DOWN). NNN is a zero-padded number that determines execution order.

migrations/
├── 001_create_users_table.sql
├── 001_create_users_table.down.sql
├── 002_add_email_index.sql
├── 002_add_email_index.down.sql
├── 003_add_roles_table.sql
└── 003_add_roles_table.down.sql

runway create <name> handles both file creation and numbering automatically.

Example UP migration (001_create_users_table.sql):

-- Migration: create_users_table (UP)
-- Created: 2026-04-07 10:00:00

CREATE TABLE users (
  id SERIAL PRIMARY KEY,
  email VARCHAR(255) NOT NULL UNIQUE,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Example DOWN migration (001_create_users_table.down.sql):

-- Migration: create_users_table (DOWN)
-- Created: 2026-04-07 10:00:00

DROP TABLE IF EXISTS users;

Status Indicators

The runway status command uses the following ASCII indicators for maximum compatibility:

| Indicator | Meaning | | :---------- | :-------------------------------------------------------------------------- | | [APPLIED] | Migration has been successfully executed in the database. | | [REVERTED]| Migration was previously applied but has since been rolled back. | | [PENDING] | Migration file exists locally but has not been applied yet. | | [ORPHAN ] | Migration is recorded as applied in the database but the file is missing. | | [OK] | General success indicator for step-level operations. | | [x] | Summary indicator for applied migrations. | | [ ] | Summary indicator for pending migrations. |


Use Cases

New Project

Starting a greenfield project with Runway:

# Bootstrap the project
runway init

# Create migrations as your schema evolves
runway create create_users_table
runway create add_email_index

# Apply to the database
runway migrate

# Verify everything is consistent
runway validate

Existing Database Onboarding

You already have a production database and want to bring it under Runway's control:

# Your migrations directory already reflects the current schema.
# Register them as applied without re-running the SQL:
runway baseline

# From this point on, new migrations are managed normally
runway create add_roles_table
runway migrate

# Audit integrity at any time
runway validate
runway status

CI/CD Integration

# In your deployment pipeline, just run:
runway migrate

# For safety, validate integrity before migrating:
runway validate && runway migrate

Architecture Overview

Runway is built around a clean separation of concerns:

bin/runway.js             → CLI entry point (Commander.js)
src/
  commands/               → One file per command
    init.js
    create.js
    migrate.js
    rollback.js
    status.js
    baseline.js
    validate.js
  core/
    runner.js             → MigrationRunner — orchestrates migrate, rollback, and validate
    log-table.js          → LogTable — manages the runway_migrations tracking table
    checksum.js           → SHA-256 checksum calculation with CRLF normalization
    adapter/
      base.js             → BaseAdapter interface
      postgres.js         → PostgresAdapter (pg driver)
      mysql.js            → MySQLAdapter (mysql2 driver)
      index.js            → getAdapter() factory function
  config.js               → Configuration resolution (ENV > config file > defaults)
  logger.js               → Chalk-based logger with ASCII output

The adapter layer abstracts all database-specific behavior. Adding a new database dialect only requires implementing BaseAdapter and registering it in getAdapter().


Testing

Runway is heavily tested with both unit and integration suites, achieving 97% coverage.

Unit Tests

Fast tests using mocks. No external dependencies required.

npm test

Integration Tests

End-to-end tests using Testcontainers. Requires Docker to be running on your machine. Covers PostgreSQL, MySQL, and MariaDB.

# Run all integration tests
npm run test:integration:all

# Run dialect-specific tests
npm run test:integration:mysql
npm run test:integration:mariadb

Coverage Report

Generate a full coverage report:

npm run test:coverage

Coverage thresholds are enforced at 80% for branches, functions, lines, and statements.


Requirements

  • Node.js >= 20.0.0
  • PostgreSQL, MySQL 8.0+, or MariaDB

Contribution

Contributions are welcome and greatly appreciated.

  1. Fork the project
  2. Create your feature branch (git checkout -b feature/my-feature)
  3. Commit your changes (git commit -m 'feat: add my feature')
  4. Push to the branch (git push origin feature/my-feature)
  5. Open a Pull Request against dev

Built with love by Vlynk Studios & Keiver-Dev