Skip to main content

Local to Cloud Migration

HatiData is designed so you develop locally and deploy to the cloud when you are ready. This guide walks through the complete migration from a local hati init environment to a managed HatiData Cloud instance.

Overview

Local Development                    HatiData Cloud
┌──────────────────┐ ┌──────────────────────┐
│ hatidata-proxy │ hati push │ Managed proxy │
│ localhost:5439 │ ────────────> │ your-env.hatidata.com│
│ DuckDB on disk │ │ DuckDB + S3 backing │
│ No TLS │ │ TLS enforced │
│ Dev API key │ │ Production API keys │
└──────────────────┘ └──────────────────────┘

What transfers: Tables, schemas, data (Parquet snapshots), and schema definitions.

What does not transfer: Agent memory entries, chain-of-thought traces, and semantic triggers. These are per-proxy runtime state and must be re-seeded in the cloud environment (see Re-seeding Agent State below).


Prerequisites

  • HatiData CLI installed (pip install hatidata-cli or cargo install hatidata-cli)
  • A local HatiData environment running (hati init completed)
  • A HatiData Cloud account at app.hatidata.com (Cloud tier, $29/month)

Step 1: Initialize Your Local Environment

If you have not already, create a local environment:

hati init my-project
cd my-project

This creates a local DuckDB-backed environment with a proxy on localhost:5439. You can connect with any Postgres client:

psql -h localhost -p 5439 -U admin -d my-project

Create tables and load data as you normally would:

CREATE TABLE analytics.events (
id INTEGER,
event_type VARCHAR,
payload JSON,
created_at TIMESTAMP
);

INSERT INTO analytics.events VALUES
(1, 'page_view', '{"url": "/home"}', '2025-01-15 10:30:00'),
(2, 'click', '{"button": "signup"}', '2025-01-15 10:31:00');

Step 2: Develop and Test Locally

Work with your data using SQL, the Python SDK, MCP tools, or any Postgres-compatible driver. All queries go through the full pipeline (transpilation, access control, audit logging), so behavior in local and cloud environments is identical.

from hatidata import Client

client = Client(host="localhost", port=5439, api_key="dev")
result = client.query("SELECT COUNT(*) FROM analytics.events")
print(result)

When you are satisfied with your schema and data, proceed to push.


Step 3: Create a Cloud Environment

Log into the HatiData Dashboard and create a new environment:

  1. Navigate to Environments and click Create Environment.
  2. Choose a region (us-east-1, eu-west-1, or ap-southeast-1).
  3. Name your environment (e.g., my-project-prod).
  4. Note the cloud endpoint displayed after creation (e.g., my-project-prod.hatidata.com).

Generate a production API key:

  1. Navigate to Settings > API Keys.
  2. Click Create Key, select the read-write scope, and set an expiration.
  3. Copy the key immediately -- it is only shown once.

Step 4: Push to Cloud

Authenticate the CLI with your cloud credentials:

hati auth login

Push your local environment to the cloud target:

hati push --target cloud --env my-project-prod

This command:

  1. Flushes all local tables to Parquet snapshots.
  2. Uploads the Parquet files to the cloud environment's backing store (S3/GCS).
  3. Recreates the schema and table definitions in the cloud proxy.
  4. Loads the data from Parquet into the cloud DuckDB instance.
info

The push transfers data and schemas only. Agent-specific state (memory, CoT traces, triggers, branches) is not included because it is tied to the proxy runtime. See Re-seeding Agent State below.

Monitor the push progress:

hati push --target cloud --env my-project-prod --verbose
# [1/4] Flushing local tables to Parquet...
# [2/4] Uploading 3 Parquet files (12.4 MB)...
# [3/4] Creating schemas in cloud environment...
# [4/4] Loading data into cloud DuckDB...
# Push complete. 3 tables transferred.

Step 5: Update Connection Strings

psql

# Before (local)
psql -h localhost -p 5439 -U admin -d my-project

# After (cloud)
psql "host=my-project-prod.hatidata.com port=5439 user=admin password=hd_live_... dbname=my-project-prod sslmode=require"

Python SDK

# Before (local)
client = Client(host="localhost", port=5439, api_key="dev")

# After (cloud)
client = Client(
host="my-project-prod.hatidata.com",
port=5439,
api_key="hd_live_...",
ssl=True, # TLS is enforced in cloud
)

TypeScript SDK

// Before (local)
const client = new HatiDataClient({
host: "localhost",
port: 5439,
apiKey: "dev",
});

// After (cloud)
const client = new HatiDataClient({
host: "my-project-prod.hatidata.com",
port: 5439,
apiKey: "hd_live_...",
ssl: true,
});

MCP Configuration

{
"mcpServers": {
"hatidata": {
"url": "https://my-project-prod.hatidata.com/mcp",
"headers": {
"ApiKey": "hd_live_..."
}
}
}
}

Step 6: Verify the Migration

Run a quick smoke test against the cloud endpoint:

psql "host=my-project-prod.hatidata.com port=5439 user=admin password=hd_live_... dbname=my-project-prod sslmode=require" \
-c "SELECT COUNT(*) FROM analytics.events;"

Check the dashboard at app.hatidata.com to confirm:

  • All tables appear under your environment.
  • Row counts match your local environment.
  • The query log shows your verification query.

Re-seeding Agent State

Agent memory, chain-of-thought traces, and semantic triggers are runtime state managed by the proxy. They are not transferred during hati push because they are scoped to the proxy instance and may reference local-only context.

Memory

Re-seed memory by replaying the store_memory MCP tool calls against the cloud endpoint, or insert directly via SQL:

INSERT INTO _hatidata_memory (agent_id, content, metadata, created_at)
VALUES
('support-bot', 'Customer prefers email contact', '{"category": "preference"}', NOW()),
('support-bot', 'Account upgraded to Pro tier on Jan 10', '{"category": "event"}', NOW());

Semantic Triggers

Re-register triggers using the MCP register_trigger tool pointed at the cloud endpoint:

import requests

response = requests.post(
"https://my-project-prod.hatidata.com/mcp",
headers={"ApiKey": "hd_live_...", "Content-Type": "application/json"},
json={
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "register_trigger",
"arguments": {
"name": "high-value-order",
"concept": "order total exceeds $10,000",
"threshold": 0.85,
"action": {"type": "FlagForReview"}
}
},
"id": 1
},
)
print(response.json())

Chain-of-Thought Traces

CoT traces are append-only audit records and are generally not migrated. If you need historical traces in cloud for compliance, export them from local:

hati export --table _hatidata_cot --format parquet --output cot_traces.parquet
hati import --env my-project-prod --file cot_traces.parquet --table _hatidata_cot

Pricing

The HatiData Cloud tier is $29/month and includes:

FeatureIncluded
Managed proxy with TLSYes
S3/GCS-backed durabilityYes
Dashboard accessYes
API keys and RBACYes
Monthly query quota100,000 queries
Storage10 GB
SupportEmail (48-hour SLA)

For higher quotas, dedicated infrastructure, or PrivateLink connectivity, see the Enterprise tier.


Keeping Local and Cloud in Sync

During active development, you may want to push updates regularly:

# Push only changed tables (incremental)
hati push --target cloud --env my-project-prod --incremental

# Push a specific table
hati push --target cloud --env my-project-prod --table analytics.events

# Pull cloud data back to local (for debugging)
hati pull --source cloud --env my-project-prod
warning

hati push overwrites the cloud tables with local data. If other agents have written to the cloud environment since your last push, those writes will be lost. Use --incremental to append only new data, or coordinate pushes through your deployment pipeline.

Stay in the loop

Product updates, engineering deep-dives, and agent-native insights. No spam.