DEV Community

GermĂĄn Alberto Gimenez Silva
GermĂĄn Alberto Gimenez Silva

Posted on • Originally published at rubystacknews.com on

🎸 Building a Multi-Tenant Rails App for Music Stores Using Apartment

May 14, 2025

A few months ago, I had to build a SaaS platform for music instrument stores. Each store needed to manage its own products, customers, and sales, but everything had to run under one codebase.

Article content

I ended up going with the apartment gem to handle multi-tenancy — specifically, schema-based separation using PostgreSQL. It was a learning curve, but totally worth it. Here’s how I made it work and some things I learned along the way.


🏢 Ready to Add Multi-Tenancy to Your Rails App?

Whether you’re building a SaaS platform or managing data for multiple clients, multi-tenancy is a game-changer — and we’ve got the tools and experience to help you implement it the right way.

Let’s set up clean, isolated environments for each of your customers using proven solutions like the apartment gem.

👉


The Setup

The idea was simple: every store that signs up gets its own schema. That way, their data stays isolated, and they don’t accidentally see another store’s inventory or customers.

I added apartment to the Gemfile:


gem 'apartment'

Enter fullscreen mode Exit fullscreen mode

Then configured it like this:


# config/initializers/apartment.rb

Apartment.configure do |config|
  config.excluded_models = %w[User] # Global models like admin users
  config.use_schemas = true
end

# This switches tenants based on subdomain (e.g. store1.myapp.com)
Rails.application.config.middleware.use Apartment::Elevators::Subdomain

Enter fullscreen mode Exit fullscreen mode

This setup assumes each store logs in via their own subdomain, like rockstore.myapp.com or jazzcenter.myapp.com.


Creating Stores (Tenants)

Article content

Once a store signs up, I just run:


Apartment::Tenant.create("rockstore")

Enter fullscreen mode Exit fullscreen mode

That creates a new schema inside PostgreSQL. Then I seed it with default data or let them start fresh.

For dev and testing, I used something like this in the Rails console:


Apartment::Tenant.switch("rockstore") do
  Instrument.create(name: "Fender Jazz Bass", brand: "Fender", price: 950)
end

Enter fullscreen mode Exit fullscreen mode

Each store gets their own instruments, customers, and orders — completely separate from the others.


A Bit About Models

I kept it pretty simple:


rails generate model Instrument name:string brand:string price:decimal
rails generate model Customer name:string email:string
rails generate model Order customer:references total:decimal

Enter fullscreen mode Exit fullscreen mode

These models live in the tenant schemas. Global stuff (like platform admins) stays in the public schema — that’s what the excluded_models setting is for.


Running Migrations

One thing to watch out for: every time you change the schema, you’ll want to run the migrations across all tenants. The gem gives you a rake task for that:


rake apartment:migrate

Enter fullscreen mode Exit fullscreen mode

If you forget this, some tenants will have outdated table structures — been there, done that 😅.


What Worked Well

  • I liked how clean and isolated the data was per store.
  • Switching schemas based on subdomain worked great.
  • Onboarding new stores was simple — just Apartment::Tenant.create(…) and you’re good to go.

A Few Gotchas

  • Migrations can be tricky. You’ll need to be careful testing them in multiple tenants.
  • Avoid jumping between tenants too much inside the same thread or request — always make sure you reset.
  • It’s not the best fit if you’re managing thousands of tenants — PostgreSQL has limits on schema counts, and you might hit performance issues eventually.

Final Thoughts

If you’re building a multi-tenant Rails app and want strong data isolation, apartment is worth considering — especially if you’re already using PostgreSQL.

It saved me a ton of work and let me keep one codebase while still giving each music store their own “space” to operate in. Just be ready to get your hands a little dirty with migrations and schema management.

If you’re trying it out and hit a wall, feel free to reach out. I probably ran into the same thing at some point.

Article content

Top comments (0)