FinOpenPOS

Deployment

Docker, Coolify, and production setup

Docker Compose

The project includes a multi-stage Alpine-based Dockerfile and Docker Compose with a persistent volume.

Loading diagram...

Commands

docker compose up -d          # Build and start
docker compose logs -f        # View logs
docker compose down           # Stop
docker compose down -v        # Stop and delete database data

Environment Variables

The compose.yaml expects these environment variables. For Docker, create a root .env file or pass them via -e:

BETTER_AUTH_SECRET=your-secret-key-at-least-32-chars
BETTER_AUTH_URL=https://your-domain.com

For local dev, configure apps/web/.env instead.

VariableRequiredDescription
BETTER_AUTH_SECRETYesSecret key for session encryption (min 32 chars)
BETTER_AUTH_URLYesPublic URL of the application
PORTNoInternal port (default: 3111)
DATABASE_URLNoPostgreSQL URL (only for production image)

Dockerfiles

FileUse Case
DockerfileDevelopment image with PGLite (default)
Dockerfile.productionProduction image with PostgreSQL support

Coolify / PaaS

The project works with Coolify and similar platforms that detect compose.yaml. Set the environment variables in the platform UI. The default internal port is 3111 (configurable via PORT env).

Production with PostgreSQL

For production deployments with real PostgreSQL you can use the automatic script or follow the manual steps.

Automatic

cd apps/web && bun run prepare-prod

The script swaps PGLite for pg, rewrites db/index.ts and drizzle.config.ts, and removes PGLite-only helpers. After running it, set DATABASE_URL and push the schema:

DATABASE_URL=postgresql://user:password@host:5432/finopenpos
cd apps/web && bun run db:push

Then use Dockerfile.production in your compose config.

Manual

If you prefer to do it step by step:

1. Install the PostgreSQL driver

bun add pg
bun remove @electric-sql/pglite

2. Update apps/web/src/lib/db/index.ts

import { drizzle } from "drizzle-orm/node-postgres";
import * as schema from "./schema";

export const db = drizzle(process.env.DATABASE_URL!, { schema });

3. Update apps/web/drizzle.config.ts

import { defineConfig } from "drizzle-kit";

export default defineConfig({
  dialect: "postgresql",
  schema: "./src/lib/db/schema.ts",
  dbCredentials: {
    url: process.env.DATABASE_URL!,
  },
});

4. Add the env variable

DATABASE_URL=postgresql://user:password@host:5432/finopenpos

5. Push schema and run

cd apps/web && bun run db:push
bun run dev

6. Clean up

  • Delete scripts/ensure-db.ts (only exists for PGLite recovery)
  • Remove db:ensure from dev and build scripts in package.json
  • Remove serverExternalPackages from next.config.mjs
  • In Docker, replace the PGLite volume with a PostgreSQL connection via DATABASE_URL

The Drizzle schema (apps/web/src/lib/db/schema.ts) doesn't change. All queries, relations and tRPC procedures keep working without modification.

See also Database — Migrating to PostgreSQL for more details on PGLite vs PostgreSQL.

On this page