← Blog

Self-Hosted or Managed: FeltDB Doesn’t Make You Configure the Database

Choose who operates your database without rebuilding your application or changing its state model.

Aug 31, 2026 · 8 min read

In the last post, we ran npx create-feltdb and built a real application.

We chose the browser. FeltDB created the application, gave it durable local state, started Studio, and gave us a development environment.

But the browser is only one place an application can live. What if you want the database on your own infrastructure? What if you want FeltDB to operate it for you?

The answer is the same command:

npx create-feltdb

You just choose a different runtime. This time, let’s look at Self-hosted and Managed.

Self-hosted: your infrastructure, without the infrastructure project

Select:

Where should FeltDB run?
  Browser — local-first with durable browser storage
  Node.js — application server or worker
❯ Self-hosted — dedicated FeltDB server
  Managed — FeltDB-hosted persistence, sync, and workloads

That’s the decision. You don’t then get handed a 40-page deployment guide. The generator creates the application and its deployment boundary for you.

A self-hosted application looks like this:

monday/
├── docker-compose.yml
├── Dockerfile
├── Dockerfile.feltdb
├── Dockerfile.studio
├── feltdb/
├── feltdb.config.json
├── feltdb.flow
├── public/
├── src/
├── index.html
├── package.json
├── package-lock.json
├── README.md
└── tsconfig.json

The important files are immediately visible. There’s a Docker Compose configuration, an application image, a FeltDB image, a Studio image, and a volume for the database’s durable data.

The volume is the database

This is one of the details that matters most. Self-hosted FeltDB doesn’t ask you to install a database separately and then connect your application to it. The generated Docker deployment creates the FeltDB service and gives it persistent storage.

Conceptually, the boundary looks like this:

┌─────────────────────────────────────────────┐
│              Your machine / server         │
│                                             │
│  ┌──────────────┐       ┌───────────────┐  │
│  │ Your React   │──────▶│    FeltDB     │  │
│  │ application  │       │   authority   │  │
│  └──────────────┘       └───────┬───────┘  │
│                                 │           │
│                           ┌─────▼─────┐     │
│                           │  Docker   │     │
│                           │  volume   │     │
│                           │  durable  │     │
│                           │   data    │     │
│                           └───────────┘     │
└─────────────────────────────────────────────┘

The generated application is connected to that FeltDB instance. The FeltDB instance is connected to the persistent volume. The data survives container restarts because it is not living only inside the container.

And the developer didn’t have to manually wire any of this together. The generated project is the deployment.

Nothing to configure

You don’t need to:

The generator establishes the boundary. Your application knows where FeltDB is. FeltDB knows where its durable data lives. Docker knows how to run the pieces.

You build the application. That’s the intended experience.

And the application itself doesn’t change

Remember the React application from the previous post? It doesn’t suddenly become a self-hosted application. Your React code still looks like React, your FeltDB collections are still the same collections, and your feltdb.flow is still the database model.

const { data: projectsList } = useCollection(projects);
const { data: tasksList } = useCollection(tasks);

The application doesn’t need to know that its state is now backed by a dedicated FeltDB server. That’s the point of separating the application model from the runtime.

The flow stays with the application

Suppose our application starts with:

collection Task {
  projectId: text
  title: text
  description: text
  status: text
  priority: text
  assignee: text
  createdAt: datetime
  updatedAt: datetime
  index project using hash(projectId)
  index status using hash(status)
  index priority using hash(priority)
}

That’s the application database definition. If the application needs a due date, another collection, or another index, change the flow.

The database definition travels with the application. The runtime determines where that definition is executed. That’s a powerful separation.

Then there is Managed

Now choose:

Where should FeltDB run?
    Browser — local-first with durable browser storage
    Node.js — application server or worker
    Self-hosted — dedicated FeltDB server
  ❯ Managed — FeltDB-hosted persistence, sync, and workloads

This time the generator asks you to sign in:

☁️  Setting up your managed FeltDB account...
Email:
Password:

And then it takes care of the rest. No Docker, server, volume, database host, or infrastructure configuration. FeltDB provisions the managed environment and connects the generated application to it.

The generated .env.local

The managed setup automatically creates the environment configuration needed by the application:

# Generated by create-feltdb managed setup. Do not commit this file.
VITE_FELTDB_MANAGED_URL=https://api.feltdb.com
VITE_FELTDB_MANAGED_APPLICATION_ID=app_xxxxxxxxxxxxxxx
FELTDB_MANAGED_CONTROL_API_KEY=fdb_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
FELTDB_TOKEN=fdb_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx

The important thing isn’t the individual environment variables. It’s what they represent.

The application now has an identity inside a managed FeltDB environment. It knows where FeltDB lives and has the credentials, tenant, application identity, namespace, and environment needed to access it.

The developer didn’t have to manually create any of those pieces.

Your data is now somewhere else

This is the fundamental difference between the two modes. With self-hosted, your data lives on infrastructure you operate. With managed, your data lives in a FeltDB-managed environment.

The application model, collections, flow, and React application don’t fundamentally change. What changes is the operational boundary:

Self-hosted

You
 │
 ├── Application
 ├── FeltDB
 ├── Storage volume
 └── Operations

Managed

Your application
       │
       ▼
   FeltDB Managed
       │
       ├── Persistence
       ├── Synchronization
       └── Workloads

You choose who operates the database. That’s the decision—not whether you have to rebuild the application.

Why have both?

Because developers have different requirements. A company that needs complete control over where its data lives can self-host FeltDB. A startup that wants to move quickly without operating database infrastructure can use Managed FeltDB.

A developer may start with a browser application and later move the durable authority to a server. That’s possible too.

The point is not to force every application into one deployment model. It is to make the state model portable across runtime boundaries.

The database shouldn’t dictate the application

The traditional workflow often starts by choosing infrastructure, configuring the database, configuring the application to talk to it, and then building the application around those constraints.

FeltDB reverses that relationship. You define the application, its state, and its capabilities. Then you choose where that state should live: Browser, Node.js, Self-hosted, or Managed.

The runtime is an implementation boundary around the application state. It isn’t the application itself.

Four runtimes, one idea

We’ve now seen three of the four runtime choices in create-feltdb:

The application model remains recognizable across all four. That’s intentional.

Infrastructure should be a choice, not a prerequisite

Developers shouldn’t have to become database operators just to build an application. But they also shouldn’t be forced into a hosted service when they need control. Those are two sides of the same problem.

Self-hosting should be possible without turning every application into a DevOps project. Managed infrastructure should be possible without turning the application into a vendor-specific rewrite.

FeltDB is designed to sit between those extremes. You choose the operational boundary. FeltDB handles the database boundary.

What happens next?

There is still a lot we haven’t shown. What does the Node.js runtime actually look like? How does FeltDB move from a browser-owned state model to a server authority? What happens when two authorities have state—or when one disappears? How do recovery and synchronization work? What does a managed application look like under production traffic?

Those are different questions. We’ll answer them separately.

For now, the important thing is simpler. Choose Self-hosted, and FeltDB gives you a Docker deployment with persistent storage already connected to your application. Choose Managed, and FeltDB provisions the hosted environment and connects the application automatically.

Same application. Same state model. Same feltdb.flow. Different operational boundary.

The database can live where you need it to live without becoming the thing you have to build first.