# Strapi

Strapi is an open source headless CMS built with Node.js

[Strapi](https://github.com/strapi/strapi) is a headless CMS you deploy as your own project rather than from the upstream monorepo. A project is created with `npx create-strapi@latest`, lives in its own Git repository, and ships an admin panel that is built once per deploy. This guide covers deploying that project repository to Hatchbox with PostgreSQL.

## Requirements

Create a PostgreSQL database from the Databases tab and keep the variable named `DATABASE_URL`; the generated `config/database` file reads it as the connection string.

Strapi supports the active Node LTS releases (22, 24 and 26). Add a `.nvmrc` with the version you develop on, for example `22`, so Hatchbox installs the same one. Building the admin panel uses about 2 GB of RAM, so use a server with at least 4 GB.

## Repository

Create the project locally and push it to Git:

```
npx create-strapi@latest my-project --dbclient postgres --dbhost localhost --dbport 5432 --dbname strapi --dbusername strapi --dbpassword strapi --skip-cloud --no-run
```

`--dbclient` must be given together with all the `--db*` connection flags. Their values only go into your local `.env`; on Hatchbox `DATABASE_URL` takes precedence. Choosing `postgres` adds the `pg` driver to `package.json`. If your project already exists with SQLite, run `npm install pg` and commit the change. Commit `package-lock.json` as well; Hatchbox runs `npm install` when it finds one.

The generated `.env` is ignored by Git, so its values go in the Environment tab instead. Add the two `.hatchbox` scripts below, then set your repository URL and branch on the app.

## Environment Variables

```
APP_KEYS=&lt;key1&gt;,&lt;key2&gt;,&lt;key3&gt;,&lt;key4&gt;
API_TOKEN_SALT=&lt;secret&gt;
ADMIN_JWT_SECRET=&lt;secret&gt;
TRANSFER_TOKEN_SALT=&lt;secret&gt;
JWT_SECRET=&lt;secret&gt;
ENCRYPTION_KEY=&lt;secret&gt;
DATABASE_CLIENT=postgres
DATABASE_SSL=false
```

Copy the secrets from the `.env` that `create-strapi` generated, or create new ones with `openssl rand -base64 16`. `DATABASE_URL` comes from the attached database. Strapi listens on `HOST=0.0.0.0` and `PORT` by default, and Hatchbox provides `PORT`.

Do not set `NODE_ENV=production` in the Environment tab: npm would then skip the dev dependencies (TypeScript, type definitions) that the build needs. The scripts below set it per command instead.

## Build Scripts

### .hatchbox/pre-build

The local upload provider writes to `public/uploads`, which must survive deploys:

```
#!/usr/bin/env bash
set -e

mkdir -p $DIR/shared/uploads
rm -rf public/uploads
ln -s $DIR/shared/uploads public/uploads
```

Skip this if you use an upload provider plugin such as S3.

### .hatchbox/post-build

Hatchbox only installs dependencies, so build the admin panel (and compile TypeScript) here. Node&#39;s default heap limit is a quarter of the server&#39;s RAM, which is too small for the admin build on servers under 8 GB, so the script raises it:

```
#!/usr/bin/env bash
set -e

NODE_OPTIONS=--max-old-space-size=2048 NODE_ENV=production npm run build
```

## Processes

1. `web`, web servers: `NODE_ENV=production npm run start`

Strapi runs its database migrations when it starts, so no separate migration step is needed.

## First Login

Open `/admin` on your domain. The registration form creates the first administrator account.

## Notes

Uploads live in `shared/uploads`, so keep the app on a single server unless you switch to a cloud upload provider.

Content types are defined in code under `src/api`, so create them locally, commit, and deploy; entries are added through the admin panel on the server. Upgrade by running `npx @strapi/upgrade latest` locally, committing, and deploying.
