Skip to Content
GuidesAdd Services

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

PostgreSQL 16

The most common choice for persistent storage. VMKit runs the official postgres:16 image.

DetailValue
VersionPostgreSQL 16
Injected env varDATABASE_URL
URL formatpostgres://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:

ServiceManaged alternative
PostgresSupabase , Neon , PlanetScale 
RedisUpstash 
SearchMeilisearch 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.

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"]
Last updated on