# rom-rb: Ruby object mapping for SQL and NoSQL without constraining database access

> rom-rb is a data mapping and persistence toolkit for Ruby that aims to give full access to the underlying database while keeping domain objects separate from storage mechanics. Three components handle adapters, changesets, and repository abstraction, each housed in its own subdirectory.

**hanakai-rb/rom** — Data mapping and persistence toolkit for Ruby

- Repository: https://github.com/hanakai-rb/rom
- Website: https://rom-rb.org
- Stars: 2,107 · Forks: 170
- Language: Ruby
- License: MIT
- Published: 2026-10-11 · Updated: 2026-10-11 · Language: en
- Canonical page: https://hysenlabs.com/projects/hanakai-rb-rom

## Object mapping without hiding the database: what rom-rb is for

Ruby Object Mapper, published as the rom gem, is a data mapping and persistence toolkit for Ruby. Its stated goal is to give full access to object mapping without constraining what the database can express. Domain objects should not carry database-level concerns or be coupled to table structure; that is the design position rom takes.

Project topics cover both sql and nosql backends alongside ddd (domain-driven design) and data-access-layer patterns. rom is not limited to relational storage: whether the backend is a SQL database or a NoSQL store, the adapter layer handles the data side while the domain model works with plain Ruby objects that have no knowledge of where they were fetched from.

This separation has a concrete implication for query complexity. ActiveRecord constrains what SQL can look like because the ORM generates the statement; rom's stated goal is to remove that constraint. Applications with complex, database-specific queries do not need to work around an abstraction layer that cannot express what they need.

The gem is MIT-licensed, v5.4.3 was published on 2025-11-20, and the last push to the repository was on 2026-10-05.

## Three components: core adapters, changeset objects, and repository abstraction

rom bundles three components, each in its own subdirectory with its own README.

core, in core/, provides the Core and Adapter APIs. Adapters form the bridge between rom's object-mapping layer and individual storage backends, and core defines the contract that all adapters must satisfy. Without an adapter, rom has no way to talk to a specific database.

changeset, in changeset/, handles the lifecycle of modifications to data integrated with rom-core. Changesets provide an object-oriented model for data changes rather than placing mutation logic directly on the domain object, keeping the modification concern separate from both the storage and the domain layers.

repository, in repository/, adds a repository abstraction on top of rom-core. A repository pattern separates the logic of how data is fetched and stored from the domain objects that consume it, which is the direct implementation of the domain-driven design orientation the ddd topic tag indicates.

Each component has a link to its own README from the main repository page. rom-rb.org/learn/repository/5.2/quick-start documents how the three layers connect in a working project, with code examples the main README does not carry.

## Installing rom and the docker-compose development environment

The gem is published as rom on RubyGems at rubygems.org/gems/rom. A quick-start is at rom-rb.org/learn/repository/5.2/quick-start and an introduction to the concepts is at rom-rb.org/learn/introduction.

For contributors or teams running the full test suite, the repository provides a Docker development environment. The docker-compose.yml at the repository root sets up a postgres service and an application container:

```yaml
version: '2'
services:
  db:
    image: postgres:latest
    ports:
      - 5432:5432
    environment:
      POSTGRES_DB: rom_repository

  app:
    build: .
    command: ./docker_start.sh
    environment:
      BASE_DB_URI: postgres@db/rom_repository
    volumes:
      - .:/opt/rom
      - bundle_box:/opt/bundle_box
    links:
      - db

volumes:
  bundle_box:
```

The app container starts by running `docker_start.sh` and connects to postgres via the `BASE_DB_URI` variable, set to `postgres@db/rom_repository`. The `rom_repository` database is created automatically when the db container starts. The app code is mounted at /opt/rom.

## The Dockerfile installs libsqlite3-dev alongside ruby:latest

Dockerfile builds the application image from ruby:latest and installs libsqlite3-dev:

```dockerfile
FROM ruby:latest

RUN apt-get update -qq && apt-get install -y libsqlite3-dev

ENV rom /opt/rom/
ENV bundle_path /opt/box
ENV BUNDLE_PATH $bundle_path
```

`libsqlite3-dev` appearing in a docker-compose setup that runs only postgres is worth noting. postgres handles integration-level testing, but `libsqlite3-dev` supports lighter-weight development and test runs that do not need the full postgres service active. This dual-backend approach is consistent with rom's adapter design: the same domain and repository code can run against different adapters without touching the domain layer.

All container operations run as a non-root user named user. Application code lands at /opt/rom, defined by the rom environment variable, and bundled gems go to /opt/box via `BUNDLE_PATH`. WORKDIR is /opt/rom, and files are copied with --chown=user:user to keep non-root ownership through the image build. A `bundle_box` volume in docker-compose.yml persists gems across container restarts.

## rom-rb vs ActiveRecord: who owns the query

ActiveRecord, which ships with Rails, uses the Active Record pattern: each model class corresponds to a table, and queries are expressed as method chains on the model class. The model both represents a domain object and carries the persistence mechanics. For applications where query complexity fits within the ORM's abstraction, this is convenient. For applications where the domain logic and query logic need to stay separate, coupling them into one class creates friction.

rom's stated goal is to provide object mapping without limiting the full power of the database. The repository component handles data retrieval separately from the objects it returns. The changeset component handles modification separately from the objects it modifies. Domain objects have no ActiveRecord-style callbacks, timestamps, or association macros. The application side works with plain Ruby objects; the persistence side works with adapters.

For a small team comfortable with Rails conventions, switching to rom adds configuration cost without clear benefit. The Quick Start guide at rom-rb.org/learn/repository/5.2/quick-start is the right first read before deciding; it shows the wiring between adapters, relations, and repositories in a working example.

## Where the documentation stops: sub-READMEs and rom-rb.org

rom's main README is intentionally brief. It names the three components and links to their component-level READMEs inside core/, changeset/ and repository/. Usage examples, adapter configuration, and relation definitions are not in the top-level README.

Substantive documentation lives at rom-rb.org. Introduction content is at rom-rb.org/learn/introduction and the repository quick-start is at rom-rb.org/learn/repository/5.2/quick-start. Both URLs appear in the README, but the content is external to the repository itself.

This means the repository alone cannot answer how to configure an adapter, write a mapper, or define relations between data sources. For engineers evaluating adoption, rom-rb.org is the primary resource, not the GitHub repository. CONTRIBUTING.md and CODE_OF_CONDUCT.md at the repository root document the contribution process. A Gemfile.devtools alongside the main Gemfile separates development-only dependencies from the gem's runtime requirements, which keeps the runtime dependency set clean.

## Patch publishing cadence and the Zulip chat community

Patch version data from the repository shows a pattern worth reading carefully. Versions v5.4.2 and v5.4.1 were published on the same date, 2025-01-19, with v5.4.1 at 14:41:05Z and v5.4.2 at 14:41:24Z, a gap of nineteen seconds. An interval of nineteen seconds means a correction was applied within seconds of the initial patch going out; v5.4.3 followed on 2025-11-20 as the current version.

Community discussion runs on Zulip at rom-rb.zulipchat.com, with a badge and link in the README header. For questions about adoption or contribution, Zulip is the documented contact point.

Funding goes through OpenCollective at opencollective.com/rom, with individual backers and organizational sponsors listed in the README with avatars and site links. GitHub Actions handles CI and Codacy handles code quality and coverage analysis, both linked from the README header badges.

## Conclusion

rom-rb suits Ruby applications where the domain model should remain independent of how data is stored and fetched. The repository pattern and changeset abstraction make persistence explicit rather than wired into model classes. Teams building straightforward CRUD applications on Rails will find that ActiveRecord handles their needs without the configuration overhead rom requires. Teams building domain-driven applications with complex query requirements, or applications that span SQL and NoSQL backends, are a better fit. Before adopting, verify the application's database usage can be expressed through rom adapters and read rom-rb.org/learn/repository/5.2/quick-start as a starting point.

## FAQ

### How do I install the rom-rb gem?

The gem is published as rom on RubyGems at rubygems.org/gems/rom. A quick-start guide for the repository component is at rom-rb.org/learn/repository/5.2/quick-start.

### What databases does rom-rb support?

The repository topics list both sql and nosql, and the Docker development environment uses postgres. The Dockerfile also installs libsqlite3-dev, indicating SQLite support for testing. Specific adapter documentation is at rom-rb.org.

### What is the difference between rom-rb and ActiveRecord?

rom-rb separates domain objects from persistence mechanics using the repository and changeset components. ActiveRecord couples the domain model to the table. The rom-rb goal is to avoid limiting database access; ActiveRecord abstracts it.

### Where is the rom-rb documentation?

The main documentation is at rom-rb.org. The introduction is at rom-rb.org/learn/introduction and the repository quick-start is at rom-rb.org/learn/repository/5.2/quick-start. Each sub-component (core, changeset, repository) has its own README in the repository.

### Is rom-rb actively maintained?

The last push to the repository was on 2026-10-05, and v5.4.3 was published on 2025-11-20. Community discussion is on Zulip at rom-rb.zulipchat.com.

## Sources

- [hanakai-rb/rom on GitHub](https://github.com/hanakai-rb/rom)
- [License: MIT](https://github.com/hanakai-rb/rom/blob/main/LICENSE)
- [Project website](https://rom-rb.org)
- [README](https://github.com/hanakai-rb/rom/blob/main/README.md)
- [Releases](https://github.com/hanakai-rb/rom/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/hanakai-rb-rom
