Open-source project
ridgepole/ridgepole avatar
ridgepole/ridgepole

Ridgepole: managing database schema as a Rails DSL file

Ridgepole is a tool to manage DB schema. It defines DB schema using Rails DSL, and updates DB schema according to DSL. (like Chef/Puppet)

1,122 stars138 forksRubyMIT

At a glance

What is it?
Ridgepole is an MIT-licensed Ruby tool that defines a database schema with the Rails migration DSL and updates the database to match that file, the way Chef or Puppet converge a server. It supports MySQL and PostgreSQL, does renames and diffs, and drops SQLite support.
Who is it for?
Ridgepole fits a team that wants a schema file to be the source of truth, reviewed in version control and diffed like code, rather than a chain of timestamped migrations that only one person understands. It does not fit a project on SQLite, which is unsupported, or a team that needs multi-step data migrations alongside schema changes, since the DSL describes structure rather than data movement.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 3 days ago.
What is it written in?
Mainly Ruby, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 7, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • ridgepole/ridgepole1,122 ★ · +0
Star history
Repository2026-10-192026-11-07
ridgepole/ridgepole1.1k1.1k

0 Stars in the last 19 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

Schema as a converged state, not a stack of migrations

Ridgepole is a tool to manage DB schema. It defines DB schema using the Rails DSL, and updates DB schema according to that DSL, and the README compares it directly to Chef and Puppet.

That comparison is the whole idea. In a Puppet or Chef model you declare the state you want and the tool works out the difference between the declared state and the actual state, then applies the difference. Ridgepole does the same for a database schema: the Schemafile is the desired state, and running the tool converges the database to it.

The alternative, which every Rails developer knows, is a chain of migrations. Each migration is a timestamped file that performs one change, and the database carries a record of which ones have run. The problems with that model are well known: the chain is order dependent, two branches that both touch a table have to be reconciled by hand, and after a year the only reliable description of the schema is the database itself.

Ridgepole replaces the chain with a single declarative file. The DSL is the same one Rails migrations use, so the syntax is not new, and the file is small enough to read in one sitting.

The Ruby implementation, the MIT licence and the fact that the project has no GitHub releases but keeps pushing to main are worth noting. The last push was on 2026-10-15, and the release notes in the README are a long changelog of Rails version support, which is the main axis of change in this project.

Export, edit, diff, apply

The usage walkthrough in the README is the clearest way to understand the workflow, and it is a four-step loop.

First you export the current schema from a live database into a Schemafile. The connection can be given in four different ways, which is unusually accommodating. You can point at a config file, or pass an inline hash such as `ridgepole -c '{adapter: mysql2, database: blog}' ...`, or a connection URL such as `ridgepole -c 'mysql2://root:[email protected]:3306/blog' ...`, or an environment variable reference with `export DB_URL='mysql2://...'; ridgepole -c env:DB_URL ...`.

The export command and its result:

sh
$ ridgepole -c config.yml --export -o Schemafile
Export Schema to `Schemafile`

The file itself is plain Rails DSL, a `create_table` block per table with a column type on each line.

Then you edit the Schemafile, and version control shows you the change as a diff, which is the part that makes this pleasant in a review. A reviewer sees that a text column was added after the existing text column, in the same format as any other code change.

Then you apply, and you can dry-run first:

sh
$ ridgepole -c config.yml --apply --dry-run
Apply `Schemafile` (dry-run)
add_column("articles", "author", :text, {:after=>"text"})

# ALTER TABLE `articles` ADD `author` text AFTER `text`

The dry-run prints the ActiveRecord operation and the SQL it corresponds to, and the real run prints the same operation with the time it took. The SQL being visible is what makes this usable in a deployment pipeline where you want to see what will run before it runs.

Renames, and why they need their own syntax

A declarative schema tool runs into the problem that a diff of two states does not know why they differ. If a column changed from `text` to `string`, was it renamed, or was one dropped and another added?

Ridgepole solves this with a `renamed_from` option on the column and on the table:

ruby
create_table "articles", force: :cascade do |t|
  t.string   "title"
  t.text     "desc", renamed_from: "text"
  t.text     "author"
  t.datetime "created_at"
  t.datetime "updated_at"
end

create_table "user_comments", force: :cascade, renamed_from: "comments" do |t|
  t.string   "commenter"
  t.text     "body"
  t.integer  "article_id"
  t.datetime "created_at"
  t.datetime "updated_at"
end

The effect is a rename rather than a drop and an add, which preserves the data and the foreign keys pointing at it. That is the whole reason this option exists, and it is what a plain diff-based tool cannot infer.

There is a caveat the README documents for the table-level case. When you use `renamed_from` on a table, Ridgepole will only perform the rename operation, and all other changes to that table are not applied. That is a deliberate restriction, since a rename that also adds columns is ambiguous about what the tool should do, and it is the kind of thing that catches people out if they expect a single pass to do everything.

The flags that show how much control there is

The help output is long, and reading it tells you more about the tool's real behaviour than the prose does.

The core verbs are `--export` with `--output` to write a Schemafile, `--apply` to converge the database, and `--diff DSL1 DSL2` to compare two schema definitions without touching a database. There is a `--with-apply` flag, so a diff can be shown and applied in the same run, and `--merge` for combining schema files.

The table options are where the MySQL and PostgreSQL differences surface. There is `--table-options`, `--table-hash-options`, `--alter-extra`, `--index-removed-drop-column`, `--create-table-with-index`, `--mysql-change-table-options`, `--mysql-change-table-comment`, `--pg-change-table-comment`, `--ignore-table-comment` and `--skip-column-comment-change`. Table selection is `--tables` and `--ignore-tables REGEX_LIST`.

The column type defaults are configurable too, with `--default-bool-limit`, `--default-int-limit`, `--default-bigint-limit`, `--default-float-limit`, `--default-string-limit`, `--default-text-limit` and `--default-binary-limit`, plus `--default-bool-limit`-style adjustments for the different engines.

Two flags have behavioural consequences worth planning for. `--drop-table` is needed to actually drop tables, because DROP TABLE is skipped by default in v1.0 and later versions, and `--drop-table-only` does the opposite, restricting the run to just the drops. And `--allow-pk-change` permits changing a primary key, which is the kind of operation that is destructive enough to be worth opting into explicitly.

There are also `--pre-query` and `--post-query` for running statements around the migration, `--external-script` for hooks, `--bulk-change` for a different change strategy, and `--check-relation-type DEF_PK` for how foreign key relations are checked.

The Rails 8.1 change is flagged separately. The order of columns when exporting has changed, and if you do not want to sort the columns you can use the `--disable-sort-columns` option.

Databases, versions and the compatibility history

The support matrix is the part of the README that tells you where the project stands.

MySQL and PostgreSQL are the supported databases, and SQLite is not supported at all. The repository's compose file confirms the test matrix: MySQL 5.7 on port 13316, MySQL 8.0 on port 13318, and PostgreSQL 14 on port 15442, each with a simple password, which is the standard arrangement for running an application's test suite against several database versions.

The version history in the README tracks Rails support, and it shows the project keeping up with each release. Ridgepole 3.0.0 added Rails 8.0 support, 3.1.0 added Rails 8.1, and 3.2.0 switched from `diffy` to `udiff`. Earlier entries show 2.0.0 adding Trilogy support and Rails 7.1, and dropping ActiveRecord 6.0. ActiveRecord 5.x support was dropped in v1.2.0, and partitioning is no longer supported as of v1.1.0.

The ActiveRecord 7.x notes are the most practically useful, because they describe a real compatibility trap. ActiveRecord 7.x has some incompatible changes, and if you get unintended differences in `datetime` columns you should consider changing `precision`, either adding `precision: nil` for columns that previously had no precision specified or removing `precision: 6` from columns that had it set explicitly. The README points at the issue threads for both.

The ActiveRecord 6.1 note is similar in shape, since the ActiveRecord dump format changed, so there is a difference between the 5.x and 6.0 formats, and if you use 6.1 you need to modify the Schemafile format.

The Rails 7.0 note is short, stating that the output of the dumper is different from Rails 6, which matters if you are comparing a Schemafile exported under one version with one exported under another.

The repository and the related Go tool

The repository is a conventional Ruby gem layout. There is `lib/` for the code, `spec/` for the specs with an `.rspec` file and a `.simplecov` for coverage, `bin/` for the executable, `ridgepole.gemspec` for the gem metadata, a `Rakefile`, an `Appraisals` file and a `gemfiles/` directory, which is how the project tests against multiple dependency versions, and a `compose.yaml` for the database matrix. The linting is RuboCop with a `.rubocop.yml`, and there is a codecov configuration plus a badge in the README.

The `compose.yaml` uses images from mirror.gcr.io rather than Docker Hub, and the MySQL 5.7 service pins `platform: linux/amd64`, which is the workaround for the fact that the old image has no arm64 build. If you are testing on an Apple Silicon machine, that pin is what makes the 5.7 case work at all.

The README also points at a sibling project. The author notes they are also developing similar declarative schema tools, as a single Go binary with plain SQL as the schema definition, and names pistachio, which is for PostgreSQL. That is a useful pointer for anyone who finds the Ruby dependency chain heavy, since the same convergence model does not require Ruby.

Installation is a Gemfile line and a bundle:

ruby
gem 'ridgepole'
sh
$ bundle install

or `gem install ridgepole` if you are not in a Rails project, and the executable is the `ridgepole` command.

Editorial conclusion

Ridgepole fits a team that wants a schema file to be the source of truth, reviewed in version control and diffed like code, rather than a chain of timestamped migrations that only one person understands. It does not fit a project on SQLite, which is unsupported, or a team that needs multi-step data migrations alongside schema changes, since the DSL describes structure rather than data movement. Before adopting it, export the current schema with `ridgepole -c config.yml --export -o Schemafile` and read the diff, and pass `--disable-sort-columns` if you do not want the Rails 8.1 column reordering.

Frequently asked questions

What is Ridgepole?

It is a Ruby tool to manage database schema. It defines the schema using the Rails DSL and updates the database to match that DSL, in a way the README compares to how Chef or Puppet converge a server. The project is MIT licensed.

How do I export a schema with Ridgepole?

Run `ridgepole -c config.yml --export -o Schemafile`. The connection can be a config file, an inline hash, a connection URL, or an environment variable reference such as `ridgepole -c env:DB_URL ...`.

How does Ridgepole handle renamed columns and tables?

With a `renamed_from` option on the column or the table, which makes Ridgepole perform a rename rather than a drop and an add, preserving data and foreign keys. When used on a table, only the rename operation is performed and other changes to that table are not applied.

Which databases does Ridgepole support?

MySQL and PostgreSQL, tested against MySQL 5.7, MySQL 8.0 and PostgreSQL 14 in the repository's compose file. SQLite is not supported.

Which Rails and ActiveRecord versions does Ridgepole support?

Recent releases track recent Rails: 3.0.0 added Rails 8.0 support, 3.1.0 added Rails 8.1, and 2.0.0 added Rails 7.1 and Trilogy. Older support was dropped along the way, including ActiveRecord 5.x in v1.2.0 and ActiveRecord 6.0 in 2.0.0.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. ridgepole/ridgepole on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/ridgepole-ridgepole.svg)](https://hysenlabs.com/projects/ridgepole-ridgepole)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/ridgepole-ridgepole.svg)](https://hysenlabs.com/projects/ridgepole-ridgepole)

Was this useful?