ɳSelfɳSELFDOCS
  • Getting Started

    • Introduction
    • Quick Start
    • Installation
    • Your First Project
  • Core Concepts

    • Architecture Overview
    • Project Structure
    • Configuration
    • Environments
  • Services

    • PostgreSQL Database
    • Hasura GraphQL
    • Authentication
    • Real-Time Communication
    • Storage (MinIO)
    • Email Configuration
    • Redis Cache
    • Search Engines
    • Functions
    • MLflow (ML Tracking)
    • Monitoring & Metrics
    • Admin UI
    • Dashboard
  • Database Tools

    • Schema Management
    • Migrations
    • Seeding Data
    • Backup & Restore
    • dbdiagram.io Sync
  • Microservices

    • NestJS Services
    • BullMQ Workers
    • Go Services
    • Python Services
  • CLI Reference

    • Complete Command Reference
    • Core Commands
    • Database Commands
    • Service Management
    • Production Commands
  • Deployment

    • Local Development
    • Production Setup
    • SSL/TLS Configuration
    • Domain Configuration
    • Environment Variables
  • Advanced Topics

    • Multi-Tenancy & SaaS
    • Security & Hardening
    • Custom Actions
    • Webhooks
    • Performance Tuning
    • Troubleshooting
  • Migration Guides

    • From Supabase
    • From Nhost
    • From Firebase
  • Resources

    • Changelog
    • Licensing
    • FAQ
    • Contributing
    • Support

Migrating from Nhost

Straightforward migration guide from Nhost to ɳSelf

Easiest Migration Path

  • Difficulty: Medium (lowest of all migrations)
  • Estimated Time: 4-8 hours
  • Compatibility: 95% (same core stack: PostgreSQL, Hasura, nHost Auth)

Why Migrate to ɳSelf?

Nhost and ɳSelf share the same core technology stack, making migration straightforward. The primary difference is deployment model.

  • Full infrastructure control - Own your data and deployment
  • No vendor lock-in - Open-source stack, deploy anywhere
  • Cost optimization - Predictable self-hosting costs vs. usage-based pricing
  • Advanced features - Multi-tenancy, billing integration, plugin system (v0.4.8+)
  • More database tools - DBML support, type generation, profiling
  • Extensive CLI - 56 commands for every operation

Key Differences

AspectNhostɳSelf
InterfaceWeb dashboard + CLICLI + optional web admin
HostingManaged cloud or self-hostedSelf-hosted only
ConfigurationWeb UI, config files.env file + CLI commands
Deploymentnhost deploynself build && nself start
BackupsAutomatic (cloud)Manual + Scheduled

Prerequisites

Before you start, ensure you have:

  • Access to Nhost project (admin credentials)
  • PostgreSQL dump capability (Nhost CLI)
  • Hasura metadata export capability
  • List of all environment variables used
  • Storage bucket inventory
  • ɳSelf installed on target server
  • Backup of current Nhost project

Required Tools

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

# Install Nhost CLI (for data export)
npm install -g nhost

# Install PostgreSQL client tools
brew install postgresql  # macOS
sudo apt-get install postgresql-client  # Ubuntu

Migration Checklist

# 1. Document current setup
nhost config show > nhost-config.txt
nhost env list > nhost-env.txt

# 2. Create full backup
nhost db dump > nhost-backup.sql
nhost metadata export > nhost-metadata.json

# 3. List all services in use
# - Auth providers enabled
# - Functions deployed
# - Environment variables

Phase 1: Setup ɳSelf Project

Estimated time: 30 minutes

Initialize Project

mkdir nhost-migration && cd nhost-migration
nself init --wizard

Configure Services to Match Nhost

# .env configuration
PROJECT_NAME=my-nhost-migration
ENV=dev
BASE_DOMAIN=localhost

# Database (use same credentials pattern)
POSTGRES_DB=myapp_db
POSTGRES_USER=postgres
POSTGRES_PASSWORD=your-secure-password

# Hasura
HASURA_GRAPHQL_ADMIN_SECRET=your-admin-secret
HASURA_GRAPHQL_JWT_SECRET={"type":"HS256","key":"your-jwt-secret-min-32-chars"}

# Auth (nHost Auth - same service Nhost uses)
AUTH_SERVER_URL=http://auth.localhost
AUTH_CLIENT_URL=http://localhost:3000

# Storage (enable MinIO)
MINIO_ENABLED=true
MINIO_ROOT_USER=minioadmin
MINIO_ROOT_PASSWORD=minioadmin

# Optional services
REDIS_ENABLED=true
FUNCTIONS_ENABLED=true
MAILPIT_ENABLED=true

Build and Start

nself build
nself start
nself doctor  # Verify all services are running
nself urls    # List all available URLs

Phase 2: Database Migration

Estimated time: 1-2 hours

Export from Nhost

# Option A: Using Nhost CLI
nhost db dump > nhost-database.sql

# Option B: Using pg_dump directly
pg_dump -h db.nhost.run -U nhost -d your-nhost-db > nhost-database.sql

# Option C: From Nhost Dashboard
# Go to Database → Backups → Download Latest Backup

Prepare Database Dump

# Clean the dump file (remove Nhost-specific settings)
cat nhost-database.sql | \
  grep -v "nhost_" | \
  sed 's/nhost/postgres/g' > cleaned-database.sql

Import to ɳSelf

# Using nself CLI (recommended)
nself db import cleaned-database.sql

# Verify import
nself db shell
-- In psql
\dt  -- List tables
SELECT count(*) FROM auth.users;  -- Verify data
\q

Phase 3: Authentication Migration

Estimated time: 30 minutes

Users Data

Authentication users are stored in the same auth.users table. If you imported the database dump, users are already migrated.

nself db shell
-- Verify users migrated
SELECT id, email, created_at FROM auth.users LIMIT 10;

-- Check roles
SELECT * FROM auth.roles;

-- Check user roles
SELECT * FROM auth.user_roles;

Configure OAuth Providers

Map Nhost OAuth config to ɳSelf:

# In .env:

# GitHub
AUTH_PROVIDER_GITHUB_ENABLED=true
AUTH_PROVIDER_GITHUB_CLIENT_ID=your-github-client-id
AUTH_PROVIDER_GITHUB_CLIENT_SECRET=your-github-secret

# Google
AUTH_PROVIDER_GOOGLE_ENABLED=true
AUTH_PROVIDER_GOOGLE_CLIENT_ID=your-google-client-id
AUTH_PROVIDER_GOOGLE_CLIENT_SECRET=your-google-secret

# Facebook
AUTH_PROVIDER_FACEBOOK_ENABLED=true
AUTH_PROVIDER_FACEBOOK_CLIENT_ID=your-facebook-app-id
AUTH_PROVIDER_FACEBOOK_CLIENT_SECRET=your-facebook-secret

Restart auth service:

nself restart --service=auth

JWT Secrets

Critical: Your JWT secret must match Nhost's secret if you want existing tokens to work.

# Find Nhost JWT secret (from Nhost Dashboard → Settings → Environment Variables)
# Copy EXACT value to ɳSelf .env
HASURA_GRAPHQL_JWT_SECRET='{"type":"HS256","key":"your-exact-nhost-jwt-secret"}'

# Rebuild and restart
nself build
nself restart

Test Authentication

curl -X POST http://auth.localhost/v1/signin/email-password \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "password": "password"
  }'

# Should return access_token and refresh_token

Phase 4: Storage Migration

Estimated time: 1-2 hours

Download Files from Nhost

#!/bin/bash
# download-nhost-storage.sh

NHOST_PROJECT_URL="https://yourproject.nhost.run"
NHOST_BUCKET="default"
OUTPUT_DIR="./nhost-storage-backup"

mkdir -p $OUTPUT_DIR/$NHOST_BUCKET

# Get file list and download
curl "$NHOST_PROJECT_URL/v1/storage/files?bucketId=$NHOST_BUCKET" | \
  jq -r '.files[].id' | \
  while read FILE_ID; do
    echo "Downloading $FILE_ID..."
    curl "$NHOST_PROJECT_URL/v1/storage/files/$FILE_ID" \
      -o "$OUTPUT_DIR/$NHOST_BUCKET/$FILE_ID"
  done

Create MinIO Buckets

# Access MinIO Console: http://minio.localhost
# OR use MinIO CLI
docker exec -it $(docker ps -qf "name=minio") mc alias set local http://localhost:9000 minioadmin minioadmin

# Create buckets to match Nhost
docker exec -it $(docker ps -qf "name=minio") mc mb local/default
docker exec -it $(docker ps -qf "name=minio") mc mb local/avatars

# Set public policy if needed
docker exec -it $(docker ps -qf "name=minio") mc policy set download local/default

Upload Files to MinIO

# Upload all files
mc mirror ./nhost-storage-backup/default ɳSelf/default

Phase 5: Hasura Metadata Migration

Estimated time: 30 minutes

Export Hasura Metadata from Nhost

# Using Hasura Console
# 1. Open Hasura Console: https://yourproject.nhost.run/console
# 2. Go to Settings → Metadata Actions → Export Metadata

# OR using Hasura CLI
cd /tmp/nhost-metadata
hasura metadata export --endpoint https://yourproject.nhost.run/v1/graphql --admin-secret YOUR_ADMIN_SECRET

Import Metadata to ɳSelf

# Option 1: Using Hasura CLI
cd /tmp/nhost-metadata
hasura metadata apply --endpoint http://api.localhost/v1/graphql --admin-secret your-admin-secret

# Option 2: Via Hasura Console
# 1. Open http://api.localhost
# 2. Go to Settings → Metadata Actions → Import Metadata

Verify Metadata

# Check tables tracked
curl http://api.localhost/v1/graphql \
  -H "x-hasura-admin-secret: your-admin-secret" \
  -d '{"query": "{ __schema { types { name } } }"}'

Phase 6: Functions Migration

Estimated time: 1 hour

Nhost and ɳSelf both support serverless functions with the same Express.js handler signature.

Copy Functions

# Enable functions in nself
# In .env:
FUNCTIONS_ENABLED=true

# Rebuild to create functions service
nself build
nself restart

# Copy Nhost functions to ɳSelf
cp -r /path/to/nhost/functions/* ./functions/src/

# Install dependencies
cd functions
npm install

# Test functions locally
nself logs --service=functions

Function Structure

No changes needed - Same Express.js handler signature:

// Nhost function
import { Request, Response } from 'express'

export default (req: Request, res: Response) => {
  res.json({ message: 'Hello from Nhost!' })
}

// nself function (identical)
import { Request, Response } from 'express'

export default (req: Request, res: Response) => {
  res.json({ message: 'Hello from ɳSelf!' })
}

Frontend Code Changes

Minimal Changes (Use Nhost SDK with ɳSelf)

The Nhost JavaScript SDK can work with ɳSelf by configuring custom URLs.

Before (Nhost Cloud)

import { NhostClient } from '@nhost/nhost-js'

const nhost = new NhostClient({
  subdomain: 'myproject',
  region: 'us-east-1'
})

After (ɳSelf)

import { NhostClient } from '@nhost/nhost-js'

const nhost = new NhostClient({
  backendUrl: 'http://auth.localhost',
  graphqlUrl: 'http://api.localhost/v1/graphql',
  storageUrl: 'http://minio.localhost',
  authUrl: 'http://auth.localhost/v1'
})

Environment Variables

Nhost

NEXT_PUBLIC_NHOST_SUBDOMAIN=myproject
NEXT_PUBLIC_NHOST_REGION=us-east-1

ɳSelf

NEXT_PUBLIC_API_URL=http://api.localhost
NEXT_PUBLIC_AUTH_URL=http://auth.localhost
NEXT_PUBLIC_STORAGE_URL=http://minio.localhost

Common Pitfalls

1. JWT Secret Mismatch

Symptom: Existing tokens don't work after migration

Solution: Use exact same JWT secret from Nhost

# Find in Nhost Dashboard → Settings → Env Vars
HASURA_GRAPHQL_JWT_SECRET='{"type":"HS256","key":"exact-nhost-secret"}'

nself restart

2. Database Connection Refused

Symptom: Connection refused when importing database

Solution: Wait for PostgreSQL to be ready

nself doctor
# Or check manually
docker exec $(docker ps -qf "name=postgres") pg_isready

3. Storage URLs Don't Work

Symptom: 404 errors when accessing files

Solution: Configure bucket policies

# Set bucket to public (if needed)
docker exec -it $(docker ps -qf "name=minio") mc policy set download local/default

Rollback Procedure

If migration fails:

  1. Keep Nhost running - Don't delete project until verified
  2. Switch DNS back - Change DNS A record to Nhost IP (5-60 min propagation)
  3. Revert frontend - Change environment variables back to Nhost URLs
# Revert environment variables
NEXT_PUBLIC_NHOST_SUBDOMAIN=myproject
NEXT_PUBLIC_NHOST_REGION=us-east-1

# Rebuild and deploy
npm run build
vercel deploy

Verification Checklist

After migration, verify everything works:

Database

  • All tables present (nself db shell → \dt)
  • Row counts match Nhost
  • Foreign keys intact
  • Triggers functioning

Authentication

  • Users can login with email/password
  • OAuth providers work
  • JWT tokens valid
  • Refresh tokens work

Storage

  • All files accessible
  • File counts match
  • Upload works

GraphQL API

  • All queries work
  • Mutations work
  • Subscriptions work (real-time)
  • Permissions enforced

Performance Optimization

After migration, optimize ɳSelf for production:

# Database optimization
nself db analyze

# Enable connection pooling
PGBOUNCER_ENABLED=true
PGBOUNCER_POOL_MODE=transaction

# Enable Redis caching
REDIS_ENABLED=true
AUTH_REDIS_ENABLED=true

# Enable monitoring
MONITORING_ENABLED=true

# Rebuild and restart
nself build
nself restart

Conclusion

Migrating from Nhost to ɳSelf is straightforward due to shared technology (PostgreSQL, Hasura, nHost Auth). Main effort is in data export/import and frontend URL configuration.

Timeline Summary:

  • Setup ɳSelf: 30 minutes
  • Database migration: 1-2 hours
  • Authentication setup: 30 minutes
  • Storage migration: 1-2 hours
  • Metadata import: 30 minutes
  • Functions migration: 1 hour
  • Frontend changes: 1-2 hours
  • Testing & verification: 1-2 hours

Total: 6-10 hours for complete migration

Recommended Approach:

  1. Migrate to staging environment first
  2. Test thoroughly for 1-2 weeks
  3. Migrate production during low-traffic period
  4. Keep Nhost running for 1 week as fallback

Need help? Check our support channels or join our Discord community for migration assistance.