---
title: "Deployment Modes"
---

# Deployment Modes


This is the canonical page for how a HeliosDB Nano process is deployed. Two
decisions are independent of each other, and mixing them up is the single most
common source of confusion:

1. **Storage mode** — where the data lives: **persistent** (a data directory on
   disk) or **in-memory** (RAM only).
2. **Access mode** — how callers reach the engine: **embedded library API**,
   **interactive REPL**, **foreground server**, or **background daemon**.

Every combination of the two is valid. "Embedded" is an access mode, not a
storage mode; "in-memory" is a storage mode, not an access mode.

---

## Storage modes

### Persistent

Data is written to a data directory and survives process restart. The local
crash-recovery write-ahead log is always on.

```bash
heliosdb-nano repl --data-dir ./my-data
heliosdb-nano start --data-dir ./my-data --port 5432
```

```rust
use heliosdb_nano::EmbeddedDatabase;

let db = EmbeddedDatabase::new("./my-data")?;
```

`heliosdb-nano start` requires either `--data-dir` or `--memory`; `repl`
defaults to `./heliosdb-data`.

### In-memory

Data lives in RAM and is discarded when the process exits.

```bash
heliosdb-nano repl --memory
heliosdb-nano start --memory --port 5432
```

```rust
let db = EmbeddedDatabase::new_in_memory()?;
```

Add `--dump-on-shutdown` (CLI only) to write a dump on a *graceful* exit —
`heliosdb-nano repl --memory --dump-on-shutdown --dump-file ./snapshot.heliodump`.
An abrupt kill still loses everything: in-memory storage is not a durability
mechanism.

Use in-memory for tests, CI, and short-lived transforms. Use persistent storage
for anything whose loss would matter.

---

## Access modes

### 1. Embedded library API (in-process)

The engine runs inside your process, with no network listener and no separate
server to manage — the SQLite-style deployment.

```rust
use heliosdb_nano::EmbeddedDatabase;

let db = EmbeddedDatabase::new("./my-data")?;
db.execute("CREATE TABLE users (id BIGSERIAL PRIMARY KEY, name TEXT)")?;
```

A Python binding for this same in-process engine is published as
`heliosdb-nano-embedded` (`pip install heliosdb-nano-embedded`, then
`import heliosdb_nano`). It is released separately and can lag the engine release; check PyPI
for the published version.

- Best for: desktop and mobile apps, edge devices, CLI tools, single-process
  services, test harnesses.
- No network listener, no authentication layer, no per-connection sessions.
- Concurrent reads and single-statement autocommit writes are supported;
  **independent overlapping explicit transactions are not** — see
  [Concurrency and transactions](https://www.heliosdb.com/docs/nano/guides/concurrency-and-transactions/) before you
  share one handle between threads.

### 2. Interactive REPL

A single-user interactive SQL shell over the same in-process engine.

```bash
heliosdb-nano repl --data-dir ./my-data
heliosdb-nano repl --memory
```

- Best for: schema work, ad-hoc queries, inspecting a data directory, learning.
- REPL meta commands (`\d`, `\dt`, `\branches`, `\use`, `\stats`) are available
  here and not over the wire protocols.
- Single process, single user, no network access.

### 3. Foreground server

A PostgreSQL-wire server that stays attached to the terminal and logs to stdout.

```bash
heliosdb-nano start --data-dir ./my-data --port 5432 --listen 127.0.0.1
```

Connect with any PostgreSQL client:

```bash
psql -h 127.0.0.1 -p 5432
```

- Best for: development, protocol debugging, watching server output live.
- Multiple clients; **each connection gets its own session and its own
  transaction state**, which is the supported way to run independent
  transactions today.
- Optional listeners on the same process: `--mysql` (MySQL wire),
  `--pg-socket-dir <dir>` (Unix-domain socket at `<dir>/.s.PGSQL.<port>`),
  `--http-port` (health/HTTP API).

### 4. Background daemon

The same server, detached, with a PID file for process management.

```bash
heliosdb-nano start --daemon \
  --data-dir ./my-data \
  --port 5432 \
  --pid-file ./heliosdb.pid

heliosdb-nano status --pid-file ./heliosdb.pid
heliosdb-nano stop --pid-file ./heliosdb.pid
```

- Best for: long-running deployments, containers, service managers.
- Identical engine and connection semantics to the foreground server; the
  difference is process lifecycle, not capability.

---

## Choosing

| Requirement | Access mode |
|---|---|
| Ship the database inside the application binary | Embedded library API |
| Explore or administer a data directory by hand | Interactive REPL |
| Several clients, or clients in another language/host | Foreground server or daemon |
| Independent overlapping explicit transactions | Server or daemon (separate connections) |
| Run under systemd / Docker / a supervisor | Background daemon |
| Throwaway state for a test run | Any access mode + in-memory storage |

| Requirement | Storage mode |
|---|---|
| Data must survive restart | Persistent |
| Reproducible, isolated test fixtures | In-memory |
| Fastest possible scratch workspace | In-memory (accepting total loss on exit) |

---

## One process per data directory

A data directory is owned by exactly one running process. Starting a second
process against a directory another process already has open is not supported
and surfaces as lock errors (`database is locked`) — see
[Troubleshooting](https://www.heliosdb.com/docs/nano/user_adoption_guide/#troubleshooting).

This has three practical consequences:

- **Modes are chosen at open/start time.** There is no live switch between
  embedded and server access.
- **Moving from embedded to server is a stop-then-start handoff.** Stop the
  embedded process, start the server against the same data directory, then
  repoint the application at a PostgreSQL client. Keep the engine version
  identical across the switch — combine one change at a time.
- **Two processes cannot share one dataset.** If more than one process needs
  the same data, one of them must be the server and the rest must be clients.

## Running a server and a REPL at the same time ("hybrid")

Running a daemon and a REPL side by side is a genuinely useful development
setup — but it is **two independent processes with two separate data
directories**, not shared access to one dataset:

```bash
# Terminal 1 — server, its own data directory
heliosdb-nano start --daemon \
  --data-dir ./server-data \
  --port 5432 \
  --pid-file ./heliosdb.pid

# Terminal 2 — REPL, a DIFFERENT data directory
heliosdb-nano repl --data-dir ./scratch-data
```

Writes made in the REPL are **not** visible to clients of the server, and vice
versa. The two processes share nothing. To inspect the server's data
interactively, connect to the server with `psql` instead of opening a second
process against its directory.

---

## Authentication and network exposure

- `--auth` accepts `trust`, `password`, `md5`, `scram-sha-256`; the default is
  `trust`.
- Any method other than `trust` requires `--password`.
- `trust` is **refused on a non-loopback listener** — binding to anything other
  than `127.0.0.1`/`::1` requires a real authentication method.
- TLS: `--tls-cert` and `--tls-key` must be supplied together.
- `--max-connections` (default 100) caps concurrent client connections.

```bash
heliosdb-nano start --daemon \
  --data-dir /var/lib/heliosdb \
  --listen 0.0.0.0 --port 5432 \
  --auth scram-sha-256 --password "$HELIOSDB_PASSWORD" \
  --tls-cert /etc/heliosdb/cert.pem --tls-key /etc/heliosdb/key.pem \
  --pid-file /run/heliosdb.pid
```

---

## Configuration file

Server-mode settings can come from a TOML file instead of flags:

```bash
heliosdb-nano start --config heliosdb.toml
```

```toml
[storage]
path = "/var/lib/heliosdb"
memory_only = false
cache_size = 536870912      # bytes
compression = "zstd"
wal_enabled = true

[server]
listen_addr = "127.0.0.1"
port = 5432
max_connections = 100
tls_enabled = false
# tls_cert_path = "/etc/heliosdb/cert.pem"
# tls_key_path = "/etc/heliosdb/key.pem"

[performance]
worker_threads = 8
simd_enabled = true
parallel_query = true
query_timeout_secs = 300

[encryption]
enabled = false
algorithm = "Aes256Gcm"
key_source = { Environment = "HELIOSDB_ENCRYPTION_KEY" }
```

Encryption is compiled in by default but **disabled at runtime by default** and
requires a key source; setting `algorithm` alone does not encrypt anything.

See [Configuration](https://www.heliosdb.com/docs/nano/user-guide/configuration/) for the full key reference.

---

## Feature differences between access modes

| Capability | Embedded / REPL | Server / daemon |
|---|---|---|
| SQL, vector search, branching, time travel | Yes | Yes |
| REPL meta commands (`\d`, `\branches`, …) | REPL only | No |
| Network clients (psql, JDBC, drivers) | No | Yes |
| Per-connection sessions and transactions | No — one process-global transaction slot | Yes, per connection |
| Row-level security / multi-tenancy | Yes (embedded API and REPL) | Embedded API and REPL today; SQL `CREATE POLICY` and enforcement for REST and wire clients are planned |
| Authentication | Not applicable (in-process) | `trust` / `password` / `md5` / `scram-sha-256` |

---

## Backups

Do not treat a copy of a live data directory as a backup. Use the dump/restore
path, which is the supported mechanism:

```bash
heliosdb-nano dump --data-dir ./my-data --output backup.heliodump
heliosdb-nano restore --input backup.heliodump --target ./restored --verify
```

The same operations are available on the embedded API as `dump_full` and
`restore_from_dump`.

---

## Related

- [Concurrency and transactions](https://www.heliosdb.com/docs/nano/guides/concurrency-and-transactions/) — what is and
  is not safe to do from multiple callers
- [Deployment Modes overview](https://www.heliosdb.com/docs/nano/getting-started/deployment/) — the short
  version, for first-time readers
- [Production Deployment](https://www.heliosdb.com/docs/nano/guides/production_deployment/)
- [Migration Guide](https://www.heliosdb.com/docs/nano/guides/migration/) — including the embedded → server transition
