How to Connect to MongoDB from Ruby

6 min readMongoDB

MongoDB is not a SQL database and there is no ADO.NET-style layer here: Ruby talks to it through one official driver, the mongo gem, a pure-Ruby client. Mongoid, the popular ODM (object-document mapper) used in Rails, sits on top of that same driver. This guide shows the raw mongo interface first, then where Mongoid fits, and covers the things that actually cause MongoDB-from-Ruby incidents: client reuse, lazy connections, the whole-document replace trap, SRV URIs, authSource, and pool sizing.

The options

LibraryLayerWhen to use itVersion (as of July 2026)
mongoOfficial driver (pure Ruby)Scripts, services, or when you want direct collection access2.24.1
MongoidODM built on the driverRails apps, or when you want models, validations, and associations9.1.0

Mongoid depends on the mongo gem, so the driver-level concerns below apply whether you write against the driver directly or through Mongoid.

Installing the driver

gem install mongo

The mongo gem is pure Ruby with no C extension, so there are no system headers to install and no compile step. For DNS SRV connection strings (the mongodb+srv:// form Atlas hands you), you also need a DNS resolver gem; add resolv if your environment does not already provide it.

A minimal connection

require 'mongo'
 
client = Mongo::Client.new(
  ['localhost:27017'],
  database: 'shop'
)
 
puts client.database.command(ping: 1).documents.first
 
client.close

Mongo::Client.new takes either an array of host strings plus options (above) or a single connection URI:

client = Mongo::Client.new('mongodb://app:secret@localhost:27017/shop')

Reuse one client -- do not create per request

A Mongo::Client owns a connection pool and background monitoring threads. Create it once at process startup and reuse it for the life of the app. Building a new client per web request exhausts connections and adds handshake latency on every call. In Rails this is what the Mongoid initializer or a global constant is for; in a plain service, store it in a constant or a container.

Close it on shutdown:

CLIENT = Mongo::Client.new(ENV['MONGODB_URI'])
at_exit { CLIENT.close }

Connections are lazy

Mongo::Client.new does not connect. It returns immediately and the first real network contact happens on your first operation. That means a wrong host or bad credentials surfaces as a Mongo::Error::NoServerAvailable on your first query, not at client creation. To fail fast at startup, ping explicitly:

client.database.command(ping: 1)

CRUD basics

Collections come off the client and documents are plain Ruby hashes:

customers = client[:customers]
 
# insert
customers.insert_one(name: 'Acme', region: 'EMEA', active: true)
 
# find
customers.find(region: 'EMEA').each do |doc|
  puts doc['name']
end
 
# update a subset of fields
customers.update_one({ name: 'Acme' }, { '$set' => { active: false } })
 
# delete
customers.delete_one(name: 'Acme')

Query filters are hashes; there is no SQL string and therefore no SQL-injection surface in the usual sense. Do still be careful passing raw user input as operators (for example letting a user supply a $where), which is the MongoDB equivalent risk.

The replace-vs-update data-loss trap

replace_one swaps the entire document for the one you pass. If you meant to change one field and used replace_one with just that field, every other field is gone:

# WRONG -- this wipes every field except status
customers.replace_one({ name: 'Acme' }, { status: 'inactive' })
 
# RIGHT -- change only the field you name
customers.update_one({ name: 'Acme' }, { '$set' => { status: 'inactive' } })

Reach for update_one/update_many with $set (and the other update operators) for partial changes. Use replace_one only when you genuinely want to overwrite the whole document.

Connecting to Atlas: SRV URIs and gotchas

Atlas gives you a mongodb+srv:// connection string:

client = Mongo::Client.new(
  'mongodb+srv://app:secret@cluster0.abcde.mongodb.net/shop?retryWrites=true&w=majority'
)

Three things trip people up:

  • mongodb+srv:// implies TLS. The SRV scheme turns on TLS by default and resolves the seed list from DNS, so you do not list hosts yourself.
  • Percent-encode credentials. A password containing @, /, :, or # must be URL-encoded in the URI, or parsing breaks in confusing ways.
  • authSource. By default the driver authenticates against the database in the URI path. If your user was created in admin (the common case), you need authSource=admin, or authentication fails even with correct credentials.

For Atlas specifically, the client's public IP must be on the project's IP access list, or the connection times out with no clear auth error.

Connection pooling

Each client keeps a pool per server it knows about. The size is controlled by max_pool_size (default 20):

client = Mongo::Client.new(
  ENV['MONGODB_URI'],
  max_pool_size: 20,
  min_pool_size: 5
)

The number that matters is max_pool_size × number of app processes × number of instances against the server's connection limit. A handful of Puma workers each with a 20-connection pool adds up quickly on a small cluster. Size the pool to your real concurrency, not to a big round number.

Mongoid

Mongoid configures the same driver through config/mongoid.yml:

production:
  clients:
    default:
      uri: <%= ENV['MONGODB_URI'] %>
      options:
        max_pool_size: 20

Models then map to collections:

class Customer
  include Mongoid::Document
  field :name, type: String
  field :region, type: String
  field :active, type: Boolean
end
 
Customer.where(region: 'EMEA').to_a

Mongoid gives you validations, associations, and query composition; underneath, every call goes through the mongo driver, so the pooling and authSource notes above still apply.

Common errors

ErrorCause
Mongo::Error::NoServerAvailableWrong host/port, server down, or Atlas IP not allow-listed (surfaces on first op, not on client create)
Mongo::Auth::UnauthorizedWrong credentials, or missing authSource=admin for an admin-created user
Connection to localhost refusedClient resolving to IPv6 ::1 while mongod listens on IPv4; use 127.0.0.1
URI parse errorsSpecial characters in the password not percent-encoded
Every field but one disappeared after an updatereplace_one used where update_one + $set was meant
Connections exhausted under loadA new client per request instead of one reused client; or pool size × processes over the server cap

Querying without writing connection code

If your goal is to explore a MongoDB database rather than build a service, a GUI client skips all of the above. Mako connects to MongoDB with AI-assisted queries -- see our MongoDB GUI client guide for how it compares to Compass and Studio 3T. Connecting from another language? See How to Connect to MongoDB from Python and from Node.js.

Mako connects to MongoDB with AI-powered autocomplete. Try it free at mako.ai.

Mako — open source

Skip the terminal. Use Mako.

Connect your database, write queries with AI assistance, and import/export data in clicks. Free to start.