Projects
Workspaces that own branches, team access, network policy, backups, and audit trails in AxiomDB.
Projects
In AxiomDB, a project is your top-level organizational space. Think of it as a secure, isolated workspace that holds everything you need for a single application's database setup—including database branches, access credentials, network firewall rules, team permissions, backups, and audit histories.
We've designed projects to draw a clear line between different applications or microservices. Because of this, absolutely nothing leaks across project boundaries! Credentials you generate in one project can never touch databases in another, network policies are evaluated independently for each project, and audit logs are kept strictly separated.
Understanding Project Fields
Every project is defined by a mix of three permanent identity settings and a handful of flexible, updateable configuration settings.
Permanent Identity Fields
| Field | Type | Can I change it? | Description |
|---|---|---|---|
name | string | Yes | A friendly name for your project (like Payments Service). |
app_key | string (snake_case) | No | A unique identifier used in database names, database roles, and internal routing. |
env | enum | No | Choose from dev, staging, or prod. This sets default branch lifespans and firewall rules. |
Configurable Settings
| Field | Type | Default value | Description |
|---|---|---|---|
default_lifespan | enum | 7d for dev, 1y for staging/prod | The default lifespan we assign to new branches. |
max_branches | integer | 10 | The maximum number of active branches you can have at the same time. |
network_mode | enum | restricted | Controls how users can connect to your databases. See Connections. |
storage_quota_gib | float | 0.25 | The total storage space allocated for all branches (expandable up to 5 GiB). |
team | array<UserRef> | [creator] | The list of users who have access to this project. |
tags | map<string,string> | {} | Custom key-value pairs to help you tag, filter, and organize your projects. |
The Uniqueness Rule for (app_key, env)
To keep database routing clean, the combination of your app_key and environment env must be completely unique across AxiomDB. This is because we use these two values to name your database and generate roles inside the underlying PostgreSQL cluster.
┌─────────────────────────────────────────────┐
│ Global Uniqueness │
│ │
│ (app_key="payments", env="dev") ✓ OK │
│ (app_key="payments", env="staging") ✓ OK │
│ (app_key="payments", env="dev") ✗ DUP │
└─────────────────────────────────────────────┘If you try to create a project with a pair that already exists, our API will return a 409 Conflict status with the error code PROJECT_ALREADY_EXISTS.
How projects are created
When you trigger a POST /v1/projects request, here is the sequence of events that our control plane carries out:
Client Control Plane square-dbctl Postgres Cluster
│ │ │ │
│ POST /v1/projects │ │ │
│ ─────────────────────────► │ │ │
│ │ │ │
│ │ 1. Validate payload │ │
│ │ 2. Check uniqueness │ │
│ │ (app_key, env) │ │
│ │ │ │
│ │ 3. Enqueue command │ │
│ │ CREATE_PROJECT ─────►│ │
│ │ │ │
│ │ │ 4. Create database │
│ │ │ sq_<key>_<env> ─►│
│ │ │ │
│ │ │ 5. Create roles │
│ │ │ *_owner, *_rw, │
│ │ │ *_ro ─►│
│ │ │ │
│ │ │ 6. Grant privileges │
│ │ │ owner → CREATE ─►│
│ │ │ rw → DML ─►│
│ │ │ ro → SELECT ─►│
│ │ │ │
│ │ 7. Create main branch │ │
│ │ (protected, forever) │ │
│ │ │ │
│ │ 8. Generate PASETO v4 │ │
│ │ tokens for main │ │
│ │ │ │
│ │ 9. Write audit event │ │
│ │ PROJECT_CREATED │ │
│ │ │ │
│ ◄────────────────────── │ 10. Return project + │ │
│ 201 Created │ main branch creds │ │Step-by-step walkthrough
-
Checking the payload — Our gateway (running
axumon port 4060) first validates your request body against our schema. It makes sure yourapp_keyis formatted in lowercase snake_case and is between 3 and 48 characters, and checks that your environment setting is valid. -
Checking for duplicates — The control plane queries our system metadata to make sure this name pair is available:
SELECT id FROM projects WHERE app_key = $1 AND env = $2 LIMIT 1; -
Queueing the command — We add a new provisioning task to our Redis command queue:
{ "command": "CREATE_PROJECT", "payload": { "project_id": "proj_a1b2c3d4", "app_key": "payments", "env": "prod", "creator_id": "usr_x9y8z7" }, "status": "pending", "created_at": "2025-01-15T10:30:00Z" } -
Spinning up infrastructure —
square-dbctlpicks up the queued task and runs the queries needed to set up your database and users on the target Postgres cluster. You can read more about this in our Connections guide. -
Setting up your main branch — We automatically create your protected
mainbranch with a lifespan offorever. This branch is locked down so it can't be deleted or automatically expired. -
Generating security tokens — We issue secure PASETO v4 tokens (signed with Ed25519) for your
mainbranch. These encode the project, branch, and role permissions. -
Logging the event — We write a
PROJECT_CREATEDentry to your audit logs. -
Sending the response — Finally, we send you back the project details and your initial branch connection credentials.
What resources does a project own?
A project acts as the parent container for several related database resources:
| Resource | Relationship | Notes |
|---|---|---|
| Branches | 1:N | Each project holds between 0 and 10 active branches, including the permanent main branch. |
| Credentials | 1:N (per branch) | Every database branch exposes its own DATABASE_URL and DIRECT_URL. |
| Team membership | 1:N | You assign team permissions at the project level, which applies access to all branches. |
| Network policy | 1:1 | A single network_mode setting governs firewall rules for every branch in the project. |
| Audit log | 1:1 | Any changes made within the project write to a dedicated audit log. |
| Storage quota | 1:1 | Your storage quota is shared across all the branches in your project. |
| Tags & metadata | 1:1 | Custom tags help you label and organize your projects. |
What is outside of a project's scope?
- Users — User accounts exist independently and are simply linked to projects by their ID.
- Postgres clusters — We schedule projects onto Postgres clusters, but the project does not own the cluster itself.
- Other projects — Projects are flat, isolated containers; there is no nesting or project hierarchy.
- Billing — Billing configurations are managed at the organization level, completely outside of the project workspace.
Project lifecycles (Status values)
As your project is created, updated, and deleted, it transitions through these states:
┌──────────┐
│ creating │
└────┬─────┘
│
▼
┌──────────┐
┌────►│ active │◄────┐
│ └────┬─────┘ │
│ │ │
│ ▼ │
│ ┌──────────┐ │
│ │ updating │─────┘
│ └──────────┘
│
│ ┌──────────┐
└─────│ deleting │
└────┬─────┘
│
▼
┌──────────┐
│ deleted │
└──────────┘Here is what each state means:
| Status | Description |
|---|---|
creating | We are currently setting up your database, roles, and main branch. |
active | Your project is live and ready! All branches are active and accepting connections. |
updating | We are applying a configuration update (like changing settings or network rules). |
deleting | We are tearing down the project, removing database branches, and deleting roles. |
deleted | The project has been removed. Data is kept in a soft-delete state for 30 days before being permanently purged. |
Project settings
You can update your project settings at any time by sending a PATCH /v1/projects/:project_id request:
{
"name": "Payments Service (v2)",
"network_mode": "public_runtime",
"storage_quota_gib": 2.0,
"tags": {
"team": "platform",
"cost_center": "eng-payments"
}
}Permanent settings
Your app_key and environment env are set in stone once a project is created. If you ever need to change them, you'll need to create a new project and migrate your data over.
Selecting a Network Mode
The network_mode setting controls who can connect to your database endpoints:
| Mode | Description |
|---|---|
restricted | Only allowlisted IP addresses can connect. This is our default secure mode for all projects. |
public_runtime | Your pooled PgBouncer URL (port 6432) is open to the public, while your direct migration URL (port 5432) remains restricted. |
public_all | Both connection URLs are open to the public. Please use this mode with caution! |
See our Connections guide for more details.
Listing your projects
To fetch a list of all the projects you have access to, run this terminal command:
curl -s https://gateway.axiomdb.io/v1/projects \
-H "Authorization: Bearer paseto_v4_..." | jqHere is an example of the JSON response you'll get back:
{
"data": [
{
"id": "proj_a1b2c3d4",
"name": "Payments Service",
"app_key": "payments",
"env": "prod",
"status": "active",
"default_lifespan": "1y",
"max_branches": 10,
"network_mode": "restricted",
"storage_quota_gib": 1.0,
"storage_used_gib": 0.18,
"branch_count": 3,
"team": [
{ "user_id": "usr_x9y8z7", "role": "owner" },
{ "user_id": "usr_m3n4o5", "role": "member" }
],
"tags": { "team": "platform" },
"created_at": "2025-01-15T10:30:00Z",
"updated_at": "2025-03-20T14:15:00Z"
}
],
"pagination": {
"cursor": null,
"has_more": false
}
}Filtering project lists
You can narrow down your projects list by adding filters for env, status, or tags:
curl -s https://gateway.axiomdb.io/v1/projects?env=prod&status=active \
-H "Authorization: Bearer paseto_v4_..."Deleting a project
Warning: Deleting a project is permanent and cannot be undone! When you trigger a deletion, the control plane carries out these steps:
- Setting state to
deleting— We lock the project to prevent anyone from spinning up new branches. - Expiring active branches — We mark all database branches (except the protected
mainbranch) for immediate deletion. - Dropping branches —
square-dbctldrops databases and roles for all those branches. - Dropping main — We remove the protected
mainbranch last. - Dropping the project database — We delete the core
sq_<app_key>_<env>database from the cluster. - Cleaning up roles — We drop all database roles (
*_owner,*_rw,*_ro). - Invalidating tokens — All active connection tokens for this project are revoked.
- Logging the delete — We record a
PROJECT_DELETEDaudit event. - Setting state to
deleted— The project metadata is soft-deleted and kept for 30 days for compliance audits.
Permanent database deletion
Once the 30-day retention window closes, all metadata is permanently erased and cannot be recovered. Be sure to export your data before deleting a project!
Project Metadata
Each project contains metadata that can help you with scripts and automation tools:
{
"id": "proj_a1b2c3d4",
"cluster_id": "cls_westus2_01",
"storage_used_gib": 0.18,
"branch_count": 3,
"last_activity_at": "2025-03-20T14:15:00Z",
"created_by": "usr_x9y8z7",
"created_at": "2025-01-15T10:30:00Z",
"updated_at": "2025-03-20T14:15:00Z"
}Here's what these fields represent:
| Field | Description |
|---|---|
id | The globally unique ID for your project (proj_<random>). |
cluster_id | An internal ID for the Postgres cluster hosting your database. |
storage_used_gib | The total storage currently used across all database branches. |
branch_count | The number of active database branches. |
last_activity_at | The timestamp of the most recent database connection or edit. |
created_by | The user ID of the person who created the project. |
Project Audit Events
Every single update or setting change in your project generates an audit event:
{
"event": "PROJECT_CREATED",
"project_id": "proj_a1b2c3d4",
"actor_id": "usr_x9y8z7",
"actor_email": "alice@example.com",
"timestamp": "2025-01-15T10:30:00Z",
"metadata": {
"app_key": "payments",
"env": "prod",
"network_mode": "restricted"
}
}Here are the events we trace:
| Event | What triggers it |
|---|---|
PROJECT_CREATED | A brand new project is provisioned. |
PROJECT_UPDATED | A setting (name, network mode, quota, or tags) is updated. |
PROJECT_TEAM_MEMBER_ADDED | A new member is added to the project team. |
PROJECT_TEAM_MEMBER_REMOVED | A team member is removed from the project. |
PROJECT_DELETING | A user triggers project deletion. |
PROJECT_DELETED | All database resources are fully torn down. |
API Quick Reference
Here are the endpoints available for managing projects via our API:
| Method | Endpoint | Description |
|---|---|---|
POST | /v1/projects | Spin up a new project. |
GET | /v1/projects | Fetch a list of all your projects. |
GET | /v1/projects/:id | Get details for a specific project. |
PATCH | /v1/projects/:id | Update settings for a project. |
DELETE | /v1/projects/:id | Delete a project and tear down its branches. |
GET | /v1/projects/:id/audit | Retrieve a project's audit logs. |
POST | /v1/projects/:id/team | Invite a new team member to your project. |
DELETE | /v1/projects/:id/team/:user_id | Remove a team member from your project. |
How is this guide?
Projects
Projects are the top-level unit of organisation in AxiomDB. Each project maps to one application in one environment, owns one or more database branches, and carries its own network policy, audit log, and provisioning jobs.
Branches
Learn about database branches in AxiomDB—isolated Postgres instances you can spin up, work on, and delete with ease.
