QUICK START SAAS - nself-org/cli GitHub Wiki

Quick Start: Build a SaaS in 15 Minutes

Complete step-by-step guide to launch a production-ready SaaS platform with billing, multi-tenancy, and white-label capabilities.

Time Estimate: 15-20 minutes Difficulty: Beginner Prerequisites: Docker Desktop installed

Note: As of v0.9.6, commands have been consolidated. This guide uses the new v1.0 command structure where applicable:

  • nself env โ†’ nself config env
  • nself scale โ†’ nself perf scale
  • Other commands referenced use their consolidated forms

What You'll Build

By the end of this tutorial, you'll have:

  • Multi-tenant SaaS backend with database
  • Stripe billing integration (subscriptions & usage-based)
  • White-label customization per tenant
  • Authentication & authorization
  • Production-ready deployment
Timeline:
[0-5 min]   Install nself & initialize project
[5-10 min]  Configure billing & multi-tenancy
[10-15 min] Deploy to production
[15-20 min] Test & verify

Step 1: Install nself (2 minutes)

Install via curl

curl -sSL https://install.nself.org | bash

Verify installation

nself version
# Expected: nself v0.4.8 or later

Alternative: Manual installation

git clone https://github.com/nself-org/cli.git ~/.nself
echo 'export PATH="$PATH:$HOME/.nself/bin"' >> ~/.bashrc
source ~/.bashrc

Step 2: Create Project with SaaS Template (3 minutes)

Initialize with SaaS template

mkdir my-saas && cd my-saas
nself init --template saas

Answer the prompts:

Project name: my-saas
Environment: dev
Base domain: local.nself.org (default for local)
Enable monitoring? Yes

What gets created

my-saas/
โ”œโ”€โ”€ .env                 # Configuration
โ”œโ”€โ”€ .env.secrets         # Auto-generated secrets
โ”œโ”€โ”€ schema.dbml          # SaaS database schema (auto-generated)
โ””โ”€โ”€ nself/

Review the generated schema

cat schema.dbml

Pre-configured SaaS schema includes:

  • organizations - Tenant organizations
  • organization_members - Team members
  • subscriptions - Billing subscriptions
  • subscription_usage - Usage tracking
  • invoices - Invoice history
  • payment_methods - Saved payment methods
  • billing_events - Billing event log

Step 3: Build and Start (2 minutes)

Generate configurations

nself build

What happens:

  1. Generates docker-compose.yml (25+ services)
  2. Creates nginx configurations
  3. Sets up SSL certificates
  4. Initializes database schema
  5. Configures Hasura GraphQL

Start all services

nself start

First start downloads Docker images (2-5 minutes)

Check status

nself status

Expected output:

Service Status:
  postgres     โœ“ healthy
  hasura       โœ“ healthy
  auth         โœ“ healthy
  nginx        โœ“ healthy
  redis        โœ“ healthy
  minio        โœ“ healthy
  monitoring   โœ“ 10/10 services healthy

View all URLs

nself urls

Key URLs:


Step 4: Apply Database Schema (2 minutes)

Apply the SaaS schema

nself db schema apply schema.dbml

This command:

  1. Creates SQL migration from DBML
  2. Runs migration
  3. Generates sample data
  4. Seeds test organizations

Verify tables

nself db shell
-- List all tables
\dt

-- Check organizations table
SELECT * FROM organizations;

-- Check subscriptions table
SELECT * FROM subscriptions;

Exit with \q


Step 5: Configure Stripe Billing (3 minutes)

Get your Stripe keys

  1. Go to Stripe Dashboard
  2. Create account (free)
  3. Get test API keys:
    • Publishable key: pk_test_...
    • Secret key: sk_test_PLACEHOLDER...

Install Stripe plugin

nself plugin install stripe

Configure Stripe

Edit .env and add:

# Stripe Configuration
STRIPE_API_KEY=sk_test_PLACEHOLDER_secret_key_here
STRIPE_PUBLISHABLE_KEY=pk_test_your_publishable_key_here
STRIPE_WEBHOOK_SECRET=whsec_your_webhook_secret_here

Create Stripe products

# Create a subscription product
nself plugin stripe products create \
  --name "Pro Plan" \
  --price 29.99 \
  --interval month

# Create usage-based product
nself plugin stripe products create \
  --name "API Calls" \
  --price 0.01 \
  --type usage

Sync Stripe data

nself plugin stripe sync

Syncs:

  • Customers
  • Products & Prices
  • Subscriptions
  • Invoices
  • Payment methods

Step 6: Enable Multi-Tenancy (2 minutes)

Configure tenant isolation

Edit .env:

# Multi-Tenancy Settings
HASURA_GRAPHQL_JWT_SECRET='{"type":"HS256","key":"your-jwt-secret-here"}'
HASURA_GRAPHQL_ENABLE_CONSOLE=true
HASURA_GRAPHQL_ENABLE_TELEMETRY=false

# Tenant isolation
TENANT_ISOLATION_ENABLED=true
TENANT_COLUMN_NAME=organization_id

Set up tenant permissions

# Access Hasura console
open https://api.local.nself.org

Configure row-level security:

  1. Go to Data โ†’ organizations โ†’ Permissions
  2. For "user" role:
    • Select: {"organization_members":{"user_id":{"_eq":"X-Hasura-User-Id"}}}
    • Insert: {"owner_id":{"_eq":"X-Hasura-User-Id"}}
    • Update: Same as Select
    • Delete: Same as Select

This ensures users only see their organization's data


Step 7: Configure White-Label Branding (2 minutes)

Initialize white-label system

nself whitelabel init

Create default brand

nself whitelabel branding create "My SaaS" \
  --tagline "Your tagline here"

Set brand colors

nself whitelabel branding set-colors \
  --primary #0066cc \
  --secondary #00cc66 \
  --accent #ff6600

Upload logo (optional)

nself whitelabel logo upload ./logo.png --type main

Customize email templates

# List available templates
nself whitelabel email list

# Customize welcome email
nself whitelabel email edit welcome

Available templates:

  • welcome - Welcome new users
  • password-reset - Password reset
  • verify-email - Email verification
  • invite - Team invitations
  • subscription-created - New subscription
  • subscription-cancelled - Cancellation
  • invoice-paid - Payment confirmation
  • payment-failed - Failed payment

Step 8: Deploy to Production (5 minutes)

Create production environment

nself config env create prod

Configure production server

Edit .env.prod:

ENV=prod
PROJECT_NAME=my-saas
BASE_DOMAIN=myapp.com

# Production database
POSTGRES_DB=myapp_prod
POSTGRES_USER=postgres
POSTGRES_PASSWORD=generate-secure-password-here

# Production Stripe (LIVE keys)
STRIPE_API_KEY=sk_live_your_live_key_here
STRIPE_PUBLISHABLE_KEY=pk_live_your_live_key_here

# Security
HASURA_GRAPHQL_ADMIN_SECRET=generate-secure-secret-here
AUTH_JWT_SECRET=generate-jwt-secret-here

# Disable dev features
HASURA_GRAPHQL_ENABLE_CONSOLE=false
HASURA_GRAPHQL_DEV_MODE=false

Set up production server

Requirements:

  • Ubuntu 20.04+ or Debian 11+
  • 2GB RAM minimum
  • Docker & Docker Compose installed
  • Domain with DNS configured

DNS Configuration:

A     @              -> your-server-ip
A     *              -> your-server-ip
CNAME api            -> myapp.com
CNAME auth           -> myapp.com
CNAME admin          -> myapp.com

Configure server.json

Create .environments/prod/server.json:

{
  "host": "your-server-ip",
  "user": "root",
  "port": 22,
  "path": "/var/www/my-saas",
  "sshKey": "~/.ssh/id_rsa"
}

Deploy to production

nself deploy prod

Deployment process:

  1. Connects via SSH
  2. Uploads project files
  3. Installs dependencies
  4. Runs migrations
  5. Starts services
  6. Provisions SSL certificates

Verify deployment

nself deploy status prod

Step 9: Test Your SaaS (3 minutes)

Create test organization

Using Hasura console (https://api.myapp.com):

mutation CreateOrganization {
  insert_organizations_one(object: {
    name: "Acme Corp"
    slug: "acme-corp"
    plan: "pro"
    status: "active"
  }) {
    id
    name
    slug
  }
}

Create subscription

mutation CreateSubscription {
  insert_subscriptions_one(object: {
    organization_id: "org-id-from-above"
    stripe_subscription_id: "sub_xxxxx"
    plan: "pro"
    status: "active"
    current_period_start: "2026-01-01"
    current_period_end: "2026-02-01"
    price_amount: 2999
    currency: "usd"
  }) {
    id
    status
  }
}

Track usage

mutation TrackUsage {
  insert_subscription_usage_one(object: {
    subscription_id: "sub-id-from-above"
    metric_name: "api_calls"
    quantity: 1000
    timestamp: "now()"
  }) {
    id
    quantity
  }
}

Query revenue

query GetRevenue {
  subscriptions_aggregate(where: {status: {_eq: "active"}}) {
    aggregate {
      sum {
        price_amount
      }
      count
    }
  }
}

Common Tasks

Check billing status

# Subscription stats
nself plugin stripe subscriptions stats

# Recent invoices
nself plugin stripe invoices list --limit 10

# MRR (Monthly Recurring Revenue)
nself db query "SELECT SUM(price_amount/100) as mrr FROM subscriptions WHERE status = 'active'"

Monitor usage

# Usage by organization
nself db query "
  SELECT o.name, SUM(u.quantity) as total_usage
  FROM subscription_usage u
  JOIN subscriptions s ON u.subscription_id = s.id
  JOIN organizations o ON s.organization_id = o.id
  WHERE u.timestamp > NOW() - INTERVAL '30 days'
  GROUP BY o.name
  ORDER BY total_usage DESC
"

View logs

# All logs
nself logs

# Specific service
nself logs hasura
nself logs auth

# Follow logs in real-time
nself logs -f

Webhook Setup (Important!)

Stripe webhooks

  1. Go to Stripe Dashboard > Webhooks

  2. Add endpoint: https://myapp.com/webhooks/stripe

  3. Select events:

    • customer.created, customer.updated
    • subscription.created, subscription.updated, subscription.deleted
    • invoice.paid, invoice.payment_failed
    • payment_intent.succeeded, payment_intent.payment_failed
  4. Copy webhook secret to .env:

STRIPE_WEBHOOK_SECRET=whsec_your_webhook_secret_here
  1. Rebuild and restart:
nself build && nself restart

Test webhooks

# List recent webhook events
nself plugin stripe webhook list

# Check webhook health
nself plugin stripe webhook stats

# Retry failed webhook
nself plugin stripe webhook retry evt_xxxxx

Architecture Diagram

                           โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                           โ”‚   Load Balancer     โ”‚
                           โ”‚   (nginx + SSL)     โ”‚
                           โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                      โ”‚
                    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                    โ”‚                 โ”‚                 โ”‚
            โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
            โ”‚  GraphQL API   โ”‚ โ”‚    Auth    โ”‚ โ”‚   Admin UI     โ”‚
            โ”‚   (Hasura)     โ”‚ โ”‚  (nHost)   โ”‚ โ”‚   (nself)      โ”‚
            โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                    โ”‚                โ”‚                 โ”‚
            โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
            โ”‚              PostgreSQL Database                   โ”‚
            โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
            โ”‚  โ”‚ Organizations โ”‚ Subscriptions โ”‚ Usage        โ”‚ โ”‚
            โ”‚  โ”‚ Members      โ”‚ Invoices     โ”‚ Events        โ”‚ โ”‚
            โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
            โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                    โ”‚                                    โ”‚
            โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
            โ”‚  Stripe API    โ”‚                  โ”‚  MinIO Storage โ”‚
            โ”‚  (Billing)     โ”‚                  โ”‚  (Files/Logos) โ”‚
            โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Troubleshooting

Services not starting

# Diagnose issues
nself doctor

# Check Docker
docker ps

# View logs
nself logs postgres
nself logs hasura

Database connection errors

# Verify database is running
nself status postgres

# Check connection
nself db query "SELECT 1"

# Restart database
nself restart postgres

Stripe sync issues

# Verify API key
curl -u sk_test_PLACEHOLDER: https://api.stripe.com/v1/customers?limit=1

# Check plugin status
nself plugin status stripe

# Verbose sync
nself plugin stripe sync --verbose

SSL certificate issues

# Check certificate
nself ssl check myapp.com

# Renew certificate
nself ssl renew myapp.com

# Check nginx config
nself config validate nginx

Port conflicts

# Check what's using ports
lsof -i :5432  # PostgreSQL
lsof -i :8080  # Hasura
lsof -i :443   # nginx

# Auto-fix port conflicts
AUTO_FIX=true nself build

Next Steps

1. Customize Your SaaS

2. Add Features

# Enable search
nself service enable meilisearch

# Enable email
nself service enable mailpit

# Enable functions
nself service enable functions

3. Implement Frontend

Suggested stack:

  • React + TypeScript
  • Apollo Client (GraphQL)
  • TailwindCSS
  • nHost SDK (authentication)

Quick setup:

npx create-react-app frontend --template typescript
cd frontend
npm install @apollo/client @nhost/react graphql

4. Production Checklist

  • Use live Stripe keys
  • Configure production database backups
  • Set up monitoring alerts
  • Configure custom domain SSL
  • Enable rate limiting
  • Configure CORS
  • Set up CDN
  • Configure backup schedule
  • Document API endpoints
  • Set up error tracking

Cost Estimate

Development (Local):

  • nself: Free
  • Docker: Free
  • Stripe: Free (test mode)
  • Total: $0/month

Production (Small):

  • VPS (2GB RAM): $10-20/month
  • Domain: $12/year
  • SSL: Free (Let's Encrypt)
  • Stripe: 2.9% + $0.30 per transaction
  • Total: ~$15/month + transaction fees

Production (Medium):

  • VPS (4GB RAM): $20-40/month
  • Domain: $12/year
  • SSL: Free
  • Stripe: 2.9% + $0.30 per transaction
  • Total: ~$25-40/month + transaction fees

Scaling Your SaaS

Horizontal Scaling

# Scale specific services
nself perf scale hasura --replicas 3
nself perf scale auth --replicas 2

# Enable load balancing
LOAD_BALANCER_ENABLED=true nself build

Vertical Scaling

Edit .env:

# Increase PostgreSQL resources
POSTGRES_SHARED_BUFFERS=256MB
POSTGRES_MAX_CONNECTIONS=200
POSTGRES_WORK_MEM=8MB

# Increase Hasura resources
HASURA_GRAPHQL_MAX_CACHE_SIZE=1000
HASURA_GRAPHQL_CONNECTIONS_PER_READ_REPLICA=5

Database Optimization

# Analyze query performance
nself db analyze

# Add indexes
nself db query "CREATE INDEX idx_org_members ON organization_members(organization_id)"

# Configure connection pooling
PGBOUNCER_ENABLED=true nself build

Related Tutorials


Support


Congratulations! You've built a production-ready SaaS in 15 minutes.

Time to customize and launch your product!

โš ๏ธ **GitHub.com Fallback** โš ๏ธ