Back to Blog
Tutorial10 min read2026-06-27

How to Deploy an AdonisJS App to Production

AdonisJS is a full-featured Node MVC framework with a built-in ORM, migrations, and an ace CLI. This guide walks through building, configuring APP_KEY, running Lucid migrations, and deploying to production.

Ajay Kumar
Ajay Kumar
Founder & DevOps, PandaStack

AdonisJS brings a Laravel-style, batteries-included experience to Node: a real ORM (Lucid), first-class migrations, validation, auth, and a CLI called ace. That structure makes deployment predictable once you know the build pipeline and the few environment variables Adonis insists on.

The build pipeline

Modern AdonisJS (v6) is TypeScript and compiles to a build/ directory. The production flow is:

# Install deps
npm ci

# Compile TypeScript to ./build
node ace build

# The build output is a self-contained app; install prod deps inside it
cd build && npm ci --omit=dev

# Start
node bin/server.js

The node ace build command produces an optimized bundle. Your production process is plain node build/bin/server.js.

APP_KEY is mandatory

Adonis encrypts cookies, signs values, and powers its Encryption service with APP_KEY. The app will refuse to boot without it. Generate one:

node ace generate:key

Then set it as an environment variable in production. Never commit it, and keep it stable — rotating APP_KEY invalidates existing signed cookies and sessions.

Other core env vars:

NODE_ENV=production
PORT=3333
HOST=0.0.0.0
APP_KEY=<generated>
# Lucid (PostgreSQL example)
DB_HOST=...
DB_PORT=5432
DB_USER=...
DB_PASSWORD=...
DB_DATABASE=...

If your platform provides a single DATABASE_URL, configure Lucid to parse it:

// config/database.ts
import { defineConfig } from '@adonisjs/lucid';

export default defineConfig({
  connection: 'postgres',
  connections: {
    postgres: {
      client: 'pg',
      connection: process.env.DATABASE_URL
        ? process.env.DATABASE_URL
        : { host: process.env.DB_HOST /* ... */ }
    }
  }
});

Migrations with Lucid

Lucid migrations run through ace. In production, apply them as a deploy step:

node ace migration:run --force

The --force flag is required in production to confirm you really mean to mutate the database. Run this once per deploy, before the new version takes traffic — not on every container start, or replicas will race.

A production Dockerfile

FROM node:20-slim AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN node ace build

FROM node:20-slim
WORKDIR /app
COPY --from=build /app/build ./
RUN npm ci --omit=dev
ENV NODE_ENV=production
EXPOSE 3333
CMD ["node", "bin/server.js"]

Note how prod dependencies are installed *inside* the compiled build/ output — that directory has its own package.json.

Deploying on PandaStack

  1. 1Provision a managed PostgreSQL (or MySQL — Lucid supports both). PandaStack injects DATABASE_URL.
  2. 2Connect the Git repo as a container app. The Dockerfile is auto-detected; without one, the Node buildpack runs node ace build and starts the server.
  3. 3Set APP_KEY, NODE_ENV=production, and HOST=0.0.0.0 so the server binds correctly inside the container.
  4. 4Run node ace migration:run --force once before serving.
  5. 5Add a custom domain; SSL is automatic.

The HOST=0.0.0.0 detail matters: bind to all interfaces, not localhost, or the platform's load balancer cannot reach your app.

Production checklist

  • [ ] APP_KEY set and stable.
  • [ ] HOST=0.0.0.0 and the right PORT.
  • [ ] Migrations run with --force as a deploy step.
  • [ ] Prod dependencies installed inside build/.
  • [ ] NODE_ENV=production (enables optimizations and disables debug output).
  • [ ] Health-check route for the platform to probe.

A tiny health route helps:

// start/routes.ts
import router from '@adonisjs/core/services/router';
router.get('/health', () => ({ status: 'ok' }));

Verifying

curl -s https://app.example.com/health
# {"status":"ok"}

If that responds and your DB-backed routes work, the deploy is sound.

References

  • [AdonisJS deployment guide](https://docs.adonisjs.com/guides/getting-started/deployment)
  • [AdonisJS build process](https://docs.adonisjs.com/guides/concepts/typescript-build-process)
  • [Lucid migrations](https://lucid.adonisjs.com/docs/migrations)
  • [AdonisJS environment variables](https://docs.adonisjs.com/guides/getting-started/environment-variables)

---

AdonisJS's compiled output plus Lucid migrations deploy cleanly on PandaStack with a managed database and DATABASE_URL injected automatically. Start free at [dashboard.pandastack.io](https://dashboard.pandastack.io).

Ready to deploy?

Start free on PandaStack.

Start free on PandaStack

More in Tutorial

Browse all Tutorial articles →

See also