Database
Add official Railway database services. These are maintained templates with pre-configured volumes, networking, and connection variables.
For non-database templates, see the templates skill.
When to Use User asks to "add a database", "add Postgres", "add Redis", etc. User needs a database for their application User asks about connecting to a database User says "add postgres and connect to my server" User says "wire up the database" Decision Flow
ALWAYS check for existing databases FIRST before creating.
User mentions database │ Check existing DBs first (query env config for source.image) │ ┌────┴────┐ Exists Doesn't exist │ │ │ Create database │ (CLI or API) │ │ │ Wait for deployment │ │ └─────┬─────┘ │ User wants to connect service? │ ┌─────┴─────┐ Yes No │ │ Wire vars Done + via env suggest wiring skill
Check for Existing Databases
Before creating a database, check if one already exists.
For full environment config structure, see environment-config.md.
railway status --json
Then query environment config and check source.image for each service:
query environmentConfig($environmentId: String!) { environment(id: $environmentId) { config(decryptVariables: false) } }
The config.services object contains each service's configuration. Check source.image for:
ghcr.io/railway/postgres or postgres: → Postgres ghcr.io/railway/redis or redis: → Redis ghcr.io/railway/mysql or mysql: → MySQL ghcr.io/railway/mongo or mongo: → MongoDB Available Databases Database Template Code PostgreSQL postgres Redis redis MySQL mysql MongoDB mongodb Prerequisites
Get project context:
railway status --json
Extract:
id - project ID environments.edges[0].node.id - environment ID
Get workspace ID (not in status output):
bash <<'SCRIPT' scripts/railway-api.sh \ 'query getWorkspace($projectId: String!) { project(id: $projectId) { workspaceId } }' \ '{"projectId": "PROJECT_ID"}' SCRIPT
Adding a Database Step 1: Fetch Template bash <<'SCRIPT' scripts/railway-api.sh \ 'query template($code: String!) { template(code: $code) { id name serializedConfig } }' \ '{"code": "postgres"}' SCRIPT
This returns the template's id and serializedConfig needed for deployment.
Step 2: Deploy Template bash <<'SCRIPT' scripts/railway-api.sh \ 'mutation deployTemplate($input: TemplateDeployV2Input!) { templateDeployV2(input: $input) { projectId workflowId } }' \ '{ "input": { "templateId": "TEMPLATE_ID", "serializedConfig": SERIALIZED_CONFIG, "projectId": "PROJECT_ID", "environmentId": "ENVIRONMENT_ID", "workspaceId": "WORKSPACE_ID" } }' SCRIPT
Important: serializedConfig is the exact object from the template query, not a string.
Connecting to the Database
After deployment, other services connect using reference variables.
For complete variable reference syntax and wiring patterns, see variables.md.
Backend Services (Server-side)
Use the private/internal URL for server-to-server communication:
Database Variable Reference PostgreSQL ${{Postgres.DATABASE_URL}} Redis ${{Redis.REDIS_URL}} MySQL ${{MySQL.MYSQL_URL}} MongoDB ${{MongoDB.MONGO_URL}} Frontend Applications
Important: Frontends run in the user's browser and cannot access Railway's private network. They must use public URLs or go through a backend API.
For direct database access from frontend (not recommended):
Use the public URL variables (e.g., ${{MongoDB.MONGO_PUBLIC_URL}}) Requires TCP proxy to be enabled
Better pattern: Frontend → Backend API → Database
Example: Add PostgreSQL bash <<'SCRIPT'
1. Get context
railway status --json
Extract project.id and environment.id
2. Get workspace ID
scripts/railway-api.sh \ 'query { project(id: "proj-id") { workspaceId } }' '{}'
3. Fetch Postgres template
scripts/railway-api.sh \ 'query { template(code: "postgres") { id serializedConfig } }' '{}'
4. Deploy template
scripts/railway-api.sh \ 'mutation deploy($input: TemplateDeployV2Input!) { templateDeployV2(input: $input) { projectId workflowId } }' \ '{"input": {"templateId": "...", "serializedConfig": {...}, "projectId": "...", "environmentId": "...", "workspaceId": "..."}}' SCRIPT
Then Connect From Another Service
Use environment skill to add the variable reference:
{
"services": {
"
Response
Successful deployment returns:
{ "data": { "templateDeployV2": { "projectId": "e63baedb-e308-49e9-8c06-c25336f861c7", "workflowId": "deployTemplate/project/e63baedb-e308-49e9-8c06-c25336f861c7/xxx" } } }
What Gets Created
Each database template creates:
A service with the database image A volume for data persistence Environment variables for connection strings TCP proxy for external access (where applicable) Error Handling Error Cause Solution Template not found Invalid template code Use: postgres, redis, mysql, mongodb Permission denied User lacks access Need DEVELOPER role or higher Project not found Invalid project ID Run railway status --json for correct ID Example Workflows "add postgres and connect to the server" Check existing DBs via env config query If postgres exists: Skip to step 5 If not exists: Deploy postgres template (fetch template → deploy) Wait for deployment to complete Identify target service (ask if multiple, or use linked service) Use environment skill to stage: DATABASE_URL: { "value": "${{Postgres.DATABASE_URL}}" } Apply changes "add postgres" Check existing DBs via env config query If exists: "Postgres already exists in this project" If not exists: Deploy postgres template Inform user: "Postgres created. Connect a service with: DATABASE_URL=${{Postgres.DATABASE_URL}}" "connect the server to redis" Check existing DBs via env config query If redis exists: Wire up REDIS_URL via environment skill → apply If no redis: Ask "No Redis found. Create one?" Deploy redis template Wire REDIS_URL → apply Composability Connect services: Use environment skill to add variable references View database service: Use service skill Check logs: Use deployment skill