Docker
The image is published to docker.io/flexcal/flexcal, built for linux/amd64 and linux/arm64.
Use the dev tag for the current default branch, or a semver tag such as vX.Y.Z for a release.
docker pull docker.io/flexcal/flexcal:<version>Requirements
Section titled “Requirements”docker and docker compose must be installed on the host.
docker compose (no hyphen) is the current form of the command.
Running with Docker Compose
Section titled “Running with Docker Compose”The docker-compose.yml lives in the flexcal repository,
so start by cloning it:
git clone https://codefloe.com/flexcal/flexcal.gitcd flexcalCopy the example environment file:
cp .env.example .envPick a version
Section titled “Pick a version”docker-compose.yml runs docker.io/flexcal/flexcal:${FLEXCAL_VERSION:-dev}, so the tag comes from
your .env:
FLEXCAL_VERSION=<version>dev tracks the default branch and moves under you. Pin a release for anything you care about.
Generate the required secrets
Section titled “Generate the required secrets”Do not ship the placeholder secret values to production.
Generate NEXTAUTH_SECRET, the cookie encryption key:
openssl rand -base64 32Generate CALENDSO_ENCRYPTION_KEY, which must be 32 bytes for AES256:
openssl rand -base64 24Put both into .env:
NEXTAUTH_SECRET=<your_generated_secret>CALENDSO_ENCRYPTION_KEY=<your_generated_key>Web push notifications need a VAPID key pair.
Without them you will see Error: No key set vapidDetails.publicKey:
npx web-push generate-vapid-keysNEXT_PUBLIC_VAPID_PUBLIC_KEY=<your_public_key>VAPID_PRIVATE_KEY=<your_private_key>Everything else can usually stay as shipped, see Configuration for the full list.
Start the stack
Section titled “Start the stack”Optionally pre-pull the images:
docker compose pullThe full stack (Postgres, the flexcal web app and Prisma Studio):
docker compose up -dThe web app and Prisma Studio against an external database, with DATABASE_URL pointing at it:
docker compose up -d flexcal studioOnly the web app:
docker compose up -d flexcalDrop -d to run attached when debugging.
First run
Section titled “First run”Open http://localhost:3000, or whatever NEXT_PUBLIC_WEBAPP_URL points at.
A setup wizard runs the first time and creates your first user.
The wizard’s “Connect your Calendar” step looks mandatory but is not: navigate straight to
<NEXT_PUBLIC_WEBAPP_URL>/event-types to skip it. Calendar integrations can be added later
under Settings → Integrations.
Updating
Section titled “Updating”docker compose downdocker compose pullReconcile your .env against the current .env.example, then:
docker compose up -dMigrations and app-store seeding on boot
Section titled “Migrations and app-store seeding on boot”By default, the container applies database migrations and seeds the app store every time it starts. That is correct for Docker Compose, which has nowhere else to run them.
For deployments that migrate once per release (the Helm chart does this in a pre-upgrade Job), set both flags so replicas do not race each other:
SKIP_DB_MIGRATIONS=1SKIP_APP_STORE_SEED=1Building the image yourself
Section titled “Building the image yourself”See Container images.