
Platform Knowledge
- 6 installs
- 4 repo stars
- Updated June 18, 2026
- doubleslashse/claude-marketplace
Reference architecture, configuration, and troubleshooting knowledge for GitHub Actions, Railway, Supabase, and Postgres.
About
Provides deep knowledge of GitHub Actions, Railway, Supabase, and Postgres including architecture and best practices. A developer uses it when configuring or troubleshooting these platforms.
- Covers GitHub Actions, Railway, Supabase, Postgres
- Architecture, configuration, and troubleshooting
Platform Knowledge by the numbers
- 6 all-time installs (skills.sh)
- Ranked #870 of 1,039 Cloud & Infrastructure skills by installs in the Skillselion catalog
- Data as of Jul 29, 2026 (Skillselion catalog sync)
npx skills add https://github.com/doubleslashse/claude-marketplace --skill platform-knowledgeAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 6 |
|---|---|
| repo stars | ★ 4 |
| Last updated | June 18, 2026 |
| Repository | doubleslashse/claude-marketplace ↗ |
What it does
Reference architecture, configuration, and troubleshooting knowledge for GitHub Actions, Railway, Supabase, and Postgres.
Files
Platform Knowledge Skill
Overview
This skill provides comprehensive knowledge of the infrastructure platforms: GitHub Actions, Railway, Supabase, and Postgres. It covers architecture, configuration, troubleshooting, and best practices for each platform.
Platform Overview
GitHub Actions
- Purpose: CI/CD automation
- Key Features: Workflow automation, testing, deployment
- Config Files:
.github/workflows/*.yml - CLI:
gh
Railway
- Purpose: Application hosting and deployment
- Key Features: Auto-deployments, instant rollbacks, environment management
- Config Files:
railway.toml,nixpacks.toml,Procfile - CLI:
railway
Supabase
- Purpose: Backend-as-a-Service (Postgres, Auth, Storage, Realtime)
- Key Features: Managed Postgres, authentication, file storage, realtime subscriptions
- Config Files:
supabase/config.toml, migrations - Access: MCP tools, Dashboard, CLI
Postgres
- Purpose: Relational database
- Key Features: ACID compliance, extensions, full-text search, JSON support
- Config: Connection strings, postgresql.conf
- Access: SQL queries via MCP or psql
Platform Interaction Map
┌──────────────┐ ┌──────────────┐
│ GitHub │ │ Railway │
│ Actions │────▶│ (App) │
│ (CI/CD) │ │ │
└──────────────┘ └──────┬───────┘
│
▼
┌──────────────┐
│ Supabase │
│ (Backend) │
│ │
│ ┌──────────┐ │
│ │ Postgres │ │
│ └──────────┘ │
└──────────────┘Quick Reference
Tool Access by Platform
| Platform | MCP Tools | CLI | Logs |
|---|---|---|---|
| GitHub Actions | No | gh | gh run view --log |
| Railway | No | railway | railway logs |
| Supabase | Yes | supabase | MCP get_logs |
| Postgres | Yes (via Supabase) | psql | MCP get_logs |
Common Operations
| Task | GitHub | Railway | Supabase |
|---|---|---|---|
| Deploy | Push/workflow | Git push / railway up | Dashboard / CLI |
| Logs | gh run view --log | railway logs | MCP get_logs |
| Status | gh run list | railway status | MCP get_project |
| Rollback | Re-run workflow | Dashboard | Run migration down |
| Secrets | Repository settings | Environment variables | Project settings |
Troubleshooting Decision Tree
Issue Reported
│
▼
┌─────────────────────────────────────┐
│ Where does the issue manifest? │
└─────────────────────────────────────┘
│
├─► Build/Deploy fails ──► GitHub Actions / Railway
│
├─► API errors ──► Supabase API / Edge Functions
│
├─► Auth issues ──► Supabase Auth
│
├─► Database errors ──► Postgres
│
├─► App crashes ──► Railway / Edge Functions
│
└─► Performance ──► All platforms (profile each)Platform-Specific Guides
Detailed guides for each platform:
- GitHub Actions - CI/CD workflows, secrets, debugging
- Railway - Deployment, configuration, troubleshooting
- Supabase - Auth, API, Realtime, Storage
- Postgres - Queries, performance, administration
Cross-Platform Issues
Deployment Chain Failure
Symptom: Deploy succeeds but app broken
Check all stages: 1. GitHub Actions - Build/test passed? 2. Railway - Deploy successful? 3. Supabase - Migrations applied? 4. Environment - Variables set?
Environment Variable Issues
Common causes:
- Set in wrong environment
- Typo in variable name
- Not propagated after change
Verify across platforms:
# GitHub Actions - Check secrets
# (Can't view, only verify existence)
# Railway
railway variables
# Supabase - Check project settings
# Dashboard or MCPConnection Issues Between Services
Railway → Supabase:
- Check Supabase URL format
- Verify API key (anon vs service_role)
- Check connection pooling settings
- Verify IP restrictions
GitHub Actions → Services:
- Check secrets are accessible
- Verify network egress allowed
- Check for rate limiting
Performance Troubleshooting Matrix
| Symptom | GitHub Actions | Railway | Supabase | Postgres |
|---|---|---|---|---|
| Slow | Cache missing, big deps | Cold start, resources | Edge function | Query optimization |
| Timeout | Step timeout | Health check | API timeout | Statement timeout |
| Memory | OOM on build | Container limit | Function limit | work_mem |
| CPU | Concurrent jobs | Container limit | N/A | Query complexity |
Configuration Files Reference
GitHub Actions
# .github/workflows/deploy.yml
name: Deploy
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# ... more stepsRailway
# railway.toml
[build]
builder = "nixpacks"
buildCommand = "npm run build"
[deploy]
startCommand = "npm start"
healthcheckPath = "/health"Supabase
# supabase/config.toml
[api]
port = 54321
schemas = ["public", "graphql_public"]
[db]
port = 54322Postgres
-- Key settings
SHOW max_connections;
SHOW statement_timeout;
SHOW work_mem;GitHub Actions Platform Guide
Overview
GitHub Actions is a CI/CD platform that automates build, test, and deployment workflows directly from GitHub repositories.
Architecture
Repository
├── .github/
│ ├── workflows/ # Workflow definitions
│ │ ├── ci.yml
│ │ └── deploy.yml
│ └── actions/ # Custom actions
│ └── my-action/
│ └── action.ymlWorkflow Structure
name: CI # Workflow name
on: # Triggers
push:
branches: [main]
pull_request:
branches: [main]
env: # Global env vars
NODE_VERSION: '20'
jobs:
build: # Job ID
runs-on: ubuntu-latest # Runner
strategy: # Matrix builds
matrix:
node: [18, 20]
steps:
- uses: actions/checkout@v4 # Action
- run: npm install # CommandKey Concepts
Triggers (on)
# Push/PR triggers
on:
push:
branches: [main]
paths:
- 'src/**'
tags:
- 'v*'
pull_request:
types: [opened, synchronize]
# Scheduled triggers
on:
schedule:
- cron: '0 0 * * *' # Daily at midnight
# Manual triggers
on:
workflow_dispatch:
inputs:
environment:
description: 'Deploy environment'
required: true
default: 'staging'Jobs and Steps
jobs:
job1:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.get-version.outputs.version }}
steps:
- id: get-version
run: echo "version=1.0.0" >> $GITHUB_OUTPUT
job2:
needs: job1 # Dependency
runs-on: ubuntu-latest
steps:
- run: echo ${{ needs.job1.outputs.version }}Environment and Secrets
jobs:
deploy:
environment: production # Environment (for approvals)
env:
NODE_ENV: production
steps:
- run: echo ${{ secrets.API_KEY }}
- run: echo ${{ vars.PUBLIC_URL }}Caching
- uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-npm-Artifacts
# Upload
- uses: actions/upload-artifact@v4
with:
name: build
path: dist/
# Download
- uses: actions/download-artifact@v4
with:
name: buildDebugging
Enable Debug Logging
Set repository secret:
ACTIONS_STEP_DEBUG = trueView Logs via CLI
# List recent runs
gh run list --limit 20
# View run status
gh run view <run-id>
# View full logs
gh run view <run-id> --log
# View failed step logs only
gh run view <run-id> --log-failed
# Watch running workflow
gh run watch <run-id>
# Re-run failed jobs
gh run rerun <run-id> --failedDebug Locally with act
# Install act
brew install act
# Run workflow locally
act push
# Run specific job
act -j build
# Run with secrets
act -s MY_SECRET=valueCommon Issues and Solutions
Workflow Not Triggering
Check: 1. Branch name matches trigger 2. Path filters don't exclude changes 3. Workflow file syntax is valid 4. No [skip ci] in commit message
Debug:
# Add to see what triggered
- run: |
echo "Event: ${{ github.event_name }}"
echo "Ref: ${{ github.ref }}"
echo "SHA: ${{ github.sha }}"Secrets Not Available
Common causes:
- Secret defined in org, not repo
- Fork PR (secrets hidden by default)
- Wrong environment scope
- Typo in secret name
Check:
- run: |
if [ -z "${{ secrets.MY_SECRET }}" ]; then
echo "Secret is empty!"
fiCache Miss
Check:
- uses: actions/cache@v4
id: cache
with:
path: ~/.npm
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
- if: steps.cache.outputs.cache-hit != 'true'
run: echo "Cache miss - installing fresh"Out of Memory
Solutions:
# Increase Node memory
- run: npm run build
env:
NODE_OPTIONS: '--max-old-space-size=4096'
# Use larger runner
runs-on: ubuntu-latest-4-coresTimeout
Adjust limits:
jobs:
build:
timeout-minutes: 30 # Job timeout
steps:
- run: npm test
timeout-minutes: 10 # Step timeoutBest Practices
Workflow Efficiency
# Use concurrency to cancel redundant runs
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
# Fail fast in matrix
strategy:
fail-fast: true
matrix:
node: [18, 20, 22]Security
# Minimal permissions
permissions:
contents: read
packages: write
# Pin action versions
- uses: actions/checkout@v4.1.1 # Specific version
# Validate inputs
- run: |
if [[ ! "${{ inputs.env }}" =~ ^(dev|staging|prod)$ ]]; then
echo "Invalid environment"
exit 1
fiReusable Workflows
# .github/workflows/reusable-build.yml
on:
workflow_call:
inputs:
node-version:
required: true
type: string
secrets:
npm-token:
required: true
# Usage
jobs:
build:
uses: ./.github/workflows/reusable-build.yml
with:
node-version: '20'
secrets:
npm-token: ${{ secrets.NPM_TOKEN }}Useful Expressions
# Conditionals
if: github.ref == 'refs/heads/main'
if: contains(github.event.head_commit.message, '[deploy]')
if: always() # Run even if previous failed
if: failure() # Run only if previous failed
# String operations
${{ format('Hello {0}', github.actor) }}
${{ join(matrix.node, ', ') }}
# JSON
${{ toJSON(github.event) }}
${{ fromJSON(steps.output.outputs.data).version }}CLI Reference
# Workflows
gh workflow list
gh workflow view <name>
gh workflow run <name>
gh workflow disable <name>
gh workflow enable <name>
# Runs
gh run list [--status success|failure|...]
gh run view <id> [--log|--log-failed]
gh run watch <id>
gh run rerun <id> [--failed]
gh run cancel <id>
gh run download <id>
# Secrets
gh secret list
gh secret set NAME
gh secret delete NAMEPostgres Platform Guide
Overview
PostgreSQL is a powerful, open-source relational database system with strong reliability, feature robustness, and performance.
Key Concepts
Connections
Max Connections = base + superuser_reserved
- base: Regular connection limit
- superuser_reserved: Reserved for admin (default: 3)
Connection States:
- idle: Waiting for query
- active: Executing query
- idle in transaction: In transaction, waiting
- idle in transaction (aborted): Failed transactionSchemas
Database
├── public (default user schema)
├── auth (Supabase auth)
├── storage (Supabase storage)
├── extensions (Extension objects)
└── pg_catalog (System catalog)Roles and Permissions
-- Supabase roles
anon -- Unauthenticated API access
authenticated -- Authenticated API access
service_role -- Bypasses RLS
postgres -- SuperuserHealth Queries
Connection Monitoring
-- Current connections by state
SELECT state, count(*)
FROM pg_stat_activity
GROUP BY state
ORDER BY count DESC;
-- Connections by user
SELECT usename, count(*)
FROM pg_stat_activity
GROUP BY usename
ORDER BY count DESC;
-- Connections by application
SELECT application_name, count(*)
FROM pg_stat_activity
WHERE application_name != ''
GROUP BY application_name
ORDER BY count DESC;
-- Connection utilization
SELECT
count(*) AS current,
(SELECT setting::int FROM pg_settings WHERE name = 'max_connections') AS max,
round(count(*)::numeric /
(SELECT setting::int FROM pg_settings WHERE name = 'max_connections') * 100, 2) AS pct
FROM pg_stat_activity;Query Monitoring
-- Currently running queries
SELECT
pid,
usename,
application_name,
state,
now() - query_start AS duration,
query
FROM pg_stat_activity
WHERE state != 'idle'
ORDER BY duration DESC;
-- Long-running queries (>5 min)
SELECT
pid,
usename,
now() - query_start AS duration,
query
FROM pg_stat_activity
WHERE state = 'active'
AND query_start < now() - interval '5 minutes'
ORDER BY duration DESC;
-- Queries with most calls (requires pg_stat_statements)
SELECT
query,
calls,
round(total_exec_time::numeric / 1000, 2) AS total_seconds,
round(mean_exec_time::numeric, 2) AS avg_ms
FROM pg_stat_statements
ORDER BY calls DESC
LIMIT 10;
-- Slowest queries
SELECT
query,
calls,
round(mean_exec_time::numeric, 2) AS avg_ms,
round(max_exec_time::numeric, 2) AS max_ms
FROM pg_stat_statements
ORDER BY mean_exec_time DESC
LIMIT 10;Lock Monitoring
-- Current locks
SELECT
relation::regclass,
mode,
granted,
pid
FROM pg_locks
WHERE relation IS NOT NULL
ORDER BY relation;
-- Blocked queries
SELECT
blocked.pid AS blocked_pid,
blocked.usename AS blocked_user,
blocked.query AS blocked_query,
blocking.pid AS blocking_pid,
blocking.usename AS blocking_user,
blocking.query AS blocking_query
FROM pg_stat_activity blocked
JOIN pg_stat_activity blocking
ON blocking.pid = ANY(pg_blocking_pids(blocked.pid));
-- Lock wait times
SELECT
pid,
usename,
now() - query_start AS wait_time,
query
FROM pg_stat_activity
WHERE wait_event_type = 'Lock'
ORDER BY wait_time DESC;Table Statistics
-- Table sizes
SELECT
schemaname || '.' || tablename AS table,
pg_size_pretty(pg_total_relation_size(schemaname || '.' || tablename)) AS total_size,
pg_size_pretty(pg_table_size(schemaname || '.' || tablename)) AS table_size,
pg_size_pretty(pg_indexes_size(schemaname || '.' || tablename)) AS index_size
FROM pg_tables
WHERE schemaname = 'public'
ORDER BY pg_total_relation_size(schemaname || '.' || tablename) DESC;
-- Row counts
SELECT
schemaname || '.' || tablename AS table,
n_live_tup AS row_count,
n_dead_tup AS dead_rows
FROM pg_stat_user_tables
ORDER BY n_live_tup DESC;
-- Tables needing vacuum
SELECT
schemaname || '.' || tablename AS table,
n_dead_tup AS dead_rows,
last_vacuum,
last_autovacuum
FROM pg_stat_user_tables
WHERE n_dead_tup > 1000
ORDER BY n_dead_tup DESC;Index Statistics
-- Index usage
SELECT
schemaname || '.' || tablename AS table,
indexrelname AS index,
idx_scan AS scans,
idx_tup_read AS tuples_read,
pg_size_pretty(pg_relation_size(indexrelid)) AS size
FROM pg_stat_user_indexes
ORDER BY idx_scan DESC;
-- Unused indexes
SELECT
schemaname || '.' || tablename AS table,
indexrelname AS index,
pg_size_pretty(pg_relation_size(indexrelid)) AS size
FROM pg_stat_user_indexes
WHERE idx_scan = 0
AND indexrelname NOT LIKE '%pkey%';
-- Missing index suggestions (from seq scans)
SELECT
schemaname || '.' || relname AS table,
seq_scan,
seq_tup_read,
idx_scan,
n_live_tup AS rows
FROM pg_stat_user_tables
WHERE seq_scan > idx_scan
AND n_live_tup > 10000
ORDER BY seq_tup_read DESC;Database Size
-- Database size
SELECT pg_size_pretty(pg_database_size(current_database()));
-- Total size by schema
SELECT
schema_name,
pg_size_pretty(sum(table_size)) AS total_size
FROM (
SELECT
pg_catalog.pg_namespace.nspname AS schema_name,
pg_relation_size(pg_catalog.pg_class.oid) AS table_size
FROM pg_catalog.pg_class
JOIN pg_catalog.pg_namespace ON relnamespace = pg_namespace.oid
) t
GROUP BY schema_name
ORDER BY sum(table_size) DESC;Performance Optimization
Query Optimization
-- Explain query plan
EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT)
SELECT * FROM your_table WHERE condition;
-- Key things to look for:
-- - Seq Scan on large tables (add index)
-- - High cost estimates
-- - Actual time much higher than planned
-- - Many rows filtered (improve WHERE)Index Guidelines
-- B-tree (default) - equality, range
CREATE INDEX idx_name ON table(column);
-- Multi-column - for combined queries
CREATE INDEX idx_name ON table(col1, col2);
-- Partial - for filtered queries
CREATE INDEX idx_active ON table(column) WHERE active = true;
-- Expression - for computed values
CREATE INDEX idx_lower ON table(lower(email));
-- Covering - include columns for index-only scans
CREATE INDEX idx_name ON table(key) INCLUDE (data);Common Optimizations
-- Add missing primary key index
CREATE INDEX IF NOT EXISTS idx_table_id ON table(id);
-- Index foreign keys
CREATE INDEX IF NOT EXISTS idx_table_fk ON table(foreign_key_id);
-- Index frequently filtered columns
CREATE INDEX IF NOT EXISTS idx_table_status ON table(status);
-- Analyze table statistics
ANALYZE table_name;
-- Vacuum dead rows
VACUUM table_name;
VACUUM ANALYZE table_name;Troubleshooting
Connection Issues
Too many connections:
-- Find and terminate idle connections
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'idle'
AND query_start < now() - interval '10 minutes'
AND usename != 'postgres';Connection refused:
- Check max_connections setting
- Verify connection string
- Check firewall/security groups
- Verify role exists and has permissions
Query Issues
Slow queries: 1. Run EXPLAIN ANALYZE 2. Check for Seq Scans 3. Add appropriate indexes 4. Check table statistics (ANALYZE)
Deadlocks:
-- View deadlock info (after the fact)
SELECT * FROM pg_stat_activity
WHERE state = 'idle in transaction';
-- Prevention
-- - Acquire locks in consistent order
-- - Keep transactions short
-- - Use appropriate isolation levelsStatement timeout:
-- Check current setting
SHOW statement_timeout;
-- Set for session
SET statement_timeout = '60s';
-- Set for query
SET LOCAL statement_timeout = '120s';Space Issues
Disk full:
-- Find largest tables
SELECT
schemaname || '.' || tablename AS table,
pg_size_pretty(pg_total_relation_size(schemaname || '.' || tablename)) AS size
FROM pg_tables
ORDER BY pg_total_relation_size(schemaname || '.' || tablename) DESC
LIMIT 10;
-- Vacuum to reclaim space
VACUUM FULL table_name;
-- Delete old data
DELETE FROM logs WHERE created_at < now() - interval '30 days';Table bloat:
-- Check for bloat
SELECT
schemaname || '.' || tablename AS table,
n_dead_tup AS dead_rows,
n_live_tup AS live_rows,
round(n_dead_tup::numeric / nullif(n_live_tup, 0) * 100, 2) AS dead_pct
FROM pg_stat_user_tables
WHERE n_dead_tup > 1000
ORDER BY dead_pct DESC;
-- Fix bloat
VACUUM ANALYZE table_name;Configuration
Key Settings
-- View settings
SHOW max_connections;
SHOW statement_timeout;
SHOW work_mem;
SHOW shared_buffers;
-- Common settings
max_connections = 100 -- Connection limit
statement_timeout = '30s' -- Query timeout
work_mem = '64MB' -- Memory per operation
shared_buffers = '256MB' -- Shared memoryConnection Pooling
For high-traffic applications, use a connection pooler:
- PgBouncer: Lightweight, session/transaction pooling
- Supavisor: Supabase's pooler
Extensions
Common Extensions
-- List installed extensions
SELECT * FROM pg_extension;
-- Useful extensions
CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; -- UUID functions
CREATE EXTENSION IF NOT EXISTS "pgcrypto"; -- Encryption
CREATE EXTENSION IF NOT EXISTS "pg_stat_statements"; -- Query stats
CREATE EXTENSION IF NOT EXISTS "pg_trgm"; -- Fuzzy text searchQuick Checklist
Performance
- [ ] Indexes on frequently queried columns?
- [ ] Indexes on foreign keys?
- [ ] Table statistics up to date (ANALYZE)?
- [ ] No excessive dead rows (VACUUM)?
- [ ] Appropriate work_mem setting?
Connections
- [ ] Connection pooling enabled?
- [ ] Reasonable max_connections?
- [ ] No connection leaks in application?
- [ ] Idle connections being cleaned up?
Monitoring
- [ ] pg_stat_statements enabled?
- [ ] Logging slow queries?
- [ ] Monitoring connection count?
- [ ] Alerting on lock contention?
Railway Platform Guide
Overview
Railway is a deployment platform that provides instant deploys, automatic SSL, and environment management for applications.
Architecture
Railway Project
├── Environments (dev, staging, prod)
│ └── Services
│ ├── Application (from GitHub)
│ ├── Database (Postgres, Redis, etc.)
│ └── Cron Jobs
└── Variables (Environment-specific)Configuration Files
railway.toml
[build]
# Build settings
builder = "nixpacks" # or "dockerfile"
buildCommand = "npm run build"
watchPatterns = ["src/**"]
[deploy]
# Deployment settings
startCommand = "npm start"
healthcheckPath = "/health"
healthcheckTimeout = 300 # seconds
restartPolicyType = "ON_FAILURE"
restartPolicyMaxRetries = 3
[environments]
# Environment overrides
[environments.production]
[environments.production.deploy]
healthcheckTimeout = 100nixpacks.toml
[phases.setup]
nixPkgs = ["nodejs-18_x", "yarn"]
[phases.install]
cmds = ["yarn install"]
[phases.build]
cmds = ["yarn build"]
[start]
cmd = "yarn start"Procfile
web: npm start
worker: npm run workerDeployment Process
1. Git Push / Manual Deploy
│
▼
2. Build Phase (nixpacks/Dockerfile)
│
▼
3. Deploy Phase (start command)
│
▼
4. Health Check
│
├── Pass → Traffic routed
└── Fail → RollbackCLI Reference
Project Management
# Login
railway login
# Link to project
railway link
# View project info
railway status
# Open dashboard
railway openEnvironment Variables
# List variables
railway variables
# Set variable
railway variables set KEY=value
# Delete variable
railway variables delete KEY
# Show in different environment
railway variables --environment productionDeployments
# Deploy current directory
railway up
# View deployment status
railway status
# View logs
railway logs
railway logs --follow
railway logs --deployment <id>Services
# List services
railway service list
# View service info
railway service
# Create new service
railway service createCommon Issues and Solutions
Build Failures
Nixpacks detection failed:
# Specify provider in nixpacks.toml
providers = ["node"]Missing system dependencies:
[phases.setup]
nixPkgs = ["pkg-config", "openssl"]
aptPkgs = ["libssl-dev"]Build command not found:
[build]
buildCommand = "npm run build" # Must match package.jsonDeployment Failures
Health check failing: 1. Ensure app binds to 0.0.0.0, not localhost 2. Use correct PORT environment variable 3. Increase healthcheckTimeout
// Correct port binding
const port = process.env.PORT || 3000;
app.listen(port, '0.0.0.0', () => {
console.log(`Server running on port ${port}`);
});Start command failing:
[deploy]
startCommand = "node dist/index.js" # Full path neededEnvironment Variables
Variable not loading:
- Check environment is correct (dev vs prod)
- Verify variable is linked to service
- Redeploy after adding variable
Reference other variables:
# Railway supports variable references
DATABASE_URL=${{Postgres.DATABASE_URL}}Memory/Resource Issues
Out of memory:
- Check memory limit in Railway dashboard
- Optimize application memory usage
- Consider splitting services
Cold starts:
- Railway sleeps inactive services (free tier)
- Add keep-alive pings
- Upgrade to paid plan
Connection Strings
Postgres
postgresql://user:password@host:port/databaseAvailable as DATABASE_URL when Postgres service is added.
Redis
redis://user:password@host:portAvailable as REDIS_URL when Redis service is added.
Connecting to Supabase
# Set Supabase URL and key as variables
railway variables set SUPABASE_URL=https://xxx.supabase.co
railway variables set SUPABASE_KEY=your-anon-key
railway variables set SUPABASE_SERVICE_KEY=your-service-keyNetworking
Custom Domains
1. Add domain in Railway dashboard 2. Configure DNS CNAME to railway.app 3. SSL automatically provisioned
Private Networking
Services in same project can communicate via internal DNS:
http://service-name.railway.internalTCP Proxy
For non-HTTP services (databases, etc.): 1. Enable TCP proxy in service settings 2. Use provided external port
Debugging
View Logs
# Recent logs
railway logs
# Follow live
railway logs -f
# Specific deployment
railway logs --deployment <deployment-id>
# Search for errors
railway logs 2>&1 | grep -i errorCheck Status
# Project status
railway status
# Deployment status
# Check dashboard for detailed status
railway openLocal Testing
# Run with Railway variables
railway run npm start
# Shell with variables
railway shellBest Practices
Deployment
# Always configure health checks
[deploy]
healthcheckPath = "/health"
healthcheckTimeout = 60
# Set restart policy
restartPolicyType = "ON_FAILURE"
restartPolicyMaxRetries = 3Environment Management
# Use separate environments
railway environment create staging
railway environment create production
# Set environment-specific variables
railway variables set NODE_ENV=production --environment productionMonitoring
1. Set up log drains for external monitoring 2. Configure alerting on deployment failures 3. Monitor resource usage in dashboard
Security
1. Never commit secrets to repository 2. Use Railway variables for all secrets 3. Use service keys (not anon) for server-side Supabase access 4. Restrict access via project members
Quick Troubleshooting Checklist
- [ ] Build command matches package.json script?
- [ ] Start command correct and path complete?
- [ ] App listening on
0.0.0.0:$PORT? - [ ] Health check endpoint returning 200?
- [ ] All required environment variables set?
- [ ] Variables in correct environment?
- [ ] Memory limits sufficient?
- [ ] Recent changes deployed?
Supabase Platform Guide
Overview
Supabase is an open-source Firebase alternative providing Postgres database, authentication, instant APIs, realtime subscriptions, storage, and edge functions.
Architecture
Supabase Project
├── Database (Postgres)
│ ├── Schemas (public, auth, storage)
│ ├── Extensions
│ └── Migrations
├── Auth
│ ├── Providers (email, OAuth)
│ ├── Policies
│ └── Hooks
├── Storage
│ ├── Buckets
│ └── Policies
├── Realtime
│ └── Subscriptions
├── Edge Functions
└── API (PostgREST + Kong)MCP Tools Reference
Project Management
mcp__plugin_supabase_supabase__list_projects
mcp__plugin_supabase_supabase__get_project(project_id)Database
mcp__plugin_supabase_supabase__list_tables(project_id, schemas)
mcp__plugin_supabase_supabase__list_extensions(project_id)
mcp__plugin_supabase_supabase__list_migrations(project_id)
mcp__plugin_supabase_supabase__execute_sql(project_id, query)
mcp__plugin_supabase_supabase__apply_migration(project_id, name, query)Monitoring
mcp__plugin_supabase_supabase__get_logs(project_id, service)
# Services: api, postgres, auth, storage, realtime, edge-function
mcp__plugin_supabase_supabase__get_advisors(project_id, type)
# Types: security, performanceConfiguration
mcp__plugin_supabase_supabase__get_project_url(project_id)
mcp__plugin_supabase_supabase__get_anon_key(project_id)
mcp__plugin_supabase_supabase__generate_typescript_types(project_id)Edge Functions
mcp__plugin_supabase_supabase__list_edge_functions(project_id)
mcp__plugin_supabase_supabase__get_edge_function(project_id, function_slug)
mcp__plugin_supabase_supabase__deploy_edge_function(project_id, name, ...)Authentication
Configuration
Key settings in Auth dashboard:
- Site URL (for redirects)
- Redirect URLs (whitelist)
- JWT expiry
- Email templates
- OAuth providers
Common Patterns
-- Get current user
SELECT auth.uid();
-- Get user role
SELECT auth.role();
-- Get JWT claims
SELECT auth.jwt();RLS with Auth
-- Allow users to read own data
CREATE POLICY "Users read own data"
ON user_profiles
FOR SELECT
USING (auth.uid() = user_id);
-- Allow users to update own data
CREATE POLICY "Users update own data"
ON user_profiles
FOR UPDATE
USING (auth.uid() = user_id);Troubleshooting Auth
Login fails with `invalid_grant`:
- Refresh token expired
- Clear stored tokens
- Re-authenticate
Email not sending:
- Check SMTP configuration
- Verify email templates
- Check rate limits
OAuth redirect fails:
- Verify redirect URL is whitelisted
- Check provider configuration
- Verify Site URL setting
Row Level Security (RLS)
Enable RLS
ALTER TABLE your_table ENABLE ROW LEVEL SECURITY;Policy Types
-- SELECT policy
CREATE POLICY "name" ON table FOR SELECT USING (condition);
-- INSERT policy
CREATE POLICY "name" ON table FOR INSERT WITH CHECK (condition);
-- UPDATE policy (both)
CREATE POLICY "name" ON table FOR UPDATE
USING (read_condition) WITH CHECK (write_condition);
-- DELETE policy
CREATE POLICY "name" ON table FOR DELETE USING (condition);
-- All operations
CREATE POLICY "name" ON table FOR ALL USING (condition);Common RLS Patterns
-- Public read, authenticated write
CREATE POLICY "Public read" ON posts
FOR SELECT USING (true);
CREATE POLICY "Auth write" ON posts
FOR INSERT WITH CHECK (auth.role() = 'authenticated');
-- User owns row
CREATE POLICY "Owner access" ON items
FOR ALL USING (auth.uid() = user_id);
-- Role-based
CREATE POLICY "Admin access" ON admin_data
FOR ALL USING (auth.jwt()->>'role' = 'admin');
-- Time-based
CREATE POLICY "Active only" ON subscriptions
FOR SELECT USING (expires_at > now());Debugging RLS
-- View policies on table
SELECT * FROM pg_policies WHERE tablename = 'your_table';
-- Test as specific user
SET request.jwt.claims = '{"sub": "user-uuid", "role": "authenticated"}';
SELECT * FROM your_table;
RESET request.jwt.claims;Realtime
Enable Realtime
-- Enable on table
ALTER PUBLICATION supabase_realtime ADD TABLE your_table;
-- For UPDATE/DELETE events, need full replica identity
ALTER TABLE your_table REPLICA IDENTITY FULL;Troubleshooting Realtime
Not receiving updates: 1. Table added to publication? 2. REPLICA IDENTITY FULL set? 3. RLS allows SELECT? 4. Client subscribed correctly?
-- Check publication
SELECT * FROM pg_publication_tables
WHERE pubname = 'supabase_realtime';
-- Check replica identity
SELECT relreplident FROM pg_class WHERE relname = 'your_table';
-- 'f' = full, 'd' = default (pk only), 'n' = nothingStorage
Bucket Policies
-- Public bucket
CREATE POLICY "Public read" ON storage.objects
FOR SELECT USING (bucket_id = 'public');
-- Authenticated upload
CREATE POLICY "Auth upload" ON storage.objects
FOR INSERT WITH CHECK (
bucket_id = 'uploads'
AND auth.role() = 'authenticated'
);
-- User folder pattern
CREATE POLICY "User folders" ON storage.objects
FOR ALL USING (
bucket_id = 'user-files'
AND (storage.foldername(name))[1] = auth.uid()::text
);Edge Functions
Structure
// supabase/functions/my-function/index.ts
import { serve } from "https://deno.land/std@0.168.0/http/server.ts"
serve(async (req) => {
const { name } = await req.json()
return new Response(
JSON.stringify({ message: `Hello ${name}!` }),
{ headers: { "Content-Type": "application/json" } }
)
})Deployment
mcp__plugin_supabase_supabase__deploy_edge_function(
project_id,
name,
entrypoint_path,
verify_jwt,
files
)Troubleshooting Edge Functions
Function not responding:
- Check logs via MCP
get_logs - Verify deployment succeeded
- Check function URL
CORS errors:
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
}
// Handle OPTIONS
if (req.method === 'OPTIONS') {
return new Response('ok', { headers: corsHeaders })
}Advisories
Running Advisors
# Security advisors
mcp__plugin_supabase_supabase__get_advisors(project_id, "security")
# Performance advisors
mcp__plugin_supabase_supabase__get_advisors(project_id, "performance")Common Security Advisories
- RLS not enabled
- Public schema exposed
- Weak JWT configuration
- Storage policies missing
Common Performance Advisories
- Missing indexes
- Large tables without vacuuming
- Inefficient queries
- Connection pool settings
Quick Troubleshooting Checklist
API Issues
- [ ] RLS enabled and policies correct?
- [ ] API key correct (anon vs service_role)?
- [ ] Endpoint path correct?
- [ ] Request format correct?
Auth Issues
- [ ] Site URL configured?
- [ ] Redirect URL whitelisted?
- [ ] Email configured (if using)?
- [ ] OAuth provider configured?
Database Issues
- [ ] Migrations applied?
- [ ] RLS policies allowing access?
- [ ] Indexes on queried columns?
- [ ] Connection pool not exhausted?
Realtime Issues
- [ ] Table in publication?
- [ ] REPLICA IDENTITY FULL?
- [ ] RLS allows SELECT?
- [ ] Client subscription correct?