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-cliorcargo install hatidata-cli) - A local HatiData environment running (
hati initcompleted) - 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:
- Navigate to Environments and click Create Environment.
- Choose a region (us-east-1, eu-west-1, or ap-southeast-1).
- Name your environment (e.g.,
my-project-prod). - Note the cloud endpoint displayed after creation (e.g.,
my-project-prod.hatidata.com).
Generate a production API key:
- Navigate to Settings > API Keys.
- Click Create Key, select the
read-writescope, and set an expiration. - 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:
- Flushes all local tables to Parquet snapshots.
- Uploads the Parquet files to the cloud environment's backing store (S3/GCS).
- Recreates the schema and table definitions in the cloud proxy.
- Loads the data from Parquet into the cloud DuckDB instance.
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:
| Feature | Included |
|---|---|
| Managed proxy with TLS | Yes |
| S3/GCS-backed durability | Yes |
| Dashboard access | Yes |
| API keys and RBAC | Yes |
| Monthly query quota | 100,000 queries |
| Storage | 10 GB |
| Support | Email (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
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.