Launch a CMS
The cms stack stands up a complete headless content platform in one launch. You get a managed PostgreSQL database and a Directus application already attached to it, so your content lives in a database you own and reach it through an admin UI plus auto-generated REST and GraphQL APIs.
What the CMS stack is, and who it is for
A headless CMS separates content storage and editing from the front end that renders it. You model your content, edit it in an admin UI, and your sites and apps pull it over an API. Directus is an open-source headless CMS that turns a plain PostgreSQL database into that content backend: it introspects your tables, gives editors a polished admin app, and exposes every collection as instant REST and GraphQL endpoints.
This stack is for teams who want that outcome without the plumbing:
- Marketing and product teams who need an editable content backend behind a website or app.
- Developers who want REST and GraphQL over PostgreSQL without writing a content API by hand.
- Anyone who needs content to stay in their own EU-resident database rather than a third-party SaaS.
Composition
The stack composes two FoundryDB primitives, wired together at launch:
| Resource | What it is | Spec |
|---|---|---|
db | Managed PostgreSQL 17. Directus uses it as its own backing store, creating its system collections and first admin on first start. | tier-1, 25 GB standard storage |
app | A hosted Directus application, attached to the database with DATABASE_URL injected. Serves the admin UI and the REST and GraphQL content APIs. | tier-1, 10 GB standard storage |
PostgreSQL is the durable home for your content. Directus is the editing and API layer on top. Because Directus speaks plain SQL to a database you own, you can query, back up, and connect other tools to the same content directly, with no lock-in.
Prerequisites
- An API token. See Authentication.
Unlike the rag-chatbot stack, the CMS stack does not include an inference resource, so you do not need a configured inference provider to launch it.
Export your token for the commands below:
export FOUNDRYDB_TOKEN="your-api-token"
Launch it
Option A: one-click in the console
Open the Stacks catalog in the console, pick Launch a CMS, review the cost preview, and click Launch. The console runs the same preview, accept, and launch flow described below and shows the live endpoint once the stack reaches Running.
Option B: the API
The launch is a two-step flow: preview the cost first, then send the launch request with the cost you accepted. This guarantees you always see an up-to-date estimate before any billable resource is created.
1. Preview the cost
curl -X POST https://api.foundrydb.com/stacks/preview \
-H "Authorization: Bearer $FOUNDRYDB_TOKEN" \
-H "Content-Type: application/json" \
-d '{"template_name": "cms"}'
The response breaks the cost down per resource:
{
"template_name": "cms",
"currency": "EUR",
"monthly_total": 51.00,
"line_items": [
{
"symbolic_name": "db",
"kind": "database",
"description": "PostgreSQL tier-1 + 25 GB standard storage",
"monthly_cost": 28.00,
"is_ceiling": false
},
{
"symbolic_name": "app",
"kind": "app",
"description": "Directus app tier-1 + 10 GB standard storage",
"monthly_cost": 23.00,
"is_ceiling": false
}
],
"warnings": []
}
monthly_total is the figure you pass to the launch request. The cost preview is computed fresh on every call, so always preview right before launching.
2. Accept and launch
Pass the monthly_total from the preview as accepted_monthly_cost:
curl -X POST https://api.foundrydb.com/stacks \
-H "Authorization: Bearer $FOUNDRYDB_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "my-cms",
"template_name": "cms",
"accepted_monthly_cost": 51.00
}'
The response is 201 Created with the stack in Pending status. Capture its id:
export STACK_ID="the-id-from-the-response"
If accepted_monthly_cost has drifted from the current estimate by more than EUR 0.01, the launch returns 409 Conflict and you re-preview. If it is omitted entirely, the launch returns 400 Bad Request.
3. Poll for status
The stack provisions asynchronously. Poll GET /stacks/{id} until status reaches Running:
curl https://api.foundrydb.com/stacks/$STACK_ID \
-H "Authorization: Bearer $FOUNDRYDB_TOKEN"
Typical progression is Pending then Provisioning then Wiring then Running. Most stacks complete within a few minutes. Once the stack is Running, the endpoint_url field carries the live Directus URL:
{
"id": "...",
"name": "my-cms",
"status": "Running",
"endpoint_url": "https://my-cms-app.foundrydb.com",
"resources": [
{ "symbolic_name": "db", "kind": "database", "status": "Running", "service_id": "..." },
{ "symbolic_name": "app", "kind": "app", "status": "Running", "service_id": "..." }
]
}
First run
Open the admin UI and sign in
Open the endpoint_url in a browser. Directus serves its admin app at that URL. On first start it creates an initial administrator account. Retrieve the generated admin credentials from the app service:
curl https://api.foundrydb.com/stacks/$STACK_ID \
-H "Authorization: Bearer $FOUNDRYDB_TOKEN" | jq '.resources[] | select(.symbolic_name=="app")'
The app resource exposes its credentials the same way any FoundryDB app service does. Sign in with the admin email and password, then change the password from Settings once you are in.
Define a collection
In the admin UI, create a collection (Directus calls a table a collection). Go to Settings, then Data Model, then Create Collection. Name it articles and add a couple of fields, for example a title string and a body text field. Save, then add a few items under Content.
See it stored in your PostgreSQL
That collection is a real table in your PostgreSQL database. Connect to the db resource directly and confirm. Retrieve the database connection details and a user password from the service (see Database users for the user and password endpoints), then:
psql "host=<db-host> user=<db-user> dbname=defaultdb sslmode=verify-full" \
-c "SELECT title FROM articles;"
title
----------------------
My first article
A second article
(2 rows)
Your content is plain rows in a database you own. You can back it up, run analytics against it, or point another tool at the same data.
Hit the auto-generated content API
Directus exposes every collection over REST and GraphQL with no extra work. Create an access token in the admin UI under your user profile, then query the REST endpoint:
curl "https://my-cms-app.foundrydb.com/items/articles" \
-H "Authorization: Bearer <directus-access-token>"
{
"data": [
{ "id": 1, "title": "My first article", "body": "..." },
{ "id": 2, "title": "A second article", "body": "..." }
]
}
The same data is available over GraphQL at the /graphql path on the same host. This is the content API your website or app consumes.
How the wiring works
The stack engine does not introduce a new provisioning path. It calls the same APIs you would call yourself, in dependency order, and injects the configuration each resource needs.
For the CMS stack:
- The
dbresource is provisioned first: a managed PostgreSQL 17 service. - The
appresource is provisioned and attached to the database. During theWiringphase, the engine injects the database connection string into the Directus app asDATABASE_URL. - Directus connects on first boot, creates its system collections and the first admin, and comes up serving the admin UI and APIs.
There is no connection string to copy, no firewall rule to open by hand, and no environment variable to paste into a settings panel. The app already knows where the database is and how to reach it the moment the stack reaches Running.
Cost and EU residency
The CMS stack costs the sum of its two resources, shown in your cost preview at launch (tier-1 PostgreSQL plus a tier-1 Directus app). Each child resource is an ordinary service in your account, billed through your normal plan. You can scale either one individually after launch.
Both resources are EU-resident. The PostgreSQL database, the Directus app, and the traffic between them all stay within the platform's European footprint. Residency is not a setting you remember to flip; it is where the platform runs.
Teardown
Delete the whole stack with one call:
curl -X DELETE https://api.foundrydb.com/stacks/$STACK_ID \
-H "Authorization: Bearer $FOUNDRYDB_TOKEN"
Returns 202 Accepted. The reconciler deletes the app first, then the database, in reverse dependency order. Teardown is atomic and leaves no orphaned database or app behind. It is irreversible, so export anything you want to keep first.
Next steps
- Stacks Overview: how stacks compose primitives, the catalog, and the lifecycle.
- Launch a Stack: the full preview, launch, retry, and teardown reference.
- PostgreSQL: scale, back up, and connect directly to the database under your CMS.
- Upgrades: adopt new template versions of the stack in place.