Deploy a Full-Stack App in 5 Minutes

Go from zero to a live app with a database, auth, and storage — all on Zenith.

Prerequisites

  • A Zenith account (sign up at freezenith.com)
  • A GitHub repository with your app code
  • Node.js, Go, Python, or any Dockerfile-based app
1

Create Your App

Go to the Apps page and click New App. Provide your GitHub repo URL and branch.

api
POST /api/v1/apps
{
  "name": "my-next-app",
  "repo_url": "https://github.com/you/my-next-app",
  "branch": "main"
}

Zenith auto-detects your framework (Next.js, Go, Flask, etc.) and assigns a subdomain like my-next-app.freezenith.com.

2

Add a Database

Open your app, go to the Databases tab, and click Add Database. Choose PostgreSQL, MySQL, or Redis.

api
POST /api/v1/apps/:appId/databases
{ "engine": "postgresql" }

# Returns:
{
  "id": "db-abc123",
  "name": "db-my-next",
  "engine": "postgresql",
  "host": "localhost",
  "port": 5432,
  "status": "ready"
}

The DATABASE_URL environment variable is automatically injected into your app. No manual config needed.

3

Enable Auth

Go to the Auth tab and click Enable Auth. Your app gets its own user table and JWT tokens.

javascript
// Sign up a user in your app
const res = await fetch(
  "https://api.freezenith.com/api/v1/apps/YOUR_APP_ID/auth/signup",
  {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      email: "user@example.com",
      password: "securepassword",
      name: "Jane Doe"
    })
  }
);

const { access_token } = await res.json();
// Use access_token for authenticated requests

Each app gets isolated auth with its own JWT secret. Users are managed from the Auth tab in your app dashboard.

4

Add Storage

Go to the Storage tab and create an S3-compatible bucket for file uploads.

api
POST /api/v1/apps/:appId/storage
{ "name": "uploads", "access": "private" }

# Returns:
{
  "id": "bkt-xyz789",
  "name": "uploads",
  "endpoint": "https://uploads.s3.zenith.local",
  "status": "active"
}

S3_ENDPOINT and S3_BUCKET are auto-injected. Use any S3-compatible SDK (like AWS SDK) to upload/download files.

5

Deploy via Git Push

Set up the GitHub webhook to auto-deploy on push. Or trigger manual deploys from the dashboard.

bash
# Push to your repo — Zenith builds and deploys automatically
git add .
git commit -m "feat: initial release"
git push origin main

# Your app is live at:
# https://my-next-app.freezenith.com

Every push to your configured branch triggers a build. View build logs, deployment history, and rollback to any previous version from the Deployments tab.

6

Go Live

Your app is now running with:

  • Auto-scaling containers with SSL
  • Managed PostgreSQL with auto-injected connection string
  • Built-in user authentication with JWT tokens
  • S3-compatible object storage for file uploads
  • Automatic database backups (Pro+ plans)
  • One-click rollbacks to any previous deployment

API Quick Reference

Apps

  • POST /apps
  • GET /apps
  • DELETE /apps/:id

Databases

  • POST /apps/:id/databases
  • GET /databases
  • DELETE /apps/:id/databases/:dbId

Auth

  • POST /apps/:id/auth/enable
  • POST /apps/:id/auth/signup
  • POST /apps/:id/auth/login

Storage

  • POST /apps/:id/storage
  • GET /storage-buckets
  • DELETE /apps/:id/storage/:bktId

Backups

  • POST /apps/:id/databases/:dbId/backups
  • POST .../restore
  • GET /backups

Secrets

  • POST /apps/:id/secrets
  • GET /apps/:id/secrets/:key/value
  • DELETE /apps/:id/secrets/:key

Complete Example: Next.js + PostgreSQL + Auth

typescript
// app/api/todos/route.ts — Example API route
import { Pool } from 'pg';

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,  // Auto-injected by Zenith
});

export async function GET(req: Request) {
  // Verify Zenith Auth token
  const token = req.headers.get('Authorization')?.split(' ')[1];
  if (!token) return Response.json({ error: 'Unauthorized' }, { status: 401 });

  const { rows } = await pool.query('SELECT * FROM todos ORDER BY created_at DESC');
  return Response.json(rows);
}

export async function POST(req: Request) {
  const { title } = await req.json();
  const { rows } = await pool.query(
    'INSERT INTO todos (title) VALUES ($1) RETURNING *',
    [title]
  );
  return Response.json(rows[0], { status: 201 });
}