Data

Managed Postgres, Redis, full-text search, and object storage, provisioned per project with no external signup.

On this page

A data service in PrimDB is a database, a cache, a search index, or a bucket that the platform runs for you inside one project. You pick the engine, PrimDB provisions it, and the credentials arrive in your app as environment variables. There is no external signup and no second bill.

What managed means here

The split is worth stating plainly, because it tells you who to look at when something goes wrong. A slow query is yours. The process that runs it is ours.

  • We run: provisioning, connection strings, credential rotation, backups, suspend and resume. All of it from the dashboard or over MCP.
  • You keep: your schema, your migrations, your indexes, and the queries your app sends.
  • Databases do not sleep, including on the Free tier. There is no first-request wake-up to design around.

The engines

Five engines can be provisioned per project. You do not have to decide up front. Add one when you have a reason for it.

EngineWhat it isAdd it when
postgresRelational databaseYou need durable state you can query. For almost every project this is the first service.
redisIn-memory key/value storeYou want a cache, a session store, rate-limit counters, or a queue.
meilisearchFull-text searchUsers type words into a box and expect ranked matches back.
storageS3-compatible object storageYou are holding files: uploads, exports, generated images, anything you would regret putting in a table.
clickhouseColumnar analytics databaseYou are aggregating over a lot of rows and the row-oriented shape is fighting you. Platform tier.

How the connection reaches your app

Link a data service to an app and PrimDB injects the connection into that app’s environment. You never copy a connection string by hand for a linked app. Nothing to paste, no second copy of a secret to keep in sync, no stale value left behind after a rotation.

These are the variable names, and they are the only ones you have to read in code.

VariableEngineWhat it holds
DATABASE_URLpostgresFull Postgres connection string, credentials included.
REDIS_URLredisFull Redis connection string.
MEILI_HOSTmeilisearchBase URL of the search service.
MEILI_API_KEYmeilisearchKey your Meilisearch client authenticates with.
S3_ENDPOINTstorageBase URL of the object storage API.
S3_BUCKETstorageBucket to read and write.
S3_ACCESS_KEYstorageAccess key id.
S3_SECRETstorageSecret access key.
S3_REGIONstorageRegion string your S3 client should send.
S3_FORCE_PATH_STYLEstorageWhether the client addresses the bucket as a path segment rather than a hostname prefix.
CLICKHOUSE_URLclickhouseConnection URL for the analytics database.
// Nothing to wire up. These are already in the environment of any app
// the service is linked to.
import postgres from "postgres";
import Redis from "ioredis";

const sql = postgres(process.env.DATABASE_URL!);
const redis = new Redis(process.env.REDIS_URL!);

const users = await sql`select id, email from users limit 10`;
await redis.set("users:last-read", Date.now());

Postgres

Postgres is the service most projects start with. Connections negotiate TLS. Schema, migrations and indexes are yours to run, the same way they would be on any other Postgres.

Extensions

Extensions are enabled per database from a whitelist. The whitelist is short on purpose, and this is all of it.

  • btree_gin — GIN index support for the ordinary scalar types, so one index can cover a mixed predicate.
  • citext — case-insensitive text, which is usually what you wanted for an email column.
  • hstore — key/value pairs in a single column.
  • pg_trgm — trigram matching for fuzzy text and LIKE acceleration.
  • pgcrypto — cryptographic functions inside the database.
  • unaccent — strips accents, which matters more in some languages than others.
  • uuid-ossp — UUID generation.
  • vector — vector columns and similarity search, for embeddings.

Only a project owner can enable one. Any member can see which extensions are already on, which is the thing you actually need when you are working out why a query will not run. Every enable is audited.

Honest note. The whitelist is closed. A schema that depends on an extension outside these eight will not move here unchanged, so it is worth checking that list before you plan a migration.

Redis

Redis is the cache and the scratch space: sessions, rate-limit counters, job queues, pub/sub between processes. The usual rule applies. Put in Redis what you could rebuild, and keep in Postgres what you could not.

Meilisearch is the full-text search engine. It is the step you take when a pg_trgm index has stopped being enough for the search box. You get MEILI_HOST and MEILI_API_KEY in the app environment and talk to it with any Meilisearch client. PrimDB runs the engine. What you index, and how you shape a document, stays your decision.

Object storage

S3-compatible object storage for files. Any S3 client works, so the SDK you already know and the upload code you already wrote carry over. All five storage variables land in the app environment together.

import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";

const s3 = new S3Client({
  endpoint: process.env.S3_ENDPOINT,
  region: process.env.S3_REGION,
  forcePathStyle: process.env.S3_FORCE_PATH_STYLE === "true",
  credentials: {
    accessKeyId: process.env.S3_ACCESS_KEY!,
    secretAccessKey: process.env.S3_SECRET!,
  },
});

await s3.send(
  new PutObjectCommand({
    Bucket: process.env.S3_BUCKET,
    Key: "exports/january.csv",
    Body: csv,
  }),
);

Connecting from your laptop

A connection string is available for reaching the database from outside the platform, so local tooling keeps working: psql, a GUI client, a one-off backfill, an export you need once and never again. Read the service connection from the dashboard or over MCP, then point your tool at it.

# read the connection for the service, then use it locally
psql "postgres://..."

# same string, one-off script, no deploy involved
DATABASE_URL="postgres://..." bun run scripts/backfill.ts

Honest note. An external connection string is a real credential leaving the platform. Prefer linking the service to an app over pasting the string into a file that will outlive your memory of it, and rotate if it ends up somewhere it should not be.

Backups, rotation, suspend

  • Backup: take one on demand, and list the ones you have. Available over MCP too, so an agent can snapshot before it runs something risky.
  • Rotate credentials: issues new credentials for the service. A linked app picks the new values up from its injected environment. Anything holding a copy by hand, a local file, a teammate’s script, a CI secret, has to read the connection again.
  • Suspend and resume: stop a service and start it again later without deleting it.
  • Delete: removes the service. There is no softer version of this one.

Point-in-time recovery is a paid add-on at $8/month. On-demand backups and PITR are not the same purchase: a backup is a moment you chose in advance, PITR is what you want when the moment you care about is the one nobody thought to pick. Extra storage is $0.02/GB. See Costs for the rest of the bill.

Honest note. Credentials at rest. Connection strings, data-service credentials and your project’s environment variables are sealed under a key generated per secret, and that key is itself wrapped by two independent keys. Leaking one of them does not open anything: recovering a secret needs both.

What an agent can do with your data

The control operations are the same set in both places, dashboard and MCP. An agent holding a project token can:

  • Create a data service, and delete one.
  • Link a service to an app, and unlink it.
  • Read a service connection.
  • List extensions and enable one.
  • Take a backup, and list backups.
  • Rotate credentials.
  • Suspend a service, and resume it.

On top of that there are data-plane tools: query_sql and list_tables against Postgres, redis_get / redis_set / redis_del / redis_keys against Redis, and storage_list / storage_get_url / storage_put_text / storage_delete against object storage.

Every one of those calls is scoped to the project the token is bound to. A token cannot reach another project’s tables, keys or bucket, so the blast radius of handing one to an agent is one project and no more. See MCP.

Honest note. Honest limits. The extension whitelist is closed and only an owner can enable from it. ClickHouse is Platform tier. Point-in-time recovery and extra storage are paid lines on top of your plan. Everything else on this page, including a database that does not sleep on the Free tier, is included.

View as Markdown