Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules/
11 changes: 6 additions & 5 deletions architecture.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ title: "Architecture"
description: "How Ardent's split-plane architecture keeps your data safe and your branches fast"
---

Ardent follows a split-plane architecture where the **control plane** and **data plane** are separated:
Ardent follows a split-plane architecture like databricks where the **control plane** and **data plane** are separated:

- **Control plane:** Operated by Ardent. Handles branch orchestration, replication health monitoring, connection routing, auto-scaling, and policy enforcement. Spans across all deployments.
- **Data plane:** Where your data lives. The Ardent Replicator syncs from your production database via a Kafka pipeline into a read replica. **Branches** are isolated Postgres databases created from that replica, each with **auto-scaling compute** and its own storage.
- **Data plane:** Where your data lives. Includes the ardent replicator, kafka, your read replica, cloned databases and more. Can be deployed on your cloud or ours.

Only metadata (schema structure, replication status, branch state) flows from the data plane to the control plane. Your actual data never leaves the data plane.

Expand All @@ -18,6 +18,7 @@ flowchart TB
subgraph CP["Control plane"]
direction TB
ORCH["Branch orchestration"]
PRXY["Branch proxy"]
ROUTE["Connection routing"]
HEALTH["Health and WAL monitoring"]
POL["Policies and auth"]
Expand All @@ -37,7 +38,7 @@ flowchart TB

Always operated by Ardent. Orchestration, policies, routing, and visibility across every branch and connection.

- **Branch lifecycle:** Create, suspend, delete, and route traffic to the right branch. Connection URLs go through Ardent so every session is tied to an account and can enforce rules, hooks, and policies.
- **Branch lifecycle:** Create, suspend, delete, and route traffic to the right branch. Connection URLs go through Ardent's proxy so every session is tied to an account and can enforce rules, hooks, and policies as well as prevent leakage of raw URLs for safety.
- **Replication coordination:** Monitors health, lag, and pipeline status from metadata; scales and manages the Kafka layer that backs replication so you are not sizing or operating brokers yourself.
- **Connector setup:** Discovery and validation when you connect a database, plus connector-scoped settings such as default database and branch SQL hooks.
- **Auth, usage, and billing:** Org access, API keys, and metering. Per-user and per-branch visibility Postgres does not give you out of the box.
Expand All @@ -53,8 +54,8 @@ Where your data physically lives and where branches are served from. Runs on Ard
- Manages WAL and slot pressure so replication does not destabilize the primary.
- Quarantines, resumes, and recovers broken streams without manual replay scripts.
- **Read replica:** Stays in sync with production; branches are always created from the replica, never from production directly, so branch load never hits your primary.
- **Branches (compute and storage):** Each branch is a full Postgres instance with **compute that auto-scales with load**. Storage is built on the same replica snapshot so new branches stay fast to create at any data size and stay inexpensive when idle, while queries and connections run on elastic branch compute.
- **Isolation:** Your table data stays inside this boundary. Only metadata crosses to the control plane.
- **Branches (compute and storage):** Each branch is a full Postgres instance with **compute that auto-scales with load**. Branches share storage from the same replica through copy-on-write, so scaling to many branches is efficient for both compute and storage. Queries and connections run independently on autoscaling branch compute.
- **Isolation:** Your data stays inside this boundary. Only metadata crosses to the control plane. This means in a BYOC model you can maintain residency of all your data without losing Ardent's ability to manage the service

You connect your database and open branches. The control plane orchestrates; the data plane runs replication, the replica, and branches.

Expand Down
76 changes: 39 additions & 37 deletions index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -24,41 +24,46 @@ An instant database for every task.
</Card>
</CardGroup>

## Start making Database copies in just 4 commands

<Steps>
<Step title="Install the CLI">
```bash
npm install -g ardent-cli
```
</Step>
<Step title="Log in">
```bash
ardent login
```
</Step>
<Step title="Connect your database">
```bash
ardent connector create postgresql '<your-connection-string>'
```
Use single quotes around the URL so characters like `?`, `&`, or `$` in the string are not mangled by the shell.
</Step>
<Step title="Create a branch">
```bash
ardent branch create my-feature
```
</Step>
</Steps>

That's it. You can make full, isolated copies of your database — ready in under 6 seconds regardless of data size.

**Rather have Claude set this up?** Copy this into Claude Code or Cursor:
## Get started

<Card title="Quickstart" icon="rocket" href="/quickstart" horizontal>
Up and running in 4 commands. Takes about 2 minutes.
</Card>

**Or have Claude walk you through it.** Paste this into Claude Code or Cursor:

```
I want to set up Ardent for database branching.
Install ardent-cli, log in, connect my Postgres database
[paste connection string here], and create my first branch.
Docs: https://docs.tryardent.com
Set up Ardent for database branching. Act like a teammate at my keyboard:
run the commands yourself, stop only when you need me to do something
only I can do (browser sign-up, paste a credential). Before each step,
give me one short line on what's happening and why — process guidance,
not a recap afterward.

Run these in order:

1. Install the CLI: npm install -g ardent-cli

2. ardent login → opens a browser to authenticate. Tell me to finish
sign-up or login and ping you when done.

3. Tell me to export my Postgres connection string in this shell so
Ardent can connect to my database and start replicating it for
branching:
export ARDENT_DB_URL='postgres://...'
Then run:
ardent connector create postgresql "$ARDENT_DB_URL"
(a project gets auto-created here)

4. ardent branch create my-feature → spins up an isolated copy of my
database I can use however I want without touching prod.

5. ardent branch info → give me the connection URL. That URL is my
isolated branch — I connect to it like any Postgres database.

Skip the after-the-fact recap. Hand me the URL at the end. If a command
errors, fix it.

Docs: https://docs.tryardent.com/quickstart
```

## How it works
Expand All @@ -84,10 +89,7 @@ Create as many as you need, throw them away when you're done without worrying.

## Next steps

<CardGroup cols={2}>
<Card title="Quickstart" icon="rocket" href="/quickstart">
Up and running in 3 commands.
</Card>
<CardGroup cols={3}>
<Card title="Connectors" icon="plug" href="/connectors/supabase">
Supabase, RDS, PlanetScale, and self-hosted Postgres.
</Card>
Expand Down
16 changes: 8 additions & 8 deletions security.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,21 @@ description: "How Ardent keeps your data safe"

Ardent is designed to never put your production data at risk. Here's how.

## Production is read-only
## Minimal production footprint

Ardent uses logical replication to sync your data — it only reads from your production database. It never writes to it or modifies it.
Ardent uses logical replication to sync your table data and does not write to your application tables. During connector setup, Ardent creates one dedicated schema for its own metadata and installs DDL event triggers there so schema changes can be detected and replayed in order on the replica.

## Credentials are never exposed
This has little to no performance impact on production. Normal application reads and writes continue against your database as usual.

Every branch gets its own generated connection string. Your real database credentials are never shared — not with agents, not with team members, not with Ardent itself.
## Encryption and secrets

If a branch URL is ever compromised, it has zero access to your original database. This makes it safe to hand branch URLs to AI agents like Claude Code or Cursor without worrying about your production credentials leaking.
Ardent encrypts source database credentials, API keys, and connection secrets at rest. Replication components read credentials only at runtime when they need to connect.

Branches are controlled through Ardent's connection layer, so you can delete or de-provision them at any time.
With **BYOC (bring your own cloud)**, secrets live in your own infrastructure (for example AWS SSM Parameter Store). Ardent reads them directly from your secret store at runtime, and your credentials never leave your network.

## All secrets are encrypted
Every branch gets its own generated connection string. If a branch URL is ever compromised, it has zero access to your original database. This makes it safe to hand branch URLs to AI agents like Claude Code or Cursor without leaking your source database credentials.

All secrets (connection strings, credentials, API keys) are encrypted at rest. Nothing is stored unencrypted. In **managed, your cloud** deployments, secrets live in your own infrastructure (for example AWS SSM Parameter Store). Ardent reads them at runtime but never persists your credentials on Ardent infrastructure.
Branches are controlled through Ardent's control plane, so you can delete or de-provision them at any time.

## Branch anonymization

Expand Down
146 changes: 123 additions & 23 deletions workflows/ci-cd.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,138 @@ description: "A fresh database for every PR. Isolated, production-like, torn dow

Every PR gets its own fresh database cloned from production, torn down after merge. No shared staging that drifts out of sync. No test runs that corrupt each other.

## GitHub Actions example
## Have Claude set this up

The CLI needs to authenticate before running any commands. In CI, use `ardent login --token` with a token stored in your repo secrets. This creates a local session the same way `ardent login` does interactively.
Paste this into Claude Code or Cursor and it will walk you through the whole thing:

After login, create the branch. The CLI doesn't expose the URL as a structured output yet, so grab it from `ardent branch info` and append it to `GITHUB_ENV` so later steps (npm, pytest, your migration runner) see `DATABASE_URL`.
```
Set up Ardent branching in our GitHub Actions CI. Act like a teammate
at my keyboard: write the workflow yourself, only stop when you need
me to do browser-only steps.

Steps:

1. Tell me to create an API token at
https://app.tryardent.com/app/settings/api-keys and add it as a
repo secret called ARDENT_TOKEN (Settings > Secrets and variables >
Actions). Wait until I confirm both are done.

2. Run `ardent project list` and `ardent connector list` to get my
project and connector names. If I have multiple, ask me which to use.

3. Create .github/workflows/ardent-branch.yml using the template at
https://docs.tryardent.com/workflows/ci-cd, with my project and
connector substituted in. Use `npm test` unless this repo uses
something else (check package.json).

4. Commit on a new branch and open a PR so the workflow runs.

Don't narrate every step. Hand me a working PR at the end. If a step
errors, fix it.
```

Or follow the manual walkthrough below.

## Prerequisites

You need an Ardent account with at least one connector set up. If you haven't done that yet, follow the [Quickstart](/quickstart) first.

## Setup

<Steps>
<Step title="Get your project and connector names">

Run these locally to find the values you'll need for the workflow:

```bash
ardent project list
ardent connector list
```

Note the project name and connector name. You will use these in the workflow to explicitly select which database to branch from.

</Step>

<Step title="Create an API token">

Go to [Ardent dashboard > API keys](https://app.tryardent.com/app/settings/api-keys) and create a token.

</Step>

<Step title="Add the token to GitHub">

In your repo, go to **Settings > Secrets and variables > Actions** and click **New repository secret**. Name it **`ARDENT_TOKEN`** and paste your token.

</Step>

<Step title="Add the workflow file">

Copy the YAML below to `.github/workflows/ardent-branch.yml` in your repo, replacing `my-project` and `my-connector` with your values from step 1.

</Step>
</Steps>

## GitHub Actions workflow

```yaml
- name: Install Ardent CLI
run: npm install -g ardent-cli
name: Test with Ardent branch

on:
pull_request:
types: [opened, synchronize, reopened]

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: "22"

- name: Log in to Ardent
run: ardent login --token ${{ secrets.ARDENT_TOKEN }}
- name: Install dependencies
run: npm ci

- name: Create database branch
run: |
NAME="pr-${{ github.event.pull_request.number }}"
ardent branch create "$NAME"
echo "DATABASE_URL=$(ardent branch info | awk '/URL:/{print $2}')" >> "$GITHUB_ENV"
- name: Install Ardent CLI
run: npm install -g ardent-cli

- name: Run migrations + tests
run: npm test
- name: Log in to Ardent
run: ardent login --token ${{ secrets.ARDENT_TOKEN }}

- name: Delete branch
if: always()
run: ardent branch delete pr-${{ github.event.pull_request.number }}
- name: Select project and connector
run: |
ardent project switch my-project
ardent connector switch my-connector

- name: Create database branch
run: |
BRANCH_NAME="pr-${{ github.event.pull_request.number }}-${{ github.run_id }}"
ardent branch create "$BRANCH_NAME"
echo "DATABASE_URL=$(ardent branch info | awk '/URL:/{print $2}')" >> "$GITHUB_ENV"
echo "ARDENT_BRANCH=$BRANCH_NAME" >> "$GITHUB_ENV"

- name: Run tests
run: npm test

- name: Delete database branch
if: always()
run: ardent branch delete "$ARDENT_BRANCH"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Branch cleanup fragile due to env var ordering

Low Severity

The ARDENT_BRANCH write to GITHUB_ENV (line 117) comes after the DATABASE_URL extraction (line 116). If the ardent branch info pipeline fails and the step exits early (particularly when shell: bash enables pipefail), the branch is created but ARDENT_BRANCH is never set, so the if: always() cleanup step runs ardent branch delete "" and the branch is orphaned. Writing ARDENT_BRANCH immediately after ardent branch create would ensure cleanup always works.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit d1ed765. Configure here.

```

Use the same `DATABASE_URL` for `pytest`, `pnpm test`, or any tool your repo already uses in CI. If your framework reads a different variable, write that name to `GITHUB_ENV` instead.
**What each step does:**

- **`ardent login --token`** authenticates the CLI using your repo secret.
- **`ardent project switch` / `ardent connector switch`** explicitly selects which project and connector to branch from. A connector represents one Postgres server. Replace `my-project` and `my-connector` with your names. Always set these in CI so the workflow is deterministic.
- **`ardent branch create`** creates an isolated database branch. The name includes the PR number and run ID so concurrent runs and re-runs don't collide.
- **`ardent branch info | awk '/URL:/{print $2}'`** extracts the branch connection URL and writes it to `DATABASE_URL` in `GITHUB_ENV`. Your test step reads `DATABASE_URL` like any other environment variable. If your app uses a different env var name, change it in the `echo` line.
- **`npm test`** runs your test suite against the branch. Replace with `pytest`, `pnpm test`, `make test`, or whatever your project uses.
- **`ardent branch delete`** cleans up the branch. `if: always()` ensures this runs even when tests fail.

## Why this beats a shared staging database
## Compared to a shared staging database

- **Isolation:** each PR can't interfere with other test runs
- **Always in sync:** branched from production, no drift
- **No idle cost:** branches auto-suspend between CI runs
- **Auto cleanup:** `if: always()` means no orphaned environments
- **Full production data:** branches are not schema-only copies. You test against the same data at the same scale, so if something would blow up in production, it blows up here first.
- **Isolation:** each PR gets its own branch. No test run can interfere with another.
- **Efficient at scale:** compute auto-scales per branch and storage is shared across branches, so spinning up many ephemeral environments stays cheap.
- **Always in sync:** branches are created from a continuously synced replica. No drift.
- **Auto cleanup:** `if: always()` deletes the branch after the run. No orphaned environments.