Skip to main content

Deploy guide

Deploy Next.js to TOSE

Build Next.js in standalone mode so the image only carries the server and the files it needs, then run it as a non-root user on port 3000.

Before you start

  • A Next.js app with a package-lock.json, in a GitHub repository.
  • output: 'standalone' in next.config.
  • A TOSE account and a workspace at app.tose.sh, with the repository connected through the TOSE GitHub App.
  • Node.js, to install the TOSE CLI: npm install -g @tosesh/tose. You can also do every step in the dashboard.

The example

These files are the example app in the tose-web repository. Its test builds the image for linux/amd64, starts the container and requests the page.

Dockerfile
FROM node:22-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

FROM node:22-alpine AS build
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
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 --chown=node:node /app/.next/standalone ./
COPY --from=build --chown=node:node /app/.next/static ./.next/static
COPY --from=build --chown=node:node /app/public ./public
USER node
EXPOSE 3000
CMD ["node", "server.js"]
next.config.mjs
/** @type {import('next').NextConfig} */
const nextConfig = {
  // Emits .next/standalone with a minimal server.js and only the files it needs.
  output: 'standalone',
};

export default nextConfig;
.dockerignore
node_modules
.next

Deploy it

  1. 1. Put the Dockerfile at the root of the repository

    TOSE builds the file named Dockerfile at the repository root.

  2. 2. Check the image locally

    TOSE builds for linux/amd64. Build for the same platform and open http://localhost:3000.

    docker build --platform linux/amd64 -t my-app .
    docker run --rm -p 3000:3000 my-app
  3. 3. Create the project

    In the dashboard, create a project from the GitHub repository and keep port 3000, or run tose up in the repository and answer its questions. Either way you do this once.

    tose up
  4. 4. Deploy and check

    Every later deploy is one command. Use the build log when the build fails and the live log when the app does not answer.

    tose deploy my-workspace/my-app --json
    tose status my-workspace/my-app --json
    tose logs my-workspace/my-app --build -n 200
    tose logs my-workspace/my-app -n 100
  5. 5. Set environment variables

    Select the project, set variables, then redeploy so the container starts with them. Never commit secrets to the repository.

    tose use my-workspace/my-app
    tose env set DATABASE_URL=… API_BASE_URL=…
    tose redeploy

app.tose.sh

Notes for this stack

  • HOSTNAME=0.0.0.0 makes the standalone server listen on every interface. Without it the server can bind to the container hostname only and TOSE cannot reach it.
  • The standalone output does not include public/ or .next/static, so the Dockerfile copies both.
  • NEXT_PUBLIC_* variables are inlined at build time. Variables set with tose env set are available when the app runs.

Size and cost

  • A new project gets 1 vCPU, 2 GB RAM and 1 replica. You can change vCPU and RAM in the dashboard to 0.5, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 16.
  • Until the workspace wallet has a positive balance, a project can use at most 2 vCPU and 2 GB RAM.
  • At the base price, the default size costs $29.20 for a month of 730 hours.

Prices and calculator

When something fails

"no Dockerfile in project and OPENROUTER_KEY not configured for AI generation"
TOSE found no Dockerfile. Add one named exactly Dockerfile at the repository root.
"AI Dockerfile generation failed"
TOSE could not generate a Dockerfile for this repository. Commit your own, starting from the example on this page.
The deploy finishes but the app does not answer or keeps restarting
The app must listen on 0.0.0.0 and on the project port (3000 by default). TOSE does not set PORT for you; set it in the Dockerfile or with tose env set. Read tose logs for the crash.
The build stops without an error from your code
Builds get 2 GB of memory, 2 CPUs and 45 minutes. Cut build memory (for example fewer parallel jobs) or install fewer dependencies.
"exec format error" when the container starts
The image or a binary in it is not for linux/amd64. Use base images that publish amd64 and do not pin another platform.

Next