nextshipnextship
Quick start

Quick start

From an existing Next.js app to a live deployment, one command at a time.

Every stage is its own command, so a failure can be re-run in isolation without repeating the stages that already succeeded.

1. Look before you build#

Terminal
cd your-nextjs-app
nextship detect
Output
> Inspecting project
v acme-web is a Next.js 16.2.9 project
  root          C:\Users\you\projects\acme-web
  package mgr   pnpm
  build command pnpm run build
  node          24
  sharp         0.34.5
  env files     none

Everything reported is read from disk rather than from what package.json declares, including packages your package manager installed transitively. A project with no env files says so, instead of leaving you to guess.

In a workspace it also reports the workspace root and the app directory, because the image is built from the workspace root where the lockfile and sibling manifests live.

2. Find out what changes#

Terminal
nextship doctor

This reports what stops working when an app leaves a managed platform. Most of it never blocks a build, which is exactly why it is worth surfacing: no error would ever reveal it. The one blocker it does report is a package installed in node_modules that nothing declares, because that fails the build inside the image.

Findings are sorted with blockers first, and each carries a consequence and an action rather than only a name.

3. Run it locally first#

Terminal
nextship run

Builds, packages and starts the image on port 3000, loading your highest-precedence env file so secrets stay outside the image. This exists so the artifact can be verified before any cloud account is involved.

It runs attached with --rm. Ctrl+C stops and removes the container, so there is no background state to clean up. A stop is reported as a stop rather than a failure: exit 130 for Ctrl+C and 143 for docker stop are the codes Next.js exits with after draining connections.

4. Deploy to your own server#

Any Ubuntu 22.04, Ubuntu 24.04 or Debian 12 server you can reach over SSH, as root or a user with passwordless sudo. No cloud token is involved.

Terminal
nextship server add root@203.0.113.10         # the setup plan and the host key fingerprint
nextship server add root@203.0.113.10 --yes   # prepare the server and record it
nextship deploy        # prints the plan, changes nothing
nextship deploy --yes  # executes it

Compare the fingerprint in the plan with the one your provider shows before you pass --yes: from then on, a server presenting any other key is refused. The plan is printed every time, and nothing on the server changes until --yes.

server add records the server in nextship.json:

nextship.json
{
  "version": 2,
  "target": "vm",
  "name": "acme-web",
  "server": {
    "host": "203.0.113.10",
    "port": 22,
    "user": "nextship",
    "hostKey": "203.0.113.10 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOAcvH/9nWZZCMAtztAmv9Rm8tknstGlFBaWtrS+QjI1",
    "arch": "arm64"
  }
}

Commit that file. It holds no secrets, only the server's public host key. It is how every later command knows which server and app belong to this project. Your own server covers what setup changes and what stays yours to run.

Or to DigitalOcean App Platform#

A managed platform instead of a server you run: set a token, and deploy creates the app.

Terminal
export DIGITALOCEAN_TOKEN=dop_v1_...
 
nextship deploy        # prints the plan, changes nothing
nextship deploy --yes  # executes it

On the first deploy nextship records the app name, region and registry in nextship.json, which is the only reason destroy can be certain it will not touch anything else in your account. Deploying to App Platform covers the rest.

Tell us how it went#

Every verification so far was run by the people who wrote nextship. If you deployed something, or got stuck trying, a first deploy report takes two minutes and is the most useful thing anyone can contribute right now, including when everything worked.

Where to go next#