<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Rentivio</title>
    <description>The latest articles on DEV Community by Rentivio (@rentivio).</description>
    <link>https://dev.to/rentivio</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4210289%2F6f5c4eab-9974-41d4-8d19-005727a6d42b.png</url>
      <title>DEV Community: Rentivio</title>
      <link>https://dev.to/rentivio</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rentivio"/>
    <language>en</language>
    <item>
      <title>How CouchDB and RustFS power Rentivio's property listings</title>
      <dc:creator>Rentivio</dc:creator>
      <pubDate>Tue, 27 Oct 2026 08:19:49 +0000</pubDate>
      <link>https://dev.to/rentivio/how-couchdb-and-rustfs-power-rentivios-property-listings-52eo</link>
      <guid>https://dev.to/rentivio/how-couchdb-and-rustfs-power-rentivios-property-listings-52eo</guid>
      <description>&lt;p&gt;&lt;a href="https://rentivio.gr" rel="noopener noreferrer"&gt;Rentivio&lt;/a&gt; connects home owners in Greece with professional short-term rental managers. Owners list homes that sit empty, managers lease them for a fixed monthly rent and run them for guests.&lt;/p&gt;

&lt;p&gt;A listings platform comes down to two kinds of data: &lt;strong&gt;records that keep changing shape&lt;/strong&gt;, and &lt;strong&gt;lots of photos&lt;/strong&gt;. Here's how two open-source tools handle them for us, and why we'd pick them again.&lt;/p&gt;

&lt;h2&gt;
  
  
  CouchDB: listings that can grow without migrations
&lt;/h2&gt;

&lt;p&gt;A property listing never stays the same for long. We started with location, rent and photos, then added minimum lease duration, amenities, deal status, moderation flags and more. In a relational database, every one of those changes is a migration. In CouchDB, a listing is a JSON document, so a new field is simply a new field.&lt;/p&gt;

&lt;p&gt;What worked well for us:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One database per concern.&lt;/strong&gt; Listings, users, payments and chat each live in their own CouchDB database. Each has its own indexes and its own backups, and a heavy query on one doesn't slow down the others.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Revisions catch conflicting edits.&lt;/strong&gt; Every update has to send the document's current &lt;code&gt;_rev&lt;/code&gt;. If two people edit the same listing at once, the second save fails instead of silently overwriting the first. We got that safety for free.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The app sets up its own database.&lt;/strong&gt; On startup, our Node.js service creates any missing databases, design documents and indexes. A fresh environment is ready with a single &lt;code&gt;docker compose up&lt;/code&gt;, and a new index ships in the same commit as the query that needs it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mango queries feel familiar.&lt;/strong&gt; Searching by area, price or status is a JSON selector plus an index. If you know MongoDB, you already know most of it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  RustFS: photos that never touch our server
&lt;/h2&gt;

&lt;p&gt;Listings live or die by their photos, and image traffic is the fastest way to overload a small API. We store photos in &lt;a href="https://github.com/rustfs/rustfs" rel="noopener noreferrer"&gt;RustFS&lt;/a&gt;, a lightweight, self-hosted, S3-compatible object store.&lt;/p&gt;

&lt;p&gt;The key decision: &lt;strong&gt;image bytes never pass through our API.&lt;/strong&gt; When someone uploads or views a photo, the API checks that they're allowed to, then returns a short-lived &lt;strong&gt;presigned URL&lt;/strong&gt;. The browser talks to RustFS directly.&lt;/p&gt;

&lt;p&gt;The result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Our API only sends small JSON responses, so it stays fast even when someone scrolls through dozens of photos.&lt;/li&gt;
&lt;li&gt;Because RustFS speaks the S3 API, we use the standard AWS SDK. Moving to any other S3-compatible provider later is a configuration change, not a rewrite.&lt;/li&gt;
&lt;li&gt;It runs as one more container next to the rest of the stack, with its data on a named Docker volume. Development and production behave the same way.&lt;/li&gt;
&lt;li&gt;Like CouchDB, the bucket is created automatically on startup, so there's nothing to click through in a console.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What we learned
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pick storage by the shape of the data.&lt;/strong&gt; Documents that change go in a document database. Large binary files go in object storage, not in the database and not through the API.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Let the app set up its own infrastructure.&lt;/strong&gt; Self-creating databases, indexes and buckets removed a whole class of "works on my machine" problems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-hosted doesn't have to mean complicated.&lt;/strong&gt; CouchDB and RustFS are each a single container with a persistent volume, and both have been low-maintenance for us.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you're building a small marketplace and wondering whether you need a managed cloud database and storage from day one: you might not. CouchDB and RustFS have carried Rentivio comfortably so far.&lt;/p&gt;

&lt;p&gt;Curious about the product? Have a look at &lt;a href="https://rentivio.gr" rel="noopener noreferrer"&gt;rentivio.gr&lt;/a&gt;. Questions about the setup are welcome in the comments.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://rentivio.gr/?utm_source=devto&amp;amp;utm_medium=social&amp;amp;utm_campaign=cm-post-6" rel="noopener noreferrer"&gt;https://rentivio.gr/?utm_source=devto&amp;amp;utm_medium=social&amp;amp;utm_campaign=cm-post-6&lt;/a&gt;&lt;/p&gt;

</description>
      <category>couchdb</category>
      <category>node</category>
      <category>database</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
