# Deploy Node.js and Next.js

> A Node.js API or a Next.js application: the Dockerfile, the port, build-time variables, and the database.

Source: https://docs.fransys.cloud/en/guides/node-nextjs/ Checked against the console on 2026-10-23.

## The Dockerfile

Fransys deploys a Docker image. An example for Next.js, with the `standalone` output (`output: 'standalone'` in `next.config.js`):

```dockerfile
FROM node:22-alpine AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:22-alpine
WORKDIR /app
ENV NODE_ENV=production PORT=3000 HOSTNAME=0.0.0.0
COPY --from=build /app/.next/standalone ./
COPY --from=build /app/.next/static ./.next/static
COPY --from=build /app/public ./public
EXPOSE 3000
CMD ["node", "server.js"]
```

For a Node.js API, the idea is the same: install, build if needed, then start the server. Listen on `0.0.0.0`, not on `localhost`.

## The service

Add an **Application**, connect the repository and the CI ([From GitHub or GitLab](https://docs.fransys.cloud/en/projets/github-gitlab/)), then set the **Container port** to `3000` (or whatever your `EXPOSE` says).

## Build-time variables

Next.js writes `NEXT_PUBLIC_…` variables into the code at build time. Fransys CI doesn't pass variables to the build yet:
- keep these values in your code or in a `.env.production` file in the repository, if they aren't secret;
- or read them at startup, on the server side.

Other variables (database access, API keys) go in **Variables**, protected if they're secrets.

## The database

Add a PostgreSQL database linked to the application, then check the received names in **Variables**. If your ORM expects a single URL (`DATABASE_URL` for Prisma, for example), build it with references:

```txt
DATABASE_URL=postgresql://${USER}:${PASSWORD}@${HOST}:${PORT}/${DATABASE}
```

replacing each name with the name of the received variable, and tick **Allow ${VAR} references**.

## Migrations

In **Deployment commands**, under **After the first install** and **After an update**: for example `npx prisma migrate deploy`.

## Several processes

A worker (BullMQ, for example): have your entrypoint read a role, then copy the service with that role. See [Application](https://docs.fransys.cloud/en/projets/application/#workers-queues-scheduled-tasks).
