SvelteKit + Postgres + Atlas + Drizzle (Docker)
A production-ready deployment template for SvelteKit apps backed by PostgreSQL, with a clean separation between the HTTP server and database migrations.
| Component | Role |
|---|---|
| SvelteKit | Application framework (builds to adapter-node) |
| Bun | Runtime + package manager |
| PostgreSQL | Database |
| Drizzle ORM | Schema definition (TypeScript) + query builder |
| Atlas | Migration engine — generates and applies SQL migrations |
| Docker | Multi-target build: tiny runner + tiny migrator |
Most SvelteKit + Docker setups ship a single image that bundles the app, the dev tooling, and the migration runner — often 700 MB+. SPADA splits this into two small targets:
| Image | Purpose | Size |
|---|---|---|
runner |
HTTP server (distroless) | ~600 MB |
migrate |
One-shot DB migrations (Atlas distroless) | ~14 MB |
The migrator runs once at deploy time, applies pending SQL, then exits. The app server never carries migration tooling.
-
Use this template on GitHub → "Use this template" → create your repo.
-
Clone your new repo, then scaffold SvelteKit inside:
bunx sv create . bun install bunx sv add adapter-node -
Add Drizzle + Postgres:
bun add drizzle-orm postgres bun add -D drizzle-kit
-
Define your schema in
src/lib/server/db/schema.ts(Drizzle). -
Generate your first migration:
atlas migrate diff initial_schema --env local -
Build and deploy:
./scripts/build-and-push.sh v1.0.0 # On the server: docker compose pull && docker compose up -d
.
├── Dockerfile # Multi-target: runner (distroless) + migrate (Atlas)
├── docker-compose.yml # Production compose (db + migrate + app)
├── atlas.hcl # Atlas config — reads Drizzle schema via drizzle-kit export
├── .dockerignore
├── .env.example
├── scripts/
│ └── build-and-push.sh # Build both targets, tag, push to ghcr.io
└── migrations/ # Atlas migration files (generated)
Drizzle defines the schema (TypeScript). Atlas owns the migration lifecycle:
schema.ts (Drizzle)
↓ drizzle-kit export
atlas.hcl (external_schema)
↓ atlas migrate diff
migrations/*.sql (versioned SQL files)
↓ atlas migrate apply (in the migrate container)
PostgreSQL
The app never runs migrations. The migrate service in docker-compose.yml runs once at deploy time, before the app starts.
Set these in your .env on the server:
| Variable | Required | Example |
|---|---|---|
DB_PASSWORD |
Yes | your-secret-password |
POSTGRES_DB |
No (default: app) |
myapp |
ORIGIN |
Yes | https://myapp.example.com |
BETTER_AUTH_SECRET |
Yes | openssl rand -base64 32 |
GITHUB_ORG |
Yes (for build script) | your-github-org |
APP_NAME |
Yes (for build script) | myapp |
- Bun 1.x
- Docker
- Atlas CLI (for local migration generation)
- gh CLI authenticated with
write:packagesscope
MIT