Add Services (Postgres, Redis, and More)
Most real apps need more than a web process. They need a database, a cache, or a search index. VMKit lets you add these as one-click services — containers that run alongside your app on the same VM, managed by Kamal as “accessories”.
You don’t write a docker-compose.yml. You don’t configure volumes by hand. You click the service you want, VMKit deploys the container, and the connection string appears in your app’s environment automatically.
How to Add a Service
Services are configured per environment. Each environment can have its own set of services — useful when you want Postgres on staging but point production to a managed Supabase instance.
Open the environment’s Addons panel
Go to Repos → your repo → Environments → your environment → Addons.
Click the service you want
Each service shows its version, injected environment variable(s), and estimated memory footprint. Click Enable next to the service.
Wait for the container to start
VMKit dispatches a Kamal accessory deploy. The service container starts on your VM, the volume is created, and the connection string is written to your app’s environment variables. This usually takes under a minute.
Redeploy your app (if it’s already running)
VMKit injects the new environment variable, but your running app process won’t see it until the next deploy. Trigger a deploy from the dashboard or push a commit — your app will start with the connection string available.
Service Reference
Postgres
PostgreSQL 16
The most common choice for persistent storage. VMKit runs the official postgres:16 image.
| Detail | Value |
|---|---|
| Version | PostgreSQL 16 |
| Injected env var | DATABASE_URL |
| URL format | postgres://vmkit:password@localhost:5432/app |
| Volume | /var/lib/postgresql/data on the VM |
The DATABASE_URL variable follows the standard connection string format understood by SQLAlchemy, asyncpg, Prisma, Django, and every major ORM out of the box.
When to use: Anything that needs relational data — user accounts, orders, content, audit logs. If you’re not sure which database to pick, start here.
Data Persistence
Services store their data in Docker volumes on your VM’s disk. The volumes persist across container restarts and re-deploys — if you update your app, the Postgres data stays intact.
If the VM is destroyed, the data is gone. VMKit does not automatically back up service volumes. If you run terraform destroy, delete the VM from your cloud provider console, or use VMKit’s “Destroy Environment” action, the volume data is lost permanently.
For staging and development environments this is usually acceptable. For production, either use a managed database service or set up your own backup routine (e.g., pg_dump to S3 via a cron job on the VM).
Production Recommendation
VMKit’s one-click services are optimized for staging and development workflows — fast to spin up, zero configuration, disposable.
For production databases, the safer choice is a managed service:
| Service | Managed alternative |
|---|---|
| Postgres | Supabase , Neon , PlanetScale |
| Redis | Upstash |
| Search | Meilisearch Cloud |
To use a managed database in production: don’t enable the VMKit Postgres service on your production environment. Instead, set DATABASE_URL manually in Environment → Settings → Environment Variables using the connection string from your managed provider. Your app code doesn’t change — it reads DATABASE_URL either way.
Connecting from Your App
Since VMKit injects the connection string as an environment variable, you read it the same way regardless of which service is running.
Python
SQLAlchemy (sync)
import os
from sqlalchemy import create_engine
engine = create_engine(os.environ["DATABASE_URL"])asyncpg (async)
import os
import asyncpg
async def get_conn():
return await asyncpg.connect(os.environ["DATABASE_URL"])Django
# settings.py
import dj_database_url
DATABASES = {
"default": dj_database_url.config(
default=os.environ["DATABASE_URL"],
conn_max_age=600,
)
}Redis / Celery
import os
CELERY_BROKER_URL = os.environ["REDIS_URL"]
CELERY_RESULT_BACKEND = os.environ["REDIS_URL"]