Project Structure


Understanding the nself project structure helps you customize and extend your backend effectively. Each file and directory has a specific purpose in the orchestration of your services.

Directory Overview

your-project/
├── .env.local              # Main configuration file
├── .env                    # Active environment (symlink or copy)
├── docker-compose.yml      # Service orchestration
├── schema.dbml             # Database schema definition
│
├── bin/                    # nself runtime files
│   ├── dbsyncs/           # Database backup history
│   └── templates/         # Service templates
│
├── certs/                  # SSL certificates
│   ├── local/             # Local development certs
│   └── production/        # Let's Encrypt certs
│
├── hasura/                 # GraphQL Engine
│   ├── metadata/          # GraphQL schema & permissions
│   ├── migrations/        # Database migrations
│   └── config.yaml        # Hasura configuration
│
├── nginx/                  # Reverse proxy
│   ├── default.conf       # Main proxy config
│   ├── ssl.conf           # SSL configuration
│   └── services/          # Per-service configs
│
├── postgres/               # Database
│   ├── init.sql           # Initial setup
│   └── extensions.sql     # PostgreSQL extensions
│
├── seeds/                  # Database seeding
│   ├── development.sql    # Dev test data
│   ├── staging.sql        # Staging data
│   └── production.sql     # Production essentials
│
├── functions/              # Serverless functions
│   └── [function-name]/   # Individual functions
│
├── services/               # Microservices
│   ├── nestjs/           # NestJS services
│   ├── python/           # Python services
│   ├── golang/           # Go services
│   └── bullmq/           # Queue workers
│
└── storage/                # File storage
    ├── uploads/           # User uploads
    └── public/            # Public files

Core Files

.env.local

The main configuration file containing all project settings:

# Project Settings
PROJECT_NAME=myapp
ENVIRONMENT=development
DOMAIN=myapp.com

# Database
POSTGRES_DB=myapp_db
POSTGRES_PASSWORD=secure_password

# Services
REDIS_ENABLED=true
NHOST_DASHBOARD_ENABLED=true

# Microservices
NESTJS_SERVICES=api,webhooks
PYTHON_SERVICES=ml-engine

docker-compose.yml

Generated by nself build, orchestrates all services:

version: '3.8'
services:
  postgres:
    image: postgres:15
    environment:
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./postgres/init.sql:/docker-entrypoint-initdb.d/init.sql
  
  hasura:
    image: hasura/graphql-engine:latest
    depends_on:
      - postgres
    environment:
      HASURA_GRAPHQL_DATABASE_URL: postgres://postgres:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}
  
  # Additional services...

schema.dbml

Database schema using DBML (Database Markup Language):

Table users {
  id uuid [pk]
  email varchar [unique, not null]
  created_at timestamp [default: `now()`]
}

Table posts {
  id uuid [pk]
  user_id uuid [ref: > users.id]
  title varchar [not null]
  content text
  published boolean [default: false]
}

Service Directories

hasura/

Contains GraphQL engine configuration:

  • metadata/ - Tables, relationships, permissions
  • migrations/ - Timestamped SQL migrations
  • config.yaml - Hasura settings
# hasura/config.yaml
version: 3
endpoint: http://localhost:8080
metadata_directory: metadata
migrations_directory: migrations
actions:
  kind: synchronous
  handler_webhook_baseurl: http://nestjs-api:3000

nginx/

Reverse proxy configuration for routing and SSL:

# nginx/default.conf
server {
    listen 80;
    server_name api.local.nself.org;
    
    location / {
        proxy_pass http://hasura:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

postgres/

Database initialization scripts:

-- postgres/init.sql
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "pgcrypto";
CREATE EXTENSION IF NOT EXISTS "pg_trgm";

-- Create schemas
CREATE SCHEMA IF NOT EXISTS auth;
CREATE SCHEMA IF NOT EXISTS storage;

Microservices Structure

NestJS Services

Each NestJS service has its own directory:

services/nestjs/api/
├── Dockerfile
├── package.json
├── tsconfig.json
├── src/
│   ├── main.ts
│   ├── app.module.ts
│   └── modules/
│       ├── auth/
│       ├── users/
│       └── webhooks/

Python Services

Python services for ML/AI workloads:

services/python/ml-engine/
├── Dockerfile
├── requirements.txt
├── main.py
├── models/
│   └── prediction.py
└── utils/
    └── preprocessing.py

Data Directories

seeds/

Environment-specific seed data:

-- seeds/development.sql
INSERT INTO users (email, display_name) VALUES
  ('alice@example.com', 'Alice Developer'),
  ('bob@example.com', 'Bob Tester');

-- seeds/production.sql
INSERT INTO roles (name, permissions) VALUES
  ('admin', '{"*": true}'),
  ('user', '{"read": true}');

bin/dbsyncs/

Automatic database backups with timestamps:

bin/dbsyncs/
├── 2024-01-15_10-30-00_backup.sql
├── 2024-01-15_14-45-00_backup.sql
└── latest.sql -> 2024-01-15_14-45-00_backup.sql

Configuration Files

Environment Files

  • .env.local - Development configuration
  • .env.staging - Staging configuration
  • .env.prod-template - Production template (copy to .env before deployment)
  • .env - Active configuration (symlink)

Generated Files

Files generated by nself build:

  • docker-compose.yml - Service definitions
  • nginx/*.conf - Proxy configurations
  • hasura/migrations/* - SQL migrations

File Permissions

Important file permissions for security:

# Environment files (sensitive)
chmod 600 .env*

# Certificates
chmod 600 certs/production/*.pem

# Executables
chmod +x bin/*.sh

# Directories
chmod 755 hasura/ nginx/ postgres/

Customization Points

Adding Custom Services

Add your own services to docker-compose.yml:

# Custom service in docker-compose.yml
services:
  my-custom-service:
    build: ./services/custom
    environment:
      - DATABASE_URL=${DATABASE_URL}
    depends_on:
      - postgres

Extending Nginx Config

Add custom routes in nginx/services/:

# nginx/services/custom.conf
location /custom-api {
    proxy_pass http://my-custom-service:3000;
    proxy_set_header Host $host;
}

Best Practices

  • Version Control: Commit everything except .env, storage/, and certs/production/
  • Secrets: Never commit passwords or API keys
  • Backups: Keep bin/dbsyncs/ for disaster recovery
  • Migrations: Always use nself db run for schema changes
  • Testing: Use separate .env.test for testing

Next Steps