<?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>Forem: ghost</title>
    <description>The latest articles on Forem by ghost (@ghostdotbuild).</description>
    <link>https://forem.com/ghostdotbuild</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%2F3841846%2F97db04ab-5986-4662-a87e-e5de77d1930e.png</url>
      <title>Forem: ghost</title>
      <link>https://forem.com/ghostdotbuild</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/ghostdotbuild"/>
    <language>en</language>
    <item>
      <title>Ship an app on Ghost + Fly.io for $2/month</title>
      <dc:creator>ghost</dc:creator>
      <pubDate>Tue, 12 May 2026 02:34:43 +0000</pubDate>
      <link>https://forem.com/ghostbuild/ship-an-app-on-ghost-flyio-for-2month-4f9</link>
      <guid>https://forem.com/ghostbuild/ship-an-app-on-ghost-flyio-for-2month-4f9</guid>
      <description>&lt;p&gt;Putting a real public app on the internet shouldn't cost $25/month for managed Postgres alone — before you've added compute or shipped a feature. Ghost gives you the database, Fly.io gives you the host, and your AI agent does the plumbing.&lt;/p&gt;

&lt;p&gt;You can launch a public-facing, sparse-traffic hobby app, backed by Postgres, for roughly the cost of a coffee per month.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who this is for
&lt;/h2&gt;

&lt;p&gt;This guide is for developers who use an AI coding agent (Claude Code, Cursor, Codex, Windsurf, etc.) and want to ship a small public app fast and cheap. You don't need to know SQL or Docker — the agent handles both — but you should be comfortable approving shell commands the agent runs on your behalf.&lt;/p&gt;

&lt;p&gt;You'll need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An AI coding agent &lt;strong&gt;with both MCP support and a Bash/shell tool&lt;/strong&gt; (Claude Code, Cursor in agent mode, Codex, Windsurf, Gemini CLI, VS Code, Kiro, or Antigravity). The shell tool is what lets the agent run &lt;code&gt;flyctl&lt;/code&gt; and &lt;code&gt;npm&lt;/code&gt; on your behalf — most modern agents have this.&lt;/li&gt;
&lt;li&gt;macOS, Linux, or Windows (WSL recommended on Windows for &lt;code&gt;flyctl&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;A Fly.io account with a credit card on file. &lt;/li&gt;
&lt;li&gt;An internet connection. The agent will install everything else (&lt;code&gt;flyctl&lt;/code&gt;, Node, etc.) on its own.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is Ghost
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Ghost is Postgres for builders and their agents.&lt;/strong&gt; Unlimited databases, metered by hours of active compute. All via CLI and MCP, no GUI required.&lt;/p&gt;

&lt;p&gt;Create one in seconds, fork it like git when you want to experiment safely, share it with a simple link like a Google doc. Graduate to production with one command or throw it away when you're done.&lt;/p&gt;

&lt;p&gt;The free tier covers 100 active compute hours per month and 1TB of storage. Compute is metered in 15-minute chunks when something queries the database; an idle database burns no compute. A sparse-traffic hobby app — a handful of human visits a day — comfortably fits the free tier.&lt;/p&gt;

&lt;p&gt;You can do this with managed-Postgres alternatives like Neon, Supabase, or RDS — but those either charge a flat monthly fee, cap project counts, or push you through a GUI for changes the agent could otherwise make in seconds. Ghost is the cheapest, most agent-native way to ship a public app with real Postgres.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you will do
&lt;/h2&gt;

&lt;p&gt;In this guide, we'll deploy a public-facing todo app to Fly.io with a Ghost Postgres database. After a one-time bootstrap, &lt;strong&gt;the agent does everything else&lt;/strong&gt; — you just paste prompts.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Bootstrap (you):&lt;/strong&gt; install the Ghost CLI and &lt;code&gt;flyctl&lt;/code&gt;, log in, configure the Ghost MCP server in your agent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scaffold the app + create the database + define the schema (agent):&lt;/strong&gt; generate a small Express todo app, create a Ghost database, define a &lt;code&gt;todos&lt;/code&gt; table.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wire the app to the database and test locally (agent):&lt;/strong&gt; set &lt;code&gt;DATABASE_URL&lt;/code&gt;, run the app on &lt;code&gt;localhost&lt;/code&gt;, round-trip a todo through the database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy to Fly.io (agent):&lt;/strong&gt; create the Fly app, push the connection string as a secret, deploy to a &lt;code&gt;*.fly.dev&lt;/code&gt; URL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verify the public app (agent):&lt;/strong&gt; curl the live URL, add a todo over HTTPS, confirm it landed in Ghost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open it in your browser (you):&lt;/strong&gt; use the live app yourself and share the URL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clean up (agent):&lt;/strong&gt; destroy the Fly app and delete the Ghost database.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 1 — Bootstrap (you, one-time)
&lt;/h2&gt;

&lt;p&gt;This is the only part you can't delegate.&lt;/p&gt;

&lt;p&gt;Install the &lt;code&gt;ghost&lt;/code&gt; CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://install.ghost.build | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On Windows, run &lt;code&gt;irm https://install.ghost.build/install.ps1 | iex&lt;/code&gt; in PowerShell.&lt;/p&gt;

&lt;p&gt;Install &lt;code&gt;flyctl&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-L&lt;/span&gt; https://fly.io/install.sh | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On Windows, run &lt;code&gt;pwsh -Command "iwr https://fly.io/install.ps1 -useb | iex"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Log into both:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ghost login
flyctl auth login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each opens your browser. &lt;code&gt;flyctl auth login&lt;/code&gt; prompts you to add a credit card if you haven't yet.&lt;/p&gt;

&lt;p&gt;Configure Ghost as an MCP server in your agent. For Claude Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ghost mcp &lt;span class="nb"&gt;install &lt;/span&gt;claude-code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;claude-code&lt;/code&gt; with &lt;code&gt;cursor&lt;/code&gt;, &lt;code&gt;codex&lt;/code&gt;, &lt;code&gt;windsurf&lt;/code&gt;, &lt;code&gt;gemini&lt;/code&gt;, &lt;code&gt;vscode&lt;/code&gt;, &lt;code&gt;kiro-cli&lt;/code&gt;, or &lt;code&gt;antigravity&lt;/code&gt; if you use a different agent. Run &lt;code&gt;ghost mcp install&lt;/code&gt; with no argument for an interactive picker.&lt;/p&gt;

&lt;p&gt;Restart your agent so it picks up the new MCP server.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Expected output:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ghost &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;span class="go"&gt;ghost version 1.x.x

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;flyctl version
&lt;span class="go"&gt;flyctl v0.x.x ...
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once both CLIs are installed, you're logged in, and the agent has been restarted, the rest is the agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 — Scaffold the app, create the database, define the schema (agent)
&lt;/h2&gt;

&lt;p&gt;Tell the agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Build me a minimal public-facing todo app I can deploy to Fly.io.

Create a fresh empty directory called `todo-app` and work inside it.

Stack: Node.js with Express and the `pg` package. One server file. Server-rendered HTML — no frontend framework. Read DATABASE_URL from the environment.

Routes:
- GET  /                  render the list of todos with a small form to add a new one
- POST /todos             insert a new todo from form data, then redirect to /
- POST /todos/:id/done    mark a todo done, then redirect to /

Files to write:
- package.json             express + pg + dotenv
- server.js                the app
- Dockerfile               minimal Node runtime, copies package.json + server.js, runs `node server.js`
- fly.toml                 app = "todo-app", primary_region = "iad", [http_service] with internal_port=3000, force_https=true, auto_stop_machines="stop", auto_start_machines=true, min_machines_running=0. No [[services]] block. No [[mounts]]. No managed Postgres.
- .dockerignore            node_modules, .env, .git

Then, using the Ghost MCP:
1. Create a new Ghost database called "todo-app". Wait for it to be ready.
2. Create a `todos` table with columns: id (serial primary key), text (text not null), done (boolean default false), created_at (timestamptz default now()).
3. Print the connection string so I can use it in the next step.

Don't use a migration framework. Don't add auth. Keep server.js under 100 lines.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write &lt;code&gt;package.json&lt;/code&gt;, &lt;code&gt;server.js&lt;/code&gt;, &lt;code&gt;Dockerfile&lt;/code&gt;, &lt;code&gt;fly.toml&lt;/code&gt;, &lt;code&gt;.dockerignore&lt;/code&gt;, and minimal HTML.&lt;/li&gt;
&lt;li&gt;Create the Ghost database.&lt;/li&gt;
&lt;li&gt;Create the &lt;code&gt;todos&lt;/code&gt; table.&lt;/li&gt;
&lt;li&gt;Print the connection string.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Expected output:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Database "todo-app" created (status: running).
Table "todos" created with 4 columns.
Connection: postgres://tsdbadmin:...@...tsdb.cloud.timescale.com:.../tsdb?sslmode=require
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You now have a Postgres database in the cloud and a tiny app on disk — including a Dockerfile and fly.toml — ready for deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 — Wire the app to the database and test locally (agent)
&lt;/h2&gt;

&lt;p&gt;Tell the agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Wire the app to the Ghost database we just created.

1. Write a `.env` file with DATABASE_URL set to the connection string from the previous step. Add `.env` to `.gitignore`.
2. Make sure server.js loads .env (use the `dotenv` package).
3. SSL setup for Timescale: recent `pg` versions treat `sslmode=require` in the URL as `verify-full`, which rejects Timescale's cert chain and crashes on the first query. Strip the `sslmode` query param from DATABASE_URL before passing it to `new Pool({ ... })`, and pass `ssl: { rejectUnauthorized: false }` in the Pool config.
4. Run `npm install` and start the server on port 3000 in the background.
5. Use curl to: GET /, POST a todo with text="Ship the app", GET / again, then POST /todos/1/done.
6. Print the response bodies so I can see the todo round-tripping through the database.
7. Stop the local server.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write &lt;code&gt;.env&lt;/code&gt; and update &lt;code&gt;.gitignore&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Install dependencies.&lt;/li&gt;
&lt;li&gt;Start &lt;code&gt;node server.js&lt;/code&gt; in the background.&lt;/li&gt;
&lt;li&gt;Run a sequence of &lt;code&gt;curl&lt;/code&gt; commands.&lt;/li&gt;
&lt;li&gt;Kill the local process.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Expected output:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;curl localhost:3000
&lt;span class="gp"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;...&amp;lt;h1&amp;gt;Todos&amp;lt;/h1&amp;gt;&amp;lt;form &lt;span class="nv"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/todos"&lt;/span&gt; &lt;span class="nv"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"post"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;...
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'text=Ship the app'&lt;/span&gt; localhost:3000/todos
&lt;span class="go"&gt;(302 redirect to /)

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;curl localhost:3000
&lt;span class="gp"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;...&amp;lt;li&amp;gt;Ship the app &amp;lt;form &lt;span class="nv"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/todos/1/done"&lt;/span&gt;...
&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST localhost:3000/todos/1/done
&lt;span class="go"&gt;(302 redirect to /)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The app works end-to-end against your Ghost database. Time to put it on the internet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4 — Deploy to Fly.io (agent)
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Warning:&lt;/strong&gt; This step creates a billable Fly.io app on a public URL. With auto-stop machines enabled (configured in step 2's &lt;code&gt;fly.toml&lt;/code&gt;), an idle app costs only for storage and bandwidth — typically cents per month — but charges accrue once the machine is running. Make sure you're comfortable with Fly's pay-as-you-go pricing before deploying.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Tell the agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Deploy the app to Fly.io. Skip `flyctl launch` entirely — we already have a Dockerfile and fly.toml from step 2, and `flyctl launch --yes` has a habit of provisioning unwanted Fly Postgres clusters and overwriting DATABASE_URL.

1. Pick a globally unique app name. Start with "todo-app" and append a 6-char random suffix if Fly says it's taken (e.g. "todo-app-a1b2c3").
2. Update `app = ` in fly.toml to that name.
3. Create the app: `flyctl apps create &amp;lt;name&amp;gt;`.
4. Set DATABASE_URL as a Fly secret using the connection string from step 2: `flyctl secrets set DATABASE_URL="&amp;lt;connection string&amp;gt;" --app &amp;lt;name&amp;gt;`.
5. Deploy: `flyctl deploy --ha=false`. Wait for it to finish.
6. After deploy, force a single machine: `flyctl scale count 1 --app &amp;lt;name&amp;gt; --yes`. (Fly's first deploy sometimes creates two machines despite `--ha=false`; this keeps it to one so the auto-stop story stays honest.)
7. Print the public URL.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pick an app name and update &lt;code&gt;fly.toml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;flyctl apps create&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Set the secret.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;flyctl deploy --ha=false&lt;/code&gt; and capture the URL.&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;flyctl scale count 1&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Expected output:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;==&amp;gt; Building image
...
==&amp;gt; Pushing image to fly
...
==&amp;gt; Monitoring deployment
 ✔ [job] update succeeded

Visit your newly deployed app at https://todo-app-&amp;lt;suffix&amp;gt;.fly.dev/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your app is live on the public internet, talking to your Ghost database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5 — Verify the public app (agent)
&lt;/h2&gt;

&lt;p&gt;Tell the agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Verify the deployed app works against the Ghost database.

1. curl the public URL and confirm it renders the todos page.
2. Submit a new todo via curl: POST /todos with text="Hello from the internet".
3. curl the public URL again and confirm the new todo shows up.
4. Use the Ghost MCP to run `SELECT * FROM todos ORDER BY id` and show me the rows directly from the database.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;curl https://todo-app-&amp;lt;suffix&amp;gt;.fly.dev/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;curl -X POST -d 'text=Hello from the internet' https://todo-app-&amp;lt;suffix&amp;gt;.fly.dev/todos&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;curl https://todo-app-&amp;lt;suffix&amp;gt;.fly.dev/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Run the SELECT through the Ghost MCP.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Expected output:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; id |          text           | done |          created_at
----+-------------------------+------+-------------------------------
  1 | Ship the app            | t    | 2026-05-07 10:42:15.123+00
  2 | Hello from the internet | f    | 2026-05-07 10:48:03.456+00
(2 rows)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The row added through the public HTTPS URL is sitting in your Ghost database. You shipped a public-facing, Postgres-backed app.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6 — Open it in your browser (you)
&lt;/h2&gt;

&lt;p&gt;Click the &lt;code&gt;https://todo-app-&amp;lt;suffix&amp;gt;.fly.dev/&lt;/code&gt; URL printed at the end of step 4 (or paste it into your browser).&lt;/p&gt;

&lt;p&gt;Add a few todos through the form. Mark some done. Refresh the page — your todos persist across reloads because they're sitting in Ghost. Send the URL to a friend; it works for them too. It's on the public internet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Expected output:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A working todo app in your browser, with todos that survive a refresh.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 7 — Clean up (agent)
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Warning:&lt;/strong&gt; &lt;code&gt;flyctl apps destroy&lt;/code&gt; and Ghost's &lt;code&gt;delete&lt;/code&gt; are irreversible. The Fly app, all its history, and the Ghost database (including all data) are gone. The agent will run these on your behalf — don't approve unless you mean it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Tell the agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Tear down everything we created so I'm not paying for an idle Fly machine or holding a Ghost database I don't need.

1. Run `flyctl apps destroy &amp;lt;app-name&amp;gt; --yes` to delete the Fly app.
2. Use the Ghost MCP to delete the "todo-app" database.
3. Confirm both are gone: `flyctl apps list` should not list the app, and `ghost list` should not list the database.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Expected output:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;flyctl apps destroy todo-app-&amp;lt;suffix&amp;gt; &lt;span class="nt"&gt;--yes&lt;/span&gt;
&lt;span class="gp"&gt;Destroyed app todo-app-&amp;lt;suffix&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;
&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ghost delete todo-app
&lt;span class="go"&gt;Deleted database "todo-app".

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;flyctl apps list
&lt;span class="go"&gt;NAME    OWNER   STATUS  ...
(no todo-app)

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ghost list
&lt;span class="go"&gt;NAME  STATUS  ...
(no todo-app)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You're back to zero cost on both sides.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;You shipped a public-facing, Postgres-backed app for the price of a coffee. You learned how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bootstrap Ghost and Fly.io for an agent-driven workflow.&lt;/li&gt;
&lt;li&gt;Use Ghost's MCP server to create databases and run SQL from inside your agent.&lt;/li&gt;
&lt;li&gt;Deploy a Node.js app to Fly.io with auto-stop machines so you only pay for active compute.&lt;/li&gt;
&lt;li&gt;Connect a Fly app to a Ghost database via a &lt;code&gt;DATABASE_URL&lt;/code&gt; secret.&lt;/li&gt;
&lt;li&gt;Tear it all down cleanly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What to do next
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Add a custom domain with &lt;code&gt;flyctl certs add yourdomain.com&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add authentication — a session-cookie + bcrypt setup is enough for a small app.&lt;/li&gt;
&lt;li&gt;Try &lt;code&gt;ghost fork&lt;/code&gt; before your next schema change — Ghost lets you run a risky migration on a copy of the database first, then apply the same migration to production once you're happy.&lt;/li&gt;
&lt;li&gt;Read the Fly docs on &lt;a href="https://fly.io/docs/launch/autostop-autostart/" rel="noopener noreferrer"&gt;auto-stop machines&lt;/a&gt; to understand how the scale-to-zero billing works.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Make Ghost your default Postgres!
&lt;/h2&gt;

&lt;p&gt;Tell your agent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;When I'm prototyping or shipping a small app and need a Postgres database, default to Ghost. Use Ghost MCP tools to create / fork / delete databases and to run SQL. Don't suggest local Postgres setup or other managed-Postgres services unless I ask.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Does this work with my agent?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes, as long as it has both MCP support and a Bash/shell tool. Confirmed-working agents include Claude Code, Cursor (in agent mode), Codex, Windsurf, Gemini CLI, VS Code with Copilot, Kiro, and Antigravity. The shell tool is what lets the agent run &lt;code&gt;flyctl deploy&lt;/code&gt; and &lt;code&gt;npm install&lt;/code&gt; for you — without it, the agent can talk to Ghost via MCP but can't deploy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How much does this actually cost?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ghost is free for a sparse-traffic hobby app: 100 active compute hours per month and 1TB of storage. Ghost meters in 15-minute chunks when something queries the database, and idle databases don't burn compute. A handful of human visits per day fits comfortably.&lt;/p&gt;

&lt;p&gt;The failure mode to watch for: Ghost meters per 15-minute chunk, so anything that hits the database every 15 minutes — uptime monitors, health checks, aggressive bots, link previewers — can keep the meter running 24/7. That's ~720 hours/month, well past the 100-hour free tier, and works out to roughly $46/month at $0.075/CPU-hr. If your app needs constant availability, switch to Ghost's $10/month dedicated tier (always-on, no auto-pause).&lt;/p&gt;

&lt;p&gt;Fly.io is no longer free as of late 2024. With auto-stop enabled (which we configured in step 4), an idle app costs only for storage and bandwidth — typically cents per month. A small &lt;code&gt;shared-cpu-1x&lt;/code&gt; machine running 24/7 is around $2/month, and auto-stop means most hobby apps spend most of their time at zero compute.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why not just use SQLite on a Fly volume?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;SQLite + Fly volumes is a legitimate cheaper option for one-machine apps. You give up real concurrent writes, Postgres's type system and extensions (full-text search, JSONB, time-series, PostGIS, etc.), and the ability to scale to multiple Fly regions without painful litestream/LiteFS setups. You also can't &lt;code&gt;psql&lt;/code&gt; into a SQLite file from your laptop while debugging. For anything you'd want to grow into a real product, Postgres is worth the small extra setup — and with Ghost it's not a meaningful extra cost.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.ghost.build" rel="noopener noreferrer"&gt;Ghost docs&lt;/a&gt; — full CLI and MCP reference.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://fly.io/docs/launch/" rel="noopener noreferrer"&gt;Fly.io launch guide&lt;/a&gt; — deployment basics, including Dockerfile detection.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://fly.io/docs/launch/autostop-autostart/" rel="noopener noreferrer"&gt;Fly.io auto-stop machines&lt;/a&gt; — how scale-to-zero billing works.&lt;/li&gt;
&lt;li&gt;
&lt;a href="//movielens-analysis.md"&gt;How to Analyze a Dataset with Ghost and an AI Agent&lt;/a&gt; — same agent-driven shape, focused on data analysis.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>agents</category>
      <category>mcp</category>
      <category>sideprojects</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>your agent can think. it can't remember.</title>
      <dc:creator>ghost</dc:creator>
      <pubDate>Wed, 25 Mar 2026 15:01:56 +0000</pubDate>
      <link>https://forem.com/ghostbuild/your-agent-can-think-it-cant-remember-5e1o</link>
      <guid>https://forem.com/ghostbuild/your-agent-can-think-it-cant-remember-5e1o</guid>
      <description>&lt;p&gt;&lt;strong&gt;TLDR: &lt;a href="https://ghost.build" rel="noopener noreferrer"&gt;ghost&lt;/a&gt; gives your agent instant, ephemeral postgres databases. unlimited databases, unlimited forks, 1tb storage, free. pair it with Memory Engine for memory, pg_textsearch for full-text search, TigerFS for files, and Ox for sandboxed execution. All postgres-native.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;try Ghost today: &lt;code&gt;curl -fsSL https://install.ghost.build | sh&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;your agent can reason. it can plan. it can call tools and write code and hold a conversation that feels almost human.&lt;/p&gt;

&lt;p&gt;but ask it what it did yesterday and it doesn't know. ask it to store something for later and you’re the one figuring out where it goes. give two agents the same files and things break. tell it to run code safely and you're one bad rm -rf away from a really bad day.&lt;/p&gt;

&lt;p&gt;agents are getting smarter everyday. we haven't spent nearly enough time giving them somewhere to be productive.&lt;/p&gt;

&lt;h2&gt;
  
  
  duct tape as ai infra
&lt;/h2&gt;

&lt;p&gt;if you're building agents today, your infrastructure might look something like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;neon or supabase for the database&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;mem0 or zep for memory&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;pinecone or pgvector for search&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;s3 for files&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;e2b for sandboxed execution&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;five services. it works. kind of.&lt;/p&gt;

&lt;p&gt;until your agent's memory can't query its own database. until your sandbox can't read your agent's files. and what happens if the glue code holding everything together dissolves.&lt;/p&gt;

&lt;h2&gt;
  
  
  ghost is the database your agent is missing
&lt;/h2&gt;

&lt;p&gt;traditional databases are designed to be permanent, and the ritual of DB setup feels permanent. you provision one, you name it, you size compute, you choose a cloud provider, and a cloud region. you care for it, you back it up, you keep it running for years. that's fine for human workflows. it's wrong for agents.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ghost.build" rel="noopener noreferrer"&gt;ghost&lt;/a&gt; gives your agent postgres databases that are instant, ephemeral, and disposable. provision them through CLI or MCP. no UI. a thousand databases for a thousand parallel sessions, free.&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%2Fsdpqroqm6nsrq12ubfa9.gif" 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%2Fsdpqroqm6nsrq12ubfa9.gif" alt=" " width="844" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;the mental model is git, not RDS. spin up a database the way a developer creates a branch. do work. if the work is good, keep it. if not, throw it away. fork before a risky migration. run experiments on the fork. merge or discard. databases become part of the workflow, not the infrastructure you worry about underneath it.&lt;/p&gt;

&lt;p&gt;ghost is MCP/CLI only. your agent discovers it the same way it discovers any other tool, through MCP, and starts provisioning databases immediately. CLI works too, if that's more your speed. and because every ghost database is just postgres, your agent already knows how to use it. every LLM has postgres in the weights. schema design, queries, indexes, debugging. no proprietary query language. no SDK to learn. just SQL.&lt;/p&gt;

&lt;p&gt;ghost does one thing and does it well. but because it's postgres, it pairs naturally with other tools that extend what your agent can do.&lt;/p&gt;

&lt;h2&gt;
  
  
  extend ghost with purpose-built tools
&lt;/h2&gt;

&lt;p&gt;ghost gives your agent a database. that alone gets you pretty far. but agents need more than storage. they need memory, search, files, and safe execution. here's what plugs into ghost:&lt;/p&gt;

&lt;h2&gt;
  
  
  memory engine: persistent, temporal agent memory
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;pairs with ghost. works with any postgres.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;your agent forgets everything between sessions. you've probably already tried to solve that with a vector database or a standalone memory service.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://memory.build" rel="noopener noreferrer"&gt;memory engine&lt;/a&gt; solves this inside postgres. when you pair it with ghost, your agent's memory and data live in the ghost space. y you can query memories with SQL. you can ask "what did this agent know about this user at 3pm on tuesday?" and get an answer, because memory engine understands time natively.&lt;/p&gt;

&lt;p&gt;no separate vector database. no syncing between systems. no second bill. just postgres doing what postgres is good at.&lt;/p&gt;

&lt;p&gt;the temporal part matters more than it sounds. most memory solutions treat memory like a flat store. things go in, things come out. memory engine tracks when things were true. when facts changed. when old information got superseded by new information. this is how human memory works and it's how agent memory should work too.&lt;/p&gt;

&lt;p&gt;it's not just temporal either. memory engine lets your agent search its memory with keyword, semantic, faceted, and hierarchical search in the same query. under the hood, retrieval is powered by &lt;a href="https://github.com/timescale/pg_textsearch" rel="noopener noreferrer"&gt;pg_textsearch&lt;/a&gt;, which combines BM25 for keyword precision with pgvector for semantic similarity. pg_textsearch also ships with every ghost database, so you get full-text search out of the box even if you're not using memory engine. no elasticsearch sidecar. no separate search cluster to sync and monitor.&lt;/p&gt;

&lt;h2&gt;
  
  
  tigerfs: a filesystem backed by postgres
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;pairs with ghost. works with any postgres.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;agents create files constantly. reports, code, datasets, images, logs. most of that output ends up in s3, unstructured and impossible to query. &lt;a href="https://tigerfs.io" rel="noopener noreferrer"&gt;tigerfs&lt;/a&gt; gives your agent a filesystem backed by postgres, so files become first-class data. transactions on writes, concurrent access from multiple agents, and metadata you can actually query.&lt;/p&gt;

&lt;p&gt;two agents working on the same project both need to write files. tigerfs handles that without corruption. s3 doesn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  search: vector, keyword, and hybrid search built into postgres
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;pairs with ghost. works with any postgres.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;every ghost database ships with &lt;a href="https://github.com/timescale/pg_textsearch" rel="noopener noreferrer"&gt;pg_textsearch&lt;/a&gt; and &lt;a href="https://github.com/timescale/pgvectorscale" rel="noopener noreferrer"&gt;pgvectorscale&lt;/a&gt;. that gives you BM25 keyword search, vector semantic search, and hybrid search combining both. no elasticsearch. no pinecone. no separate system to sync.&lt;/p&gt;

&lt;p&gt;you don't need to know how to set any of this up. ghost MCP includes skills that teach your agent how to configure search indexes, choose between keyword and semantic approaches, and wire up hybrid search with reciprocal rank fusion. tell your agent you need search on a table and it handles the rest.&lt;/p&gt;

&lt;p&gt;this is also what powers memory engine's retrieval. when your agent searches its memories, it's using hybrid search under the hood: BM25 for keyword precision, pgvector for semantic similarity, combined and ranked. all inside postgres.&lt;/p&gt;

&lt;h2&gt;
  
  
  ox: sandboxed execution with full context
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;pairs with ghost. works with any postgres.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;agents need to run code. &lt;a href="https://ox.build" rel="noopener noreferrer"&gt;ox&lt;/a&gt; gives them a sandboxed execution environment that's connected to their data but quarantined from their main branch. when paired with ghost, an ox sandbox can query the agent's database and read its tigerfs files directly. no API hops. no extra auth.&lt;/p&gt;

&lt;p&gt;this is the difference between a sandbox and a workspace. your agent doesn't just execute code in isolation. it executes code in the context of everything it knows.&lt;/p&gt;

&lt;h2&gt;
  
  
  how people are building with ghost
&lt;/h2&gt;

&lt;p&gt;ghost was in private preview for the past two months. here are some of the things beta testers built.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;the code review agent&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;the agent picks up a PR. it forks its ghost database to get a clean copy of the current state. it spins up an ox sandbox, runs the test suite against the fork, and checks for regressions. it searches memory engine for past reviews on the same files. what broke last time. what patterns the team prefers. what feedback the author got previously. it writes its review, stores the results in tigerfs, and updates its memory with what it learned.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;the research agent&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;the agent spins up a ghost database to store everything it finds. company profiles, product comparisons, pricing data. it writes raw reports to tigerfs as markdown files. it checks memory engine: have we researched this company before? what did we find last time? what changed? when it needs to crunch numbers, it forks the database into an ox sandbox so it can run analysis without touching the original data. when it's done, it stores what it learned with full temporal context. next quarter, the agent knows what the landscape looked like this quarter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;the multi-agent team&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;three agents, one project. one writes code. one writes docs. one runs tests. all three read and write files through tigerfs without stepping on each other. all three check memory engine so they don't duplicate work. all three get their own ox sandbox that can still query the shared ghost database. they share a substrate without sharing a failure mode.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;the data exploration agent&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;a user asks "what would our metrics look like if we changed the pricing model?" the agent forks the ghost database. rewrites the pricing logic on the fork. reruns three months of transactions against the new model in an ox sandbox. doesn't like the result. forks again with a different model. runs it again. the user gets three scenarios in ten minutes. all run against real data. none of them touching production.&lt;/p&gt;

&lt;h2&gt;
  
  
  all on postgres
&lt;/h2&gt;

&lt;p&gt;we are proud members of the postgres fan club. here's why we build on it:&lt;/p&gt;

&lt;p&gt;postgres is battle-tested. it's been in production for 30+ years. it handles transactions, concurrent access, replication, and failure recovery. when your agent's infrastructure needs to be reliable, you want it built on something boring.&lt;/p&gt;

&lt;p&gt;one substrate means zero glue code. when your database, memory, search, and files all run on postgres, they share the same transaction model, the same auth, the same query language. the integration layer doesn't exist because it doesn't need to.&lt;/p&gt;

&lt;p&gt;we've been building on postgres for years. before ghost, we built timescaledb, one of the most widely-used postgres extensions for time-series data. memory engine's temporal capabilities come directly from that work. we're applying a decade of postgres engineering to a new problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  get started
&lt;/h2&gt;

&lt;p&gt;ghost is in early access. install it with the comment below. run &lt;code&gt;ghost mcp install&lt;/code&gt; directly in claude code, and let your agents cook.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://install.ghost.build | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the full toolkit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://ghost.build" rel="noopener noreferrer"&gt;ghost&lt;/a&gt; → instant, ephemeral postgres databases for agents&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://memory.build" rel="noopener noreferrer"&gt;memory engine&lt;/a&gt; → persistent, temporal agent memory&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/timescale/pg_textsearch" rel="noopener noreferrer"&gt;pg_textsearch&lt;/a&gt; → BM25 + keyword search for postgres&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://tigerfs.io" rel="noopener noreferrer"&gt;tigerfs&lt;/a&gt; → postgres-backed file storage&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ox.build" rel="noopener noreferrer"&gt;ox&lt;/a&gt; → sandboxed execution, connected to your data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;everything is postgres. everything is MCP-native. each one works on its own. they're better together.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>postgres</category>
      <category>agents</category>
    </item>
  </channel>
</rss>
