You're reading docs for Nextly Alpha. APIs may change between releases.

Guides

Deployment

Deploy a Nextly application to Vercel (recommended) or self-host on Node.js. Production checklist, environment variables, and database migrations.

A Nextly application is a standard Next.js app, so anywhere Next.js runs is fair game. This guide covers the two paths Nextly is built around:

  • Vercel (recommended) -- the default target. Zero-config Next.js, first-class Vercel Blob storage, build-step migrations.
  • Self-host -- Node.js 20+ behind a process manager and reverse proxy. Linked out for the operator-side details rather than reproduced here.

Whichever you choose, run database migrations on a CI/CD step (or your laptop) before the new app code takes traffic. The deployed app never touches schema -- see Production migrations for why.

Production checklist (the short list)

Before you ship, set the following:

VariableRequiredPurpose
NODE_ENVyesSet to production.
DB_DIALECTyespostgresql, mysql, or sqlite. PostgreSQL recommended.
DATABASE_URLyes (Postgres / MySQL)Database connection string.
NEXTLY_SECRETyesJWT signing secret, at least 32 characters. Generate with openssl rand -base64 32.
NEXT_PUBLIC_APP_URLyesThe public URL of your deployment (used in client code and email links).
NEXTLY_ALLOWED_ORIGINSoptionalComma-separated additional CSRF origins (e.g. a separate frontend domain).

Plus storage env vars if you're using cloud storage (see Media & Storage) and email env vars if you're using a real provider (see Email).

Note: Boot-time validation refuses to start in production unless NEXTLY_SECRET is at least 32 characters and NEXT_PUBLIC_APP_URL is set.

Deploy to Vercel

Vercel is the recommended platform for Nextly. Next.js detection is automatic, the Vercel Blob adapter is the easiest storage option, and the build step doubles as a migration runner.

1. Push to GitHub and import

  1. Push the project to GitHub, GitLab, or Bitbucket.
  2. Open the Vercel Dashboard, import the repository.
  3. Vercel detects Next.js and configures the build pipeline. Override only if you've customised the build script (see step 3 below).

2. Configure environment variables

In Project Settings -> Environment Variables, add everything from the production checklist above, plus storage and email variables you intend to use.

Set them for Production and Preview environments separately if you want preview deployments to talk to a staging database.

3. Build command

A scaffolded Nextly project ships this build script in package.json:

{
  "scripts": {
    "build": "nextly migrate && next build"
  }
}

The nextly migrate step runs against the database referenced by DATABASE_URL during the Vercel build, so pending migrations are applied as part of every deploy. Migrations are forward-only -- to undo, write a new corrective migration. See Production migrations for the deeper trade-offs (build-time vs. CI-step migrations) and recovery patterns.

If you'd rather run migrations in a separate CI job before the Vercel deploy promotes (recommended once you have multiple developers / preview deploys), wire it into a GitHub Actions workflow as described in the migrations guide and remove nextly migrate from build.

4. Storage on Vercel

The default zero-config local-disk adapter does not work on Vercel -- serverless function instances are ephemeral, so ./public/uploads/ is wiped on cold start. Pick one of:

  • Vercel Blob (easiest) -- install @nextlyhq/storage-vercel-blob, set BLOB_READ_WRITE_TOKEN. The auto-detection picks it up:

    // nextly.config.ts
    import { defineConfig } from "@nextlyhq/nextly/config";
    import { getStorageFromEnv } from "@nextlyhq/nextly/storage";
    
    export default defineConfig({
      storage: await getStorageFromEnv(),
    });
  • S3 / R2 / DigitalOcean Spaces / etc. -- install @nextlyhq/storage-s3, set S3_BUCKET + S3_REGION + AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY (and S3_ENDPOINT + S3_FORCE_PATH_STYLE for non-AWS providers).

Vercel's serverless functions also have a 4.5MB request-body limit. Enable client-side direct uploads on storage collections that need to accept larger files:

// nextly.config.ts
import { defineConfig } from "@nextlyhq/nextly/config";
import { vercelBlobStorage } from "@nextlyhq/storage-vercel-blob";

export default defineConfig({
  storage: [
    vercelBlobStorage({
      token: process.env.BLOB_READ_WRITE_TOKEN,
      collections: {
        media: {
          clientUploads: true,
        },
      },
    }),
  ],
});

See Media & Storage for the full storage reference.

5. Database

Use a managed PostgreSQL service that's reachable from Vercel's IP ranges:

SQLite is not suitable for Vercel deployments -- the file would be wiped on every cold start. See Database for adapter-specific guidance.

Self-host with Node.js

Run Nextly on any host that supports Node.js 20+. The deployment shape is intentionally boring: build the app, run it under a process manager, put a reverse proxy in front for SSL.

Requirements

  • Node.js 20+ (matches the serverExternalPackages and sharp ABI requirements).
  • A process manager -- pm2, systemd, Docker, or similar. Keep the Node process supervised so crashes auto-restart.
  • A reverse proxy -- nginx or Caddy in front for TLS termination, HTTP/2, and access logging.

Build and start

pnpm install --frozen-lockfile
pnpm build
pnpm start

The scaffolded build script runs nextly migrate && next build, and pnpm start is next start. If you'd rather run migrations as a separate step (recommended for production with zero-downtime deploys), drop nextly migrate from build and run it via your CI pipeline before promoting the new release.

Environment variables

Configure the same variables listed in the production checklist above. On most hosts that means a .env file outside the repo (loaded by your process manager) or a secrets manager.

Process manager and reverse proxy

Use a process manager (pm2, systemd, Docker, etc.) and a reverse proxy (nginx, Caddy, etc.) -- consult their documentation for setup specific to your distribution. The Nextly process is a plain Next.js server; nothing about it requires special configuration beyond ensuring the proxy forwards Host and X-Forwarded-Proto so callbacks resolve correctly.

If your reverse proxy is on a separate IP and you rely on rate-limiting / refresh-token IP binding, set security.trustProxy: true in nextly.config.ts and populate the TRUSTED_PROXY_IPS env var with the proxy's CIDR ranges. Otherwise Nextly ignores X-Forwarded-For and treats every request as coming from a single bucket, which is the safe default for direct-internet deployments.

Migrations on deploy

For self-hosted deploys, the same forward-only model applies. Run nextly migrate against the production database before the new app binary takes traffic. See Production migrations for GitHub Actions, Railway, Render, Fly.io, and AWS examples.

Final checklist

Before going live, verify:

  • NODE_ENV=production.
  • NEXTLY_SECRET is at least 32 characters (generated with openssl rand -base64 32).
  • DATABASE_URL points to a production database (not localhost / SQLite).
  • NEXT_PUBLIC_APP_URL is the public URL of your deployment.
  • NEXTLY_ALLOWED_ORIGINS lists any additional CSRF origins (separate frontend domain, mobile bundle, etc.).
  • Storage adapter is configured for non-ephemeral filesystems (no local disk on serverless).
  • An email provider is configured (Resend, SMTP, or SendLayer) -- without one, password-reset and verification tokens are returned in the API response as a development fallback.
  • All pending migrations have been applied (nextly migrate:status reports zero pending).
  • The reverse proxy / load balancer terminates TLS and forwards real client headers.
  • Database backups are configured (your hosting provider's snapshots, point-in-time recovery, etc.).
  • Monitoring / error reporting is wired up (Sentry, Datadog, etc.).
  • .env* files are not committed to version control.

Next steps