<?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: Mateusz Woźniak</title>
    <description>The latest articles on DEV Community by Mateusz Woźniak (@matisiekpl).</description>
    <link>https://dev.to/matisiekpl</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F162624%2F3fe3ef91-d099-46c5-8996-ff853b526e31.jpeg</url>
      <title>DEV Community: Mateusz Woźniak</title>
      <link>https://dev.to/matisiekpl</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/matisiekpl"/>
    <language>en</language>
    <item>
      <title>I built a self-hosted PostgreSQL Control Plane that runs on single Docker container</title>
      <dc:creator>Mateusz Woźniak</dc:creator>
      <pubDate>Mon, 20 Apr 2026 08:30:19 +0000</pubDate>
      <link>https://dev.to/matisiekpl/i-built-a-self-hosted-postgresql-control-plane-that-runs-on-single-docker-container-30gm</link>
      <guid>https://dev.to/matisiekpl/i-built-a-self-hosted-postgresql-control-plane-that-runs-on-single-docker-container-30gm</guid>
      <description>&lt;h2&gt;
  
  
  The itch I was scratching
&lt;/h2&gt;

&lt;p&gt;Every time I spin up a new side project, I hit the same wall with Postgres:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;postgres:latest&lt;/code&gt; in Docker is fine until you want a throwaway copy of prod to reproduce a bug, or a preview environment per PR.&lt;/li&gt;
&lt;li&gt;Managed services (Neon, Supabase, RDS) solve this beautifully — branching in seconds, PITR by default — but they cost real money once you have more than a toy project, and you lose control. Also for me latency was always big problem. Most of my projects are hosted on big dedicated server in Warsaw (Poland), but cloud providers don't often offer this region.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;I wanted the developer experience of Neon — instant branches, a nice UI, one connection string per branch — on a $10 Hetzner box. That gap is what NeonD tries to fill.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What it actually does
&lt;/h2&gt;

&lt;p&gt;NeonD is a control plane that sits on top of the open-source neondatabase/neon storage engine. The Neon team open-sourced the hard parts (pageserver, safekeeper, compute); NeonD wraps them into something you can deploy in five minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Spin up Postgres instances on v14, v15, v16, or v17 from a web UI&lt;/li&gt;
&lt;li&gt;Branch any timeline — fork production into dev, pr-142, bug-repro in seconds, because branches are copy-on-write at the storage layer&lt;/li&gt;
&lt;li&gt;Point-in-time recovery down to the second&lt;/li&gt;
&lt;li&gt;S3 checkpoints — your data lives durably in an S3 bucket, the local disk is just a cache&lt;/li&gt;
&lt;li&gt;TLS SNI routing — publish compute endpoints under subdomains like &lt;code&gt;{instance-slug}.yourcompany.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Multi-tenancy — organizations, projects, users, roles&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Migration between servers is docker compose down, rsync one directory, docker compose up on the new box. That's it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe9m34bvs9lod7p9wk6mn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe9m34bvs9lod7p9wk6mn.png" alt="Screenshot from Dashboard" width="800" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What it's not
&lt;/h2&gt;

&lt;p&gt;I want to be very upfront: NeonD is not for mission-critical production. The architecture is intentionally tightly coupled — one container, one server, one point of failure. There's no HA, no automated failover, no multi-region story.&lt;br&gt;
If you're running a bank, use RDS. If you're running a side project, a staging cluster, a preview-environment farm, or an early-stage startup where velocity matters more than five nines — that's the sweet spot.&lt;/p&gt;
&lt;h2&gt;
  
  
  A quick tour
&lt;/h2&gt;

&lt;p&gt;Deployment is a docker-compose.yaml:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;neond&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;neond/neond:latest&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;PORT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3000&lt;/span&gt;
      &lt;span class="na"&gt;SERVER_SECRET&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SuperSecret"&lt;/span&gt; &lt;span class="c1"&gt;# you should change this&lt;/span&gt;
      &lt;span class="na"&gt;PORT_RANGE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;50000-50010&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3000:3000"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;50000-50010:50000-50010"&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./neond_data:/neond&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;a href="http://your-server:3000" rel="noopener noreferrer"&gt;http://your-server:3000&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Create an organization and a project&lt;/li&gt;
&lt;li&gt;Hit "Start endpoint" on the production branch&lt;/li&gt;
&lt;li&gt;Copy the connection string, psql in&lt;/li&gt;
&lt;li&gt;Right-click the branch → "Create branch from here" → you now have an instant, isolated copy of your data on a new connection string&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Total time from docker compose up to querying a branched database: under five minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where I'd love feedback
&lt;/h2&gt;

&lt;p&gt;This is an early project (17 stars as I write this, hi!) and there are plenty of rough edges. Things I'd especially appreciate eyes on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The branching UX — is it intuitive if you've never used Neon?&lt;/li&gt;
&lt;li&gt;The S3 setup — does the doc make sense for people who aren't AWS-native?&lt;/li&gt;
&lt;li&gt;Use cases I haven't thought of — tell me what you'd want to do with branching Postgres on your own box&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Repo: &lt;a href="//github.com/matisiekpl/neond"&gt;github.com/matisiekpl/neond&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Credits
&lt;/h2&gt;

&lt;p&gt;Huge credit to the Neon team for open-sourcing the storage engine. NeonD is a thin control plane on top of their work — none of this would exist without what they've built.&lt;/p&gt;

</description>
      <category>database</category>
      <category>postgres</category>
      <category>selfhosted</category>
    </item>
  </channel>
</rss>
