# Databases

Managed PostgreSQL and MySQL. A database is created, then provisioned; shared tiers are ready in seconds, dedicated ones take 10-20 minutes.

With an [API key](/reference/api/authentication) the organisation is inferred. Session tokens must add `targetOrganisationId` to every body.

## List databases

```endpoint
POST /api/databases
> Databases in the organisation, newest first, paginated.
permission: read:projects

param page | number | 1 | 1-based page number
param limit | number | 10 | Between 1 and 100
param filter | string | optional | Free text, matched against the name
param sortColumn | string | created_at | Field to order by
param sortOrder | string | desc | asc or desc
param targetOrganisationId | string | session only | Required when using a session token

response 200 | Paginated envelope
{
  "items": [
    {
      "id": "db_2Vx",
      "name": "shop-orders",
      "database_type": "postgresql",
      "tier": "db-f1-micro",
      "region": "europe-west1",
      "storage_gb": 5,
      "ha_enabled": false,
      "status": "healthy",
      "created_at": "2026-08-20T10:00:00.000Z"
    }
  ],
  "totalItems": 1,
  "totalPages": 1,
  "currentPage": 1
}

code curl
curl -X POST https://api.light-cloud.com/api/databases \
  -H "Authorization: Bearer $LIGHT_CLOUD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"limit": 100}'

code Node
const res = await fetch("https://api.light-cloud.com/api/databases", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.LIGHT_CLOUD_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ limit: 100 }),
});

if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);

const { items } = await res.json();
items.forEach((db) => console.log(db.name, db.tier, db.status));

code Python
import os
import requests

res = requests.post(
    "https://api.light-cloud.com/api/databases",
    headers={"Authorization": f"Bearer {os.environ['LIGHT_CLOUD_API_KEY']}"},
    json={"limit": 100},
)
res.raise_for_status()

for db in res.json()["items"]:
    print(db["name"], db["tier"], db["status"])
```

## Retrieve a database

```endpoint
POST /api/databases/get
> One database and its configuration. Never includes credentials — use the connection string endpoint for those.
permission: read:projects

param databaseId | string | required | The database to read
param targetOrganisationId | string | session only | Required when using a session token

response 200 | A database
{
  "id": "db_2Vx",
  "name": "shop-orders",
  "database_type": "postgresql",
  "tier": "db-f1-micro",
  "region": "europe-west1",
  "storage_gb": 5,
  "ha_enabled": false,
  "public_ip_enabled": true,
  "status": "healthy",
  "created_at": "2026-08-20T10:00:00.000Z"
}

code curl
curl -X POST https://api.light-cloud.com/api/databases/get \
  -H "Authorization: Bearer $LIGHT_CLOUD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"databaseId": "db_2Vx"}'

code Node
const res = await fetch("https://api.light-cloud.com/api/databases/get", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.LIGHT_CLOUD_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ databaseId: "db_2Vx" }),
});

const database = await res.json();
```

## Retrieve status

```endpoint
POST /api/databases/status
> Poll this while a dedicated instance provisions — it can take 10-20 minutes.
permission: read:projects

param databaseId | string | required | The database to poll
param targetOrganisationId | string | session only | Required when using a session token

response 200 | Current status
{ "id": "db_2Vx", "status": "provisioning" }

code curl
until [ "$(curl -sS -X POST https://api.light-cloud.com/api/databases/status \
  -H "Authorization: Bearer $LIGHT_CLOUD_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"databaseId\":\"$DB_ID\"}" | jq -r .status)" = "healthy" ]; do
  sleep 15
done
```

## Create a database

```endpoint
POST /api/databases/create
> Records the database and begins provisioning. Shared tiers are ready in seconds, dedicated ones take 10-20 minutes.
permission: create:projects

param name | string | required | Display name
param databaseType | string | platform default | `postgresql` or `mysql`
param tier | string | platform default | Cloud SQL machine type: `db-f1-micro` or `db-g1-small` (shared-core, dev/test, no SLA), or `db-custom-<vCPU>-<memoryMB>` (dedicated)
param region | string | platform default | See Limits
param storageGb | number | platform default | Grows without downtime, never shrinks
param haEnabled | boolean | false | High availability. Doubles the compute price
param publicIpEnabled | boolean | true | Whether the instance gets a public address
param authorizedNetworks | string[] | optional | CIDR list. An empty list means world-reachable
param databaseName | string | generated | Initial database name
param adminUser | string | generated | Admin username
param adminPassword | string | generated | 12+ characters, no spaces, quotes or backslashes
param projectId | string | optional | Folder to file it under

response 201 | The created database
{
  "id": "db_2Vx",
  "name": "shop-orders",
  "database_type": "postgresql",
  "tier": "db-f1-micro",
  "status": "provisioning"
}

code curl
curl -X POST https://api.light-cloud.com/api/databases/create \
  -H "Authorization: Bearer $LIGHT_CLOUD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "shop-orders",
    "databaseType": "postgresql",
    "tier": "db-f1-micro",
    "storageGb": 5,
    "authorizedNetworks": ["203.0.113.10/32"]
  }'

code Node
const API = "https://api.light-cloud.com";
const headers = {
  Authorization: `Bearer ${process.env.LIGHT_CLOUD_API_KEY}`,
  "Content-Type": "application/json",
};

const post = async (path, body) => {
  const res = await fetch(API + path, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
  });
  if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
  return res.json();
};

const db = await post("/api/databases/create", {
  name: "shop-orders",
  databaseType: "postgresql",
  tier: "db-f1-micro",
  storageGb: 5,
  authorizedNetworks: ["203.0.113.10/32"],
});

let status = db.status;
while (status !== "healthy") {
  await new Promise((resolve) => setTimeout(resolve, 15_000));
  ({ status } = await post("/api/databases/status", { databaseId: db.id }));
}

code Python
import os
import time
import requests

API = "https://api.light-cloud.com"
headers = {"Authorization": f"Bearer {os.environ['LIGHT_CLOUD_API_KEY']}"}

def post(path, **body):
    res = requests.post(API + path, headers=headers, json=body)
    res.raise_for_status()
    return res.json()

db = post(
    "/api/databases/create",
    name="shop-orders",
    databaseType="postgresql",
    tier="db-f1-micro",
    storageGb=5,
    authorizedNetworks=["203.0.113.10/32"],
)

while post("/api/databases/status", databaseId=db["id"])["status"] != "healthy":
    time.sleep(15)
```

> [!WARNING]
> `publicIpEnabled` defaults to `true` because that is what actually gets provisioned today. Restrict reachability with `authorizedNetworks`, and treat an unset list as world-reachable.

## Get a connection string

```endpoint
POST /api/databases/connection-string
> Returns the full connection URL, credentials included.
permission: read:projects

param databaseId | string | required | The database to connect to
param targetOrganisationId | string | session only | Required when using a session token

response 200 | Connection URL
{
  "connectionString": "postgresql://app:s3cr3t@34.0.0.1:5432/shop?sslmode=require"
}

code curl
curl -X POST https://api.light-cloud.com/api/databases/connection-string \
  -H "Authorization: Bearer $LIGHT_CLOUD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"databaseId": "db_2Vx"}'

code Node
// Pipe it straight into an environment without it touching disk or a log
const API = "https://api.light-cloud.com";
const headers = {
  Authorization: `Bearer ${process.env.LIGHT_CLOUD_API_KEY}`,
  "Content-Type": "application/json",
};

const post = async (path, body) => {
  const res = await fetch(API + path, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
  });
  if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
  return res.json();
};

const { connectionString } = await post("/api/databases/connection-string", {
  databaseId,
});

const environment = await post("/api/environments/get", { environmentId });

await post("/api/environments/update", {
  environmentId,
  environmentVars: {
    ...environment.environment_vars,
    DATABASE_URL: connectionString,
  },
});

code Python
import os
import requests

API = "https://api.light-cloud.com"
headers = {"Authorization": f"Bearer {os.environ['LIGHT_CLOUD_API_KEY']}"}

def post(path, **body):
    res = requests.post(API + path, headers=headers, json=body)
    res.raise_for_status()
    return res.json()

connection = post("/api/databases/connection-string", databaseId=database_id)
environment = post("/api/environments/get", environmentId=environment_id)

post(
    "/api/environments/update",
    environmentId=environment_id,
    environmentVars={
        **environment["environment_vars"],
        "DATABASE_URL": connection["connectionString"],
    },
)
```

> [!IMPORTANT]
> This response contains the password in clear text. Do not log it, and do not write it to a file your CI archives. See [Connecting](/platform/databases/connect).

## Update a database

```endpoint
POST /api/databases/update
> Changes size or configuration. Storage grows without downtime and never shrinks; changing tier restarts the instance.
permission: update:projects

param databaseId | string | required | The database to update
param name | string | optional | Display name
param tier | string | optional | Restarts the instance
param region | string | optional | See Limits
param storageGb | number | optional | Can only increase
param haEnabled | boolean | optional | Doubles the compute price

response 200 | The updated database
{ "id": "db_2Vx", "tier": "db-custom-1-3840", "storage_gb": 20 }

code curl
curl -X POST https://api.light-cloud.com/api/databases/update \
  -H "Authorization: Bearer $LIGHT_CLOUD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"databaseId": "db_2Vx", "tier": "db-custom-1-3840", "storageGb": 20}'
```

## Rotate the password

```endpoint
POST /api/databases/rotate-password
> Issues new credentials. Applications holding the old ones break immediately.
permission: update:projects

param databaseId | string | required | The database to rotate
param newPassword | string | generated | 12+ characters, no spaces, quotes or backslashes
param targetOrganisationId | string | session only | Required when using a session token

response 200 | The new connection details
{
  "connectionString": "postgresql://app:n3wp4ss@34.0.0.1:5432/shop?sslmode=require"
}

code curl
curl -X POST https://api.light-cloud.com/api/databases/rotate-password \
  -H "Authorization: Bearer $LIGHT_CLOUD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"databaseId": "db_2Vx"}'
```

> [!WARNING]
> Update the [variables](/platform/environment-variables) of anything using this database and redeploy, or it stays broken.

## Read metrics

```endpoint
POST /api/databases/metrics
> CPU, memory, storage and connection counts over a window.
permission: read:projects

param databaseId | string | required | The database to measure
param timeRange | string | 1h | `1h`, `6h`, `24h` or `7d`
param targetOrganisationId | string | session only | Required when using a session token

response 200 | Series per metric
{
  "databaseId": "db_2Vx",
  "metrics": {
    "cpu": [{ "t": "2026-08-28T08:00:00.000Z", "v": 0.12 }],
    "connections": [{ "t": "2026-08-28T08:00:00.000Z", "v": 7 }]
  }
}

code curl
curl -X POST https://api.light-cloud.com/api/databases/metrics \
  -H "Authorization: Bearer $LIGHT_CLOUD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"databaseId": "db_2Vx", "timeRange": "24h"}'
```

## Delete a database

```endpoint
POST /api/databases/delete
> Removes the instance and its data. Not reversible.
permission: delete:projects

param databaseId | string | required | The database to delete
param targetOrganisationId | string | session only | Required when using a session token

response 200 | Deletion accepted
{ "message": "Database deleted" }

code curl
curl -X POST https://api.light-cloud.com/api/databases/delete \
  -H "Authorization: Bearer $LIGHT_CLOUD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"databaseId": "db_2Vx"}'
```

## Other endpoints

| Endpoint | Body | Description |
| --- | --- | --- |
| `POST /api/databases/provision` | `databaseId` | Starts provisioning for a database created but not yet built |
| `POST /api/databases/dump` | `databaseId` | Produces a `pg_dump` or `mysqldump` file to download |
| `POST /api/databases/import` | `databaseId` | The other direction |
| `POST /api/databases/move` | `databaseId`, `targetFolderId` | Files it under a different folder |
| `GET /api/databases/:targetOrganisationId/:databaseId/stream` | | Server-sent events for provisioning progress |

### Data explorer

Reading and editing rows directly, the same surface the console's Data tab uses. Each takes `databaseId`.

| Endpoint | Description |
| --- | --- |
| `POST /api/databases/explorer/schema` | Tables and columns |
| `POST /api/databases/explorer/rows` | Paged rows of one table |
| `POST /api/databases/explorer/query` | Run a statement |
| `POST /api/databases/explorer/row` | Insert, update, or delete one row |
| `POST /api/databases/explorer/table` | Table-level operations |

> [!NOTE]
> The explorer and dump endpoints sit behind feature flags. If they answer with a "not enabled" message on your account, check `GET /api/config/feature-flags`.

## Related

- [Databases](/platform/databases): Engines, tiers, and how provisioning works.
- [Connecting](/platform/databases/connect): Connection strings and clients.
- [Limits](/reference/limits#databases): Tiers, storage, and password rules.
